Live schedule for DFW open mics, built with Angular and served via a lightweight Node/Express host.
- Install dependencies with
npm install(ornpm ciif you prefer a clean install). - Run
npm run startto start the dev server onhttp://localhost:4200/; the browser auto-opens with live reload. - Specs live next to the code; execute
npx ng test --watchduring development for fast feedback. - Service worker updates are enabled; when testing locally you can toggle deterministic builds with
npx ng config cli.cache.enabled false.
- Run
npm run build(ornpx ng build --configuration production) to emit production assets intodist/openmicjoy/. - The output bundle is what CI uploads and what the Docker image serves from the
/app/distdirectory.
- Running
docker compose up --build -dworks well. - Copy
.env.omjapp.exampleto.env.omjappand adjust non-secret values as needed. docker-compose*.ymlloads that file viaenv_file, so values such asADMIN_API_KEY,CONTACT_TO, etc. become environment variables inside the container without exporting them manually.- Build and start the container with
docker compose -f docker-compose.omjapp.yml up -d(the default file mirrors prod wiring). - The container exposes port
4000internally; behind a reverse proxy setVIRTUAL_HOST,LETSENCRYPT_HOST, andVIRTUAL_PORTper the compose file. - Health checks hit
/health(GET and HEAD) and should respond with HTTP 200 JSON.
.env.omjapp.exampledocuments the required environment variables; it intentionally omits secrets.- SMTP credentials are sourced from the
omj_sendgrid_api_keyDocker secret and mounted at runtime (seedocker-compose*.yml). - Contact routing uses the
CONTACT_TOandCONTACT_FROMvalues; override them in.env.omjappwithout committing secrets. - When you run
node server.cjs(ornpm run serve:node) locally, the host automatically loads.envthen.env.omjappif they exist, so you can defineADMIN_API_KEY, mail overrides, etc. without exporting them manually.
- Every POST to
/api/contactsends an email and then appends sanitized JSON snapshots todata/contact-submissions.json(all messages) and, when an actionable event is included, todata/event-submissions.json. - Set
EVENT_STORAGE_DIR=/some/pathto relocate those files (defaults to<repo>/data); the server creates the directory if it does not exist. - Event records include
id,submittedAt, contact info, request type, and the normalized event payload (name, description, cadence, next show date, etc.) so approvers can review without digging through email. - Download a fresh copy at any time with
docker exec <container> cat /app/data/event-submissions.json(or the custom path) before curating the schedule.
- Five taps/clicks on the OMJ logo (within three seconds) reveal a fourth toolbar icon that links to
/admin. It is intentionally hidden from the public nav. - The admin view prompts for the shared passphrase and then calls
GET /api/admin/event-submissions, sending the passphrase as thex-omj-admin-keyheader. - Set
ADMIN_API_KEYin.env.omjapp(and in production secrets) to enable the endpoint; when unset, the API returns503 admin_disabled. - The UI stores the passphrase in-memory only; refresh the queue from the page header after triaging events in
data/event-submissions.json.