Files
Bookra/apps/backend
Tomas DvorakandDevin cdad7875e1 fix(reminders): lifecycle-aware jobs and dispatch skip guard
The reminder pipeline fired regardless of what happened to the booking
after creation: cancelled customers got reminded about bookings that
weren't happening, reschedules kept the old reminder time, and
waitlisted bookings armed jobs too. Pending jobs are now cancelled on
both cancel paths, deleted and re-armed on reschedule, and dispatch
joins bookings.status to skip anything not confirmed. Reschedule also
gained the same availability-window and blocked-day validation as
booking creation, closing a 3am-reschedule hole via the manage URL.

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-18 12:47:07 +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