Tenants paying for the SMS add-on still got email-only reminders — the channel column existed but nothing armed or dispatched sms jobs. Booking creation now adds a second job when SMS is enabled and the customer left a phone; dispatch routes sms jobs through an injected sender adapter wired to the existing sms.Service, so monthly limits, usage metering, and Stripe billing apply unchanged. Lifecycle handling from the previous milestone clears and re-arms both channels together. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Bookra
Remote-first booking SaaS aligned to the tdvorak-fullstack profile with these overrides:
- frontend on Vercel
- backend on Railway
- Neon Postgres + Neon Auth
- Stripe billing (checkout, customer portal, webhooks, SMS usage invoices)
- no Docker-based local runtime
Workspace
apps/frontendSolidJS frontendapps/backendGo APIpackages/api-clientgenerated TypeScript client/types from OpenAPIpackages/shared-typesshared frontend constants and helpers
Local development
Frontend
npm install
npm run dev:frontend
Backend
cd apps/backend
go run ./cmd/api
Both apps expect remote services:
- Neon Postgres
- Neon Auth
- Stripe
See .env.example, apps/frontend/.env.example, and apps/backend/.env.example.
Demo mode
Set BOOKRA_DEMO_MODE=true to run the backend with an in-memory repository and
pre-populated demo data — no database, Neon Auth, or Stripe required. All
requests are authenticated as the demo-owner principal. Pair with
VITE_BOOKRA_DEMO_MODE=true on the frontend.
CI/CD
- GitHub Actions CI lives in
.github/workflows/ci.yml - rollout notes and platform wiring live in docs/ci-cd.md
Backend database commands
npm run db:migrate:status
npm run db:migrate:up
db:migrate:* expects BOOKRA_DATABASE_DIRECT_URL to be exported in the shell.
The API client types are regenerated from the OpenAPI spec:
npm run generate:api-client
Verification
npm run verify
Runs API-client generation, frontend typecheck, backend tests, and both builds. Run this before pushing.
Brand Colors
Bookra uses a sophisticated color system designed for modern booking interfaces with support for both light and dark themes.
Primary Palette
- Canvas (
--color-canvas): #FFFFFF (light) / #0A0A0A (dark) - Canvas Elevated (
--color-canvas-elevated): #F8F9FA (light) / #1A1A1A (dark) - Canvas Sunken (
--color-canvas-sunken): #F1F3F4 (light) / #252525 (dark)
Accent Colors
- Primary (
--color-primary): #3B82F6 - Primary Hover (
--color-primary-hover): #2563EB - Primary Active (
--color-primary-active): #1D4ED8
Semantic Colors
- Success (
--color-success): #10B981 - Warning (
--color-warning): #F59E0B - Error (
--color-error): #EF4444 - Info (
--color-info): #06B6D4
Text Colors
- Text Primary (
--color-text-primary): #111827 (light) / #F9FAFB (dark) - Text Secondary (
--color-text-secondary): #6B7280 (light) / #D1D5DB (dark) - Text Muted (
--color-text-muted): #9CA3AF (light) / #9CA3AF (dark)
Border & Surface
- Border (
--color-border): #E5E7EB (light) / #374151 (dark) - Surface Glass (
--color-surface-glass): rgba(255, 255, 255, 0.8) (light) / rgba(0, 0, 0, 0.8) (dark)
Shadow System
- Shadow XS (
--shadow-xs): 0 1px 2px 0 rgba(0, 0, 0, 0.05) - Shadow SM (
--shadow-sm): 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.06) - Shadow MD (
--shadow-md): 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06) - Shadow LG (
--shadow-lg): 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05) - Shadow XL (
--shadow-xl): 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04) - Shadow 2XL (
--shadow-2xl): 0 25px 50px -12px rgba(0, 0, 0, 0.25)
Animation Timing
- Ease Out Expo (
--ease-out-expo): cubic-bezier(0.16, 1, 0.3, 1) - Ease Spring (
--ease-spring): cubic-bezier(0.68, -0.55, 0.265, 1.55)
These colors are implemented as CSS custom properties and are used throughout the frontend application for consistent theming and accessibility.