docs: update comments and README to reflect current feature set

- Refresh app.py module and route docstrings for runtime settings,
  MP3 tagging, rate limiting, revision workflow, and admin actions.
- Clarify config.py and models.py comments.
- Update template comments/CSS for dashboard filters, request detail,
  player page, and settings page.
- Rewrite README.md with current features, status flow, file layout,
  deployment variables, and troubleshooting.
- Refresh REVIEW.md quick-reference.
- Add MAX_REVISIONS to docker-compose.yml environment list.
- Expand requirements.txt comment coverage.

No version history or changelog included.
This commit is contained in:
Troll (Hermes Agent) 2026-08-02 00:07:24 +00:00
parent 14ed80fe4b
commit 4af9322c9d
11 changed files with 148 additions and 111 deletions

View file

@ -1,16 +1,37 @@
# Theme Song Booth
Custom theme-song request and delivery system for a convention booth. Customers fill out a form, the operator generates two AI-made song versions, the customer picks one, and the approved MP3 is delivered by email after payment is collected.
A Flask web app for a convention booth where visitors request a custom AI-generated theme song, the operator manages the queue, and the final MP3(s) are delivered by email after payment.
## What this project does
## Features
- **Customer request page** (`/request`) — booth visitors enter their name, email, hobbies, notable facts, preferred genre, and extra requests. A branded banner image is shown.
- **Operator dashboard** (`/admin`) — queue of all requests with status filters, per-request detail page, and system reset.
- **Prompt generation** — the admin page builds a plain-text prompt for Hermes/AI, which returns a Title, Style, and Lyrics block. The operator pastes that response, clicks **Extract**, then uses Copy buttons to paste into Suno Custom Mode.
- **Song upload** — operator uploads Version A and Version B MP3s.
- **Customer player page** — a private `/play/<token>` page emails to the customer. They can listen to both versions, choose A/B/both, or request changes.
- **Payment and delivery** — operator enters a Square payment reference and clicks **Mark Paid & Deliver**. The approved MP3(s) are emailed as attachments.
- **System reset** — one button in the admin topbar clears all requests and files at the start of an event.
### Customer-facing
- **Request form** (`/request`) — visitors enter name, email, hobbies, notable facts, preferred style/genre, vocal gender preference, and extra requests. A branded banner image is shown.
- **Confirmation page** (`/thanks/<id>`) — shows the request number after submission.
- **Private player page** (`/play/<token>`) — customer receives an email with a unique link. They can stream Version A and Version B, pick one (or both), or request a limited number of revisions.
- **Revision workflow** — when a customer asks for changes, the current MP3s are archived and the operator sees the request as "Revisions Requested" in the dashboard.
- **Rate limiting** — the public request form is capped at 5 submissions per minute per IP.
### Operator/admin
- **Admin login** (`/admin/login`) — simple session-based login protected by `ADMIN_PASSWORD`.
- **Dashboard queue** (`/admin`) — filter by status (All, Pending, Needs Upload, Awaiting Payment, Delivered) and auto-refresh at a configurable interval.
- **Per-request detail page** (`/admin/request/<id>`):
- Generate and save a Suno prompt from customer info.
- Upload Version A and Version B MP3s (with automatic ID3 metadata tagging).
- Send a preview email with a private player link.
- Mark paid, enter a Square payment reference, and deliver selected MP3 attachments.
- **Settings / maintenance page** (`/admin/settings`):
- Database health check with optional schema repair.
- Database statistics, size, upload counts.
- Configure customer revision limit.
- Configure dashboard auto-refresh interval.
- Configure SMTP host/port/user/from; store the SMTP password encrypted.
- Configure default MP3 metadata tags (artist, album, year, comment).
- Send a test email.
- Download or restore the SQLite database backup.
- Reset the entire system for a new event.
- **Per-request delete** and **system reset** — remove requests and uploaded files; reset auto-increment back to 1.
## Status flow
@ -20,33 +41,36 @@ pending → prompt_ready → songs_uploaded → awaiting_payment → paid → de
| Status | Meaning |
|---|---|
| `pending` | Customer submitted request; no prompt yet. |
| `pending` | Customer submitted a request; operator has not saved a prompt yet. |
| `prompt_ready` | Operator saved Title/Style/Lyrics. |
| `songs_uploaded` | Both MP3s uploaded; preview link can be sent. |
| `awaiting_payment` | Customer approved a version. |
| `paid` | Payment reference recorded; delivery email sent. |
| `delivered` | MP3 attachments emailed. |
| `songs_uploaded` | Both MP3s uploaded; preview link can be sent. Dashboard filter label: **Needs Upload** (shown for this state when filtering). |
| `revisions_requested` | Customer asked for changes; current files were archived. |
| `awaiting_payment` | Customer approved a version; waiting for operator to collect payment and deliver. |
| `paid` | Payment recorded (used internally). |
| `delivered` | MP3 attachment(s) emailed to the customer. |
## File layout
| File | Purpose |
|---|---|
| `app.py` | Flask routes, helpers, and email logic. |
| `config.py` | Environment-variable based configuration. |
| `models.py` | SQLite schema and database helper functions. |
| `app.py` | Flask routes, helpers, email layer, runtime settings, MP3 tagging, rate limiting, and DB maintenance helpers. |
| `config.py` | Environment-variable based configuration; defines defaults for DB, uploads, SMTP, and secrets. |
| `models.py` | SQLite schema and CRUD helpers. |
| `init_db.py` | Standalone script to create the database tables. |
| `templates/request.html` | Customer request form (with banner). |
| `templates/request.html` | Customer request form. |
| `templates/thanks.html` | Post-submission confirmation. |
| `templates/player.html` | Customer audio player and approval page. |
| `templates/admin/login.html` | Admin password login. |
| `templates/admin/dashboard.html` | Operator queue with filters and reset. |
| `templates/admin/request.html` | Single-request detail / prompt / upload / delivery. |
| `templates/player.html` | Customer audio player, approval, and revision form. |
| `templates/admin/login.html` | Admin login page. |
| `templates/admin/dashboard.html` | Operator queue with filters and auto-refresh. |
| `templates/admin/request.html` | Single-request detail / prompt / upload / delivery page. |
| `templates/admin/settings.html` | Maintenance, settings, backup/restore, and reset page. |
| `static/Trollgorithm_booth.jpg` | Banner image on the request page. |
| `static/DM-Logo_email.png` | Inline Dionysis Media logo attached to emails. |
| `Dockerfile` | Production container image. |
| `docker-compose.yml` | Portainer stack definition. |
| `requirements.txt` | Python dependencies. |
| `.env.example` | Template for environment variables. |
| `REVIEW.md` | Quick reference for returning to this project. |
| `.env.example` | Template for local environment variables. |
| `REVIEW.md` | Quick-reference for returning to this project. |
## Local development
@ -76,18 +100,19 @@ Visit:
| Variable | Required | Purpose |
|---|---|---|
| `APP_SECRET_KEY` | Yes | Long random string for Flask sessions. Generate with `python3 -c "import secrets; print(secrets.token_hex(32))"`. |
| `APP_SECRET_KEY` | Yes | Long random string for Flask sessions and to encrypt stored SMTP password. Generate with `python3 -c "import secrets; print(secrets.token_hex(32))"`. |
| `ADMIN_PASSWORD` | Yes | Password for `/admin`. |
| `SMTP_PASS` | Yes | Password for `ai@hallsworth.ca`. |
| `SMTP_PASS` | Yes | Password for the SMTP account. |
| `PUBLIC_BASE_URL` | Yes | Public HTTPS URL, e.g. `https://booth.dionysismedia.ca`. |
| `HOST_PORT` | No | Host-side port mapping, default `127.0.0.1:8000`. |
| `INTERNAL_PORT` | No | Port gunicorn binds inside container, default `8000`. |
| `BOOTH_NAME` | No | Name used in emails, default `Trollgorithm Theme Songs`. |
| `PRICE_PER_VERSION` | No | Shown on receipt page, default `10.00`. |
| `PRICE_PER_VERSION` | No | Shown to the operator/customer, default `10.00`. |
| `CURRENCY` | No | Currency label, default `CAD`. |
| `MAX_REVISIONS` | No | Default customer revision limit if not changed in settings, default `2`. |
5. Deploy the stack.
6. Open a console in the `booth` container and run once:
6. Open a console in the `theme-song-booth` container and run once:
```bash
python init_db.py
@ -103,8 +128,11 @@ After each push to GitLab, go to Portainer → **Stacks** → `theme-song-booth`
## Important notes
- **No `.env` file in production.** `docker-compose.yml` passes variables directly from Portainer. This avoids Portainer's `env_file not found` error.
- **Runtime settings persist.** SMTP config, revision limit, auto-refresh interval, and MP3 metadata defaults are stored encrypted (where sensitive) in `booth_settings.json` inside the persistent uploads volume. They survive redeploys.
- **Payments are manual.** The app records a Square payment reference but does not integrate with Square's API. Use a Square Terminal/Reader at the booth.
- **Operator queue is the dashboard.** No operator email alerts are sent; approvals and revision notes appear as status changes in `/admin`.
- **MP3 metadata.** Uploaded files are tagged with title (from the saved prompt), plus configured artist/album/year/comment values.
- **Email logo.** `static/DM-Logo_email.png` is attached inline to all customer emails as the Dionysis Media signature.
- **Security:** the repo is public on GitLab. No secrets are committed. Admin password is plain text in the Portainer environment.
## Common troubleshooting
@ -112,9 +140,11 @@ After each push to GitLab, go to Portainer → **Stacks** → `theme-song-booth`
| Problem | Cause | Fix |
|---|---|---|
| "Send Preview Link" does nothing | Form tags were unbalanced (now fixed). | Redeploy the latest commit. |
| Emails not arriving | SMTP_PASS wrong or messages in spam. | Verify SMTP credentials; check spam folder. |
| Emails not arriving | SMTP settings wrong or messages in spam. | Use **Send Test Email** on `/admin/settings`; verify host/port/password. |
| Can't reach app through domain | Reverse proxy points to wrong host port. | Match `HOST_PORT` to your proxy upstream. |
| Static banner not showing | Browser cached old image. | Hard-refresh or redeploy stack. |
| Logo missing from email | Logo file missing from `static/`. | Ensure `static/DM-Logo_email.png` is in the container. |
| Database schema mismatch | New column added but old DB not migrated. | Go to `/admin/settings` and click **Fix Missing Columns**, or run `python init_db.py`. |
## License / ownership