Files
Bookra/apps/backend
Tomas DvorakandDevin 1cd5b1ba91 feat(classes): session roster + manual waitlist promotion
Adds the roster and manual promotion controls deferred from the booking
lifecycle milestones. Businesses can now inspect who holds a seat and who
is queueing on a class session, and promote waitlisted customers by hand
— including a deliberate over-capacity override when the session is full.

Backend:
- GET /v1/catalog/class-sessions/{id}/roster — session metadata plus
  confirmed and waitlist entry lists with queue positions
- POST /v1/catalog/bookings/{id}/promote — 409 on a full session unless
  allowOverCapacity is set; 400 for non-waitlisted, 404 for missing or
  foreign bookings; reuses the shared confirm path so waitlist ledger
  rows resolve and reminder jobs re-arm
- ListBookingsBySession repository method (pgx + memory); ClassSession
  carries waitlistCount; UpcomingBooking carries classSessionId and
  waitlistPosition
- OpenAPI paths + schemas, regenerated client, catalog service tests

Frontend:
- classes tab session rows expand into a two-column roster panel with
  per-entry promote buttons and an explicit confirm-anyway step on 409
- booking detail modal shows waitlist position and offers promote for
  waitlisted bookings; list badges show #N queue positions
- CS/EN i18n keys and seeded demo roster data; demo mutations surface
  the demo notice

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-18 14:37:40 +02:00
..
2026-05-05 09:48:15 +02:00
2026-05-05 09:48:15 +02:00
2026-05-05 09:48:07 +02:00
2026-05-05 09:48:15 +02:00

Bookra Backend

Go + Gin API for Bookra, designed for Railway deployment with Neon Auth, Neon Postgres, and Stripe billing.

Commands

go run ./cmd/api
go build ./...
go test ./...
npm run db:migrate:status
npm run db:migrate:up

Environment

  • BOOKRA_FRONTEND_URL allowed browser origin
  • BOOKRA_DATABASE_URL Neon pooled connection
  • BOOKRA_DATABASE_DIRECT_URL Neon direct connection for migrations/admin tasks
  • BOOKRA_NEON_AUTH_URL Neon Auth base URL used for JWKS verification
  • BOOKRA_AUTH_JWT_SECRET local JWT secret for the password-auth endpoints
  • BOOKRA_JOB_RUNNER_KEY shared secret for remote job-runner calls
  • BOOKRA_EMAIL_FROM sender identity for email reminders
  • BOOKRA_SMTP_* optional SMTP transport for email delivery
  • BOOKRA_STRIPE_API_KEY Stripe secret API key
  • BOOKRA_STRIPE_WEBHOOK_SECRET Stripe webhook signing secret
  • BOOKRA_STRIPE_{STARTER,PRO,BUSINESS}_{CZK,USD}_{MONTHLY,YEARLY}_PRICE_ID Stripe price IDs
  • BOOKRA_STRIPE_SMS_{CZK,USD,...}_PRICE_ID Stripe SMS usage price IDs
  • BOOKRA_SMSMANAGER_API_KEY optional SMS Manager.cz key
  • BOOKRA_UMAMI_API_URL and BOOKRA_UMAMI_API_KEY optional analytics integration
  • BOOKRA_ADMIN_EMAIL and BOOKRA_ADMIN_KEY optional platform admin API credentials
  • BOOKRA_SENTRY_DSN optional error monitoring

See .env.example for the full list.

Notes

  • Auth verification is isolated in internal/auth.
  • OpenAPI lives in openapi/bookra.openapi.yaml.
  • SQL migrations live in migrations/ (goose).
  • Repositories are handwritten pgx in internal/db/; there is no generated query layer.
  • Goose migrations are wired through npm run db:migrate:* and use the Neon direct connection URL.
  • Reminder dispatch runs through POST /v1/internal/jobs/reminders/dispatch with X-Bookra-Job-Key.
  • BOOKRA_DEMO_MODE=true swaps the repository for deterministic in-memory demo data and authenticates all requests as demo-owner.

Production Auth

Bookra production auth uses Neon Auth directly:

  • frontend uses VITE_NEON_AUTH_URL
  • backend verifies Neon JWTs with BOOKRA_NEON_AUTH_URL

Trusted redirect domains in Neon Auth should include your frontend origin such as https://bookra.eu, plus local dev origins when needed.

Stripe Setup

Get these values from the Stripe dashboard:

  • BOOKRA_STRIPE_API_KEY: Developers -> API keys -> secret key
  • BOOKRA_STRIPE_WEBHOOK_SECRET: Developers -> Webhooks -> destination signing secret
  • BOOKRA_STRIPE_*_PRICE_ID: Product catalog -> recurring price IDs

Create one recurring price per plan/currency/interval you support:

  • starter / pro / business × czk / usd × monthly / yearly

Set the webhook destination to:

POST /v1/webhooks/stripe

Subscribe to at least: checkout.session.completed, customer.subscription.created, customer.subscription.updated, customer.subscription.deleted, invoice.payment_succeeded, invoice.payment_failed.

For local testing:

stripe listen --forward-to http://localhost:8080/v1/webhooks/stripe