# 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. ## What this project does - **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/` 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. ## Status flow ``` pending → prompt_ready → songs_uploaded → awaiting_payment → paid → delivered ``` | Status | Meaning | |---|---| | `pending` | Customer submitted request; no 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. | ## 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. | | `init_db.py` | Standalone script to create the database tables. | | `templates/request.html` | Customer request form (with banner). | | `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. | | `static/Trollgorithm_booth.jpg` | Banner image on the request page. | | `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. | ## Local development ```bash cd /home/jess/workspace/theme-song-booth python3 -m venv .venv .venv/bin/pip install -r requirements.txt cp .env.example .env # Edit .env and set APP_SECRET_KEY, ADMIN_PASSWORD, SMTP_PASS, PUBLIC_BASE_URL .venv/bin/python init_db.py .venv/bin/python -m flask --app app run --host=0.0.0.0 ``` Visit: - Customer form: http://127.0.0.1:5000/request - Admin login: http://127.0.0.1:5000/admin ## Deployment with Portainer 1. Log in to Portainer. 2. Go to **Stacks** → **Add stack**. 3. Choose **Repository**: - URL: `https://gitlab.hallsworth.ca/yrtria/theme-song-booth.git` - Branch: `main` - Compose path: `docker-compose.yml` 4. Add environment variables: | Variable | Required | Purpose | |---|---|---| | `APP_SECRET_KEY` | Yes | Long random string for Flask sessions. 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`. | | `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`. | | `CURRENCY` | No | Currency label, default `CAD`. | 5. Deploy the stack. 6. Open a console in the `booth` container and run once: ```bash python init_db.py ``` 7. Point your reverse proxy at the `HOST_PORT` you chose. 8. Print or display a QR code pointing to `https://your-domain/request`. ### Updating the deployment After each push to GitLab, go to Portainer → **Stacks** → `theme-song-booth` → **Pull and redeploy** to rebuild from the repo. ## Important notes - **No `.env` file in production.** `docker-compose.yml` passes variables directly from Portainer. This avoids Portainer's `env_file not found` error. - **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`. - **Security:** the repo is public on GitLab. No secrets are committed. Admin password is plain text in the Portainer environment. ## Common troubleshooting | 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. | | 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. | ## License / ownership Built for Jess's Trollgorithm theme-song booth. All code and assets are private to that project.