Add public demo mode with auto-seeding, hourly reset, and Portainer deploy guide

- DEMO_MODE=true env flag: disables password changes and backup endpoints (403),
  exposes GET /demo/status for frontend detection
- Auto-seed on first startup: creates demo user (demo@mymidas.app / demo123)
  with 6 months of transactions, investments, budgets, subscriptions, and tax
  payslips; takes a pg_dump snapshot immediately after for hourly restore
- Hourly reset: resetter Alpine container with cron restores DB from snapshot
  and purges uploaded attachments every hour on the hour
- Frontend: amber demo banner on all pages, login page shows credentials,
  password change disabled with notice, backups section replaced with notice
- demo/ directory: self-contained docker-compose.yml (ports 4001/8091),
  .env.example, reset.sh, and step-by-step Portainer DEPLOY.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
megaproxy 2026-04-23 22:08:24 +00:00
parent afb5e99bb2
commit 9897d03d91
17 changed files with 975 additions and 2 deletions

152
demo/DEPLOY.md Normal file
View file

@ -0,0 +1,152 @@
# MyMidas Demo — Deployment Guide (Portainer)
This guide deploys the public demo instance on a separate server using Portainer Stacks.
**What you get:** a fully seeded MyMidas instance at port 4001, with demo data and an hourly auto-reset. No manual steps after initial deploy.
---
## Prerequisites
- Docker and Portainer installed on the demo server
- SSH or console access to the demo server (for the initial clone and key generation)
- Your reverse proxy pointing a public domain at port `4001` on this server
---
## Step 1 — Clone the repo
On the demo server, clone into your preferred location:
```bash
git clone https://git.rdx4.com/megaproxy/MyMidas.git
cd MyMidas
```
---
## Step 2 — Generate JWT keys
The demo shares the `secrets/` directory with the main app structure. If you've already generated keys on this server you can skip this.
```bash
mkdir -p secrets
openssl genrsa -out secrets/jwt_private.pem 4096
openssl rsa -in secrets/jwt_private.pem -pubout -out secrets/jwt_public.pem
```
---
## Step 3 — Create the demo .env file
```bash
cd demo
cp .env.example .env
```
Open `.env` and fill in the three required values:
| Variable | How to generate |
|---|---|
| `ENCRYPTION_KEY` | `python3 -c "import secrets; print(secrets.token_hex(32))"` |
| `DB_PASSWORD` | Any strong random string |
| `REDIS_PASSWORD` | Any strong random string |
Leave `ENVIRONMENT=production`.
---
## Step 4 — Deploy the stack in Portainer
1. Open Portainer → **Stacks** → **Add stack**
2. Name it `mymidas-demo`
3. Select **Repository** as the build method
4. Set the repository URL to your Gitea URL and branch `main`
5. Set **Compose path** to `demo/docker-compose.yml`
6. Under **Environment variables**, add the four variables from your `.env`:
- `ENCRYPTION_KEY`
- `DB_PASSWORD`
- `REDIS_PASSWORD`
- `ENVIRONMENT` = `production`
7. Click **Deploy the stack**
> **Alternative (upload method):** If you prefer to upload the compose file directly, paste the contents of `demo/docker-compose.yml` into Portainer's web editor and add the environment variables manually.
---
## Step 5 — Wait for first-time seeding
On first startup, the backend will:
1. Run database migrations
2. Detect that `DEMO_MODE=true` and no users exist
3. Seed the full demo dataset (~180 transactions, investments, budgets, tax data)
4. Save a compressed snapshot (`demo_snapshot.sql.gz`) for hourly resets
This takes about 3060 seconds. Watch progress in Portainer → **Containers**`mymidas-demo-backend-1`**Logs**.
You'll see these log lines when ready:
```
demo_seed_complete
demo_snapshot_created
Uvicorn running on http://0.0.0.0:8000
```
---
## Step 6 — Configure your reverse proxy
Point your public domain at `http://<demo-server-ip>:4001`.
The frontend serves the React app and proxies all `/api/` calls to the backend internally — so you only need to expose port `4001`.
**nginx proxy manager example:**
- Scheme: `http`
- Forward hostname/IP: `<demo-server-ip>`
- Forward port: `4001`
- Enable websockets: off
---
## Step 7 — Verify
Open your domain in a browser. You should see the MyMidas login page with a yellow demo credentials banner:
```
Email: demo@mymidas.app
Password: demo123
```
Log in and confirm the data is populated (accounts, transactions, investments, tax page).
---
## Hourly reset
The `resetter` container runs a cron job at the top of every hour that:
1. Restores the database from the snapshot taken on first boot
2. Deletes any files uploaded by demo users
No action needed — it runs automatically. You can check reset logs in Portainer → **Containers**`mymidas-demo-resetter-1`**Logs**.
---
## Updating the demo
When you push code changes to main:
1. In Portainer → **Stacks**`mymidas-demo`**Editor** → **Update the stack**
2. This rebuilds the images and restarts all containers
3. On restart, migrations run automatically; the seed check runs and skips if already seeded (snapshot is preserved on the `demo_snapshot` volume)
> If you want to **force a full re-seed** (e.g. after adding more demo data): in Portainer, delete the `demo_snapshot` volume, then redeploy. The backend will re-seed and take a new snapshot on next startup.
---
## Troubleshooting
| Symptom | Check |
|---|---|
| Blank page / 502 | Backend still starting — wait 60 s and refresh |
| Login fails | Seeding still in progress — check backend logs |
| Data not resetting | Check resetter logs; confirm `demo_snapshot` volume has the `.sql.gz` file |
| "Snapshot not found" in resetter log | Backend may not have finished first-time seed — redeploy backend only |