Implementation Plan: Otterly Fun Swim School
Maps the full architecture, database schema, page routes, and phased implementation for a swim school booking platform built on Next.js and self-hosted Supabase.
What this file does
Maps the full architecture, database schema, page routes, and phased implementation for a swim school booking platform built on Next.js and self-hosted Supabase.
When to use it
- Starting a new Next.js + Supabase project with a booking system
- Planning a self-hosted Supabase deployment for a small business app
- Designing a multi-client system (web, mobile, WhatsApp) sharing one API layer
- Documenting a project's tech stack, schema, and deployment plan for a team
Assumes this stack
Implementation Plan: Otterly Fun Swim School
1. Tech Stack Overview
| Layer | Technology | Notes |
|---|---|---|
| Frontend | Next.js 14 (App Router) | React-based, SSR/SSG, TypeScript |
| Styling | Tailwind CSS | Utility-first, responsive design |
| Backend / API | Next.js Route Handlers + Supabase | REST API via route handlers; Supabase for auth, DB, storage |
| Database | PostgreSQL (via self-hosted Supabase) | Relational, Row Level Security (RLS) |
| Authentication | Supabase Auth | Email/password for trainers; magic-link or OAuth for parents (future) |
| Supabase Edge Functions + Resend (or SMTP) | Transactional emails for booking confirmations | |
| Hosting | Docker Compose (self-hosted Supabase) + Vercel or VPS for Next.js | Supabase stack on VPS; Next.js deployed separately |
| Future: WhatsApp Bot | Supabase Edge Functions + WhatsApp Business API | Stateless functions hitting shared DB |
| Future: Mobile App | React Native (Expo) | Shares API layer with web |
2. Architecture Diagrams
2.1 High-Level System Architecture
graph TB
subgraph "Clients"
WEB["š Next.js Web App<br/>(Parents & Trainers)"]
MOBILE["š± Mobile App<br/>(React Native ā Future)"]
WHATSAPP["š¬ WhatsApp Bot<br/>(Future)"]
end
subgraph "Self-Hosted Supabase (Docker)"
AUTH["š Supabase Auth"]
API["š PostgREST API"]
DB[("š PostgreSQL")]
STORAGE["š Supabase Storage"]
EDGE["ā” Edge Functions"]
REALTIME["š Realtime"]
end
subgraph "External Services"
EMAIL["š§ Email Service<br/>(Resend / SMTP)"]
WA_API["WhatsApp<br/>Business API"]
end
WEB --> AUTH
WEB --> API
MOBILE --> AUTH
MOBILE --> API
WHATSAPP --> EDGE
EDGE --> WA_API
EDGE --> DB
EDGE --> EMAIL
API --> DB
AUTH --> DB
API --> STORAGE
2.2 Database Schema (ERD)
erDiagram
TRAINERS {
uuid id PK
text email
text full_name
text phone
timestamptz created_at
}
COURSES {
uuid id PK
text title
text description
text level "beginner | intermediate | advanced"
text prerequisites
text goals
int price_cents
text currency
int max_participants
text location
boolean is_active
timestamptz created_at
}
COURSE_SESSIONS {
uuid id PK
uuid course_id FK
uuid trainer_id FK
date start_date
date end_date
text day_of_week
time start_time
time end_time
int spots_available
text status "open | full | cancelled"
}
PARENTS {
uuid id PK
uuid auth_user_id FK "nullable ā future auth"
text email
text full_name
text phone
timestamptz created_at
}
CHILDREN {
uuid id PK
uuid parent_id FK
text full_name
date date_of_birth
text swimming_level
text notes
}
BOOKINGS {
uuid id PK
uuid session_id FK
uuid child_id FK
uuid parent_id FK
text status "pending | confirmed | cancelled"
timestamptz booked_at
text payment_status "unpaid | paid | refunded"
text payment_reference
}
SESSION_LOGS {
uuid id PK
uuid session_id FK
uuid trainer_id FK
date log_date
text notes
text attendance "jsonb ā child_id + present boolean"
timestamptz created_at
}
TRAINERS ||--o{ COURSE_SESSIONS : leads
COURSES ||--o{ COURSE_SESSIONS : "has many"
PARENTS ||--o{ CHILDREN : "has many"
PARENTS ||--o{ BOOKINGS : places
CHILDREN ||--o{ BOOKINGS : "is booked in"
COURSE_SESSIONS ||--o{ BOOKINGS : contains
COURSE_SESSIONS ||--o{ SESSION_LOGS : "has logs"
TRAINERS ||--o{ SESSION_LOGS : writes
2.3 Next.js Page / Route Structure
graph LR
subgraph "Public Pages (Parents)"
HOME["/"]
ABOUT["/about"]
COURSES_PAGE["/courses"]
COURSE_DETAIL["/courses/[id]"]
SCHEDULE["/schedule"]
BOOKING["/courses/[id]/book"]
PREP["/preparation"]
CONFIRM["/booking/confirmation"]
end
subgraph "Trainer Dashboard (Auth Required)"
DASH["/dashboard"]
SESSIONS["/dashboard/sessions"]
SESSION_LOG["/dashboard/sessions/[id]/log"]
MANAGE_COURSES["/dashboard/courses"]
end
subgraph "API Routes (/api)"
API_BOOK["/api/bookings"]
API_COURSES["/api/courses"]
API_SESSIONS["/api/sessions"]
API_LOGS["/api/session-logs"]
API_EMAIL["/api/send-email"]
API_WA["/api/whatsapp (future)"]
end
HOME --> COURSES_PAGE --> COURSE_DETAIL --> BOOKING --> CONFIRM
DASH --> SESSIONS --> SESSION_LOG
DASH --> MANAGE_COURSES
2.4 Booking Flow (Sequence Diagram)
sequenceDiagram
actor Parent
participant Web as Next.js Frontend
participant API as Next.js API Route
participant DB as Supabase PostgreSQL
participant Email as Email Service
Parent->>Web: Browse courses & schedule
Web->>API: GET /api/courses
API->>DB: SELECT courses + sessions
DB-->>API: Course data
API-->>Web: JSON response
Web-->>Parent: Display courses with availability
Parent->>Web: Select course session & fill form
Web->>API: POST /api/bookings {session_id, parent info, child info}
API->>DB: BEGIN TRANSACTION
API->>DB: Check spots_available > 0
DB-->>API: OK
API->>DB: INSERT parent (if new)
API->>DB: INSERT child (if new)
API->>DB: INSERT booking (status: confirmed)
API->>DB: UPDATE session spots_available -= 1
API->>DB: COMMIT
DB-->>API: Booking created
API->>Email: Send confirmation email with payment info
Email-->>Parent: š§ Booking confirmation
API-->>Web: 201 Created
Web-->>Parent: Show confirmation page
2.5 Future: WhatsApp Bot Architecture
graph TB
PARENT_WA["š± Parent on WhatsApp"] -->|message| WA_CLOUD["WhatsApp Cloud API"]
WA_CLOUD -->|webhook| EDGE_FN["ā” Supabase Edge Function<br/>/whatsapp-webhook"]
EDGE_FN -->|query| DB[("š PostgreSQL")]
EDGE_FN -->|call| AI["š¤ AI/LLM API<br/>(OpenAI / Anthropic)"]
AI -->|response| EDGE_FN
EDGE_FN -->|reply| WA_CLOUD
WA_CLOUD -->|message| PARENT_WA
EDGE_FN -->|"book course"| DB
EDGE_FN -->|"send confirmation"| EMAIL["š§ Email Service"]
2.6 Future: Mobile App Architecture
graph TB
subgraph "Mobile App (React Native / Expo)"
SCREENS["Screens:<br/>Home, Courses, My Bookings,<br/>Payments, Profile"]
PUSH["Push Notifications"]
end
subgraph "Shared Backend (Self-Hosted Supabase)"
AUTH["Supabase Auth"]
API["PostgREST API"]
RT["Realtime Subscriptions"]
DB[("PostgreSQL")]
end
SCREENS --> AUTH
SCREENS --> API
API --> DB
RT --> SCREENS
PUSH -.->|"via Edge Function"| SCREENS
3. Implementation Phases
Phase 1 ā Foundation & Information Pages
Goal: Get the website live with static content and course information.
| Task | Details |
|---|---|
| Set up Next.js project | App Router, TypeScript, Tailwind CSS, ESLint |
| Self-host Supabase | Docker Compose on VPS, configure PostgreSQL, Auth, Storage |
| Create database schema | Courses, course_sessions, trainers tables + seed data |
| Build public pages | Home, About/Location, Courses listing, Course detail, Preparation tips |
| Responsive design | Mobile-first layout with Tailwind |
| SEO & metadata | Open Graph tags, structured data for local business |
Phase 2 ā Booking System & Email
Goal: Parents can book courses and receive confirmation emails.
| Task | Details |
|---|---|
| Extend schema | Add parents, children, bookings tables |
| Build booking flow | Booking form on course page ā API route ā DB insert |
| Availability logic | Real-time spot tracking, disable booking when full |
| Email integration | Set up Resend or SMTP; send confirmation with payment info |
| Booking confirmation page | Thank-you page with summary and next steps |
| Input validation | Zod schemas for all form inputs |
Phase 3 ā Trainer Dashboard
Goal: Trainers can log in, view sessions, and keep training logs.
| Task | Details |
|---|---|
| Supabase Auth setup | Email/password login for trainers |
| Trainer dashboard layout | Protected routes with middleware |
| Session management | View upcoming & past sessions |
| Session logs | Create/edit logs per session (notes, attendance tracking) |
| Course management | CRUD operations for courses and sessions |
| Row Level Security | RLS policies so trainers only access their own data |
Phase 4 ā AI-Powered WhatsApp Bot (Future)
Goal: Parents can interact with the swim school via WhatsApp.
| Task | Details |
|---|---|
| WhatsApp Business API setup | Register number, configure webhook |
| Supabase Edge Function | Webhook handler for incoming messages |
| AI integration | Connect to LLM for natural language understanding |
| Intent handling | Answer FAQs, check availability, make bookings |
| Conversation state | Track multi-turn conversations in DB |
| Testing & moderation | Safety guardrails, fallback to human support |
Phase 5 ā Mobile App (Future)
Goal: Parents manage bookings and interact with the school on mobile.
| Task | Details |
|---|---|
| Expo / React Native setup | Shared API layer with web |
| Authentication | Supabase Auth with secure token storage |
| Core screens | Home, Courses, My Bookings, Payments, Profile |
| Push notifications | Course reminders, booking confirmations |
| Realtime updates | Live availability via Supabase Realtime |
4. Project Structure
otterly-fun/
āāā src/
ā āāā app/ # Next.js App Router
ā ā āāā (public)/ # Public route group
ā ā ā āāā page.tsx # Home
ā ā ā āāā about/page.tsx
ā ā ā āāā courses/
ā ā ā ā āāā page.tsx # Course listing
ā ā ā ā āāā [id]/
ā ā ā ā āāā page.tsx # Course detail
ā ā ā ā āāā book/page.tsx
ā ā ā āāā schedule/page.tsx
ā ā ā āāā preparation/page.tsx
ā ā ā āāā booking/
ā ā ā āāā confirmation/page.tsx
ā ā āāā dashboard/ # Trainer (protected)
ā ā ā āāā page.tsx
ā ā ā āāā sessions/
ā ā ā ā āāā page.tsx
ā ā ā ā āāā [id]/log/page.tsx
ā ā ā āāā courses/page.tsx
ā ā āāā api/
ā ā ā āāā bookings/route.ts
ā ā ā āāā courses/route.ts
ā ā ā āāā sessions/route.ts
ā ā ā āāā session-logs/route.ts
ā ā ā āāā send-email/route.ts
ā ā āāā layout.tsx
ā āāā components/
ā ā āāā ui/ # Reusable UI components
ā ā āāā courses/ # Course-specific components
ā ā āāā booking/ # Booking form components
ā ā āāā dashboard/ # Trainer dashboard components
ā āāā lib/
ā ā āāā supabase/
ā ā ā āāā client.ts # Browser Supabase client
ā ā ā āāā server.ts # Server Supabase client
ā ā ā āāā admin.ts # Service-role client
ā ā āāā email.ts # Email sending utility
ā ā āāā validations.ts # Zod schemas
ā āāā types/
ā ā āāā database.ts # Generated Supabase types
ā āāā styles/
ā āāā globals.css
āāā supabase/
ā āāā docker-compose.yml # Self-hosted Supabase
ā āāā migrations/ # SQL migration files
ā ā āāā 001_create_trainers.sql
ā ā āāā 002_create_courses.sql
ā ā āāā 003_create_sessions.sql
ā ā āāā 004_create_parents_children.sql
ā ā āāā 005_create_bookings.sql
ā ā āāā 006_create_session_logs.sql
ā āāā seed.sql # Initial seed data
ā āāā config.toml
āāā public/
ā āāā images/
āāā .env.local
āāā next.config.ts
āāā tailwind.config.ts
āāā tsconfig.json
āāā package.json
āāā README.md
5. Key Technical Decisions
Why Self-Hosted Supabase?
- Full control over data and infrastructure (important for handling children's data).
- No vendor lock-in; can scale independently.
- Cost-effective at scale compared to Supabase Cloud.
- Edge Functions run locally, ideal for future WhatsApp bot webhook handling.
Why Next.js App Router?
- Server components reduce client-side JavaScript for fast page loads.
- Built-in API routes keep the backend co-located with the frontend.
- SSR for SEO-critical pages (courses, schedules).
- Easy to add authentication middleware for the trainer dashboard.
Future-Proof API Design
- All data access goes through Supabase PostgREST or Next.js API routes.
- The same API layer will serve the mobile app and WhatsApp bot ā no duplication.
- Row Level Security ensures consistent authorization regardless of client.
Database Design for Extensibility
parentstable has an optionalauth_user_idā no auth required now, ready for login later.session_logswith JSON attendance enables flexible tracking without schema changes.- All tables use UUIDs as primary keys for easy cross-system integration.
6. Environment & Deployment
# .env.local (example)
NEXT_PUBLIC_SUPABASE_URL=https://supabase.yourdomain.com
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
RESEND_API_KEY=your-resend-api-key
| Component | Deployment |
|---|---|
| Supabase (Postgres, Auth, PostgREST, Edge Functions) | Docker Compose on VPS (e.g., Hetzner, DigitalOcean) |
| Next.js | Vercel (easiest) or self-hosted on same/different VPS |
| Domain & SSL | Caddy or Nginx reverse proxy with Let's Encrypt |
| CI/CD | GitHub Actions ā lint, test, deploy on push to main |
7. Non-Functional Requirements
- Performance: Lighthouse score > 90 on all public pages.
- Accessibility: WCAG 2.1 AA compliance.
- Security: RLS on all tables, input validation with Zod, CSRF protection.
- Privacy: GDPR-aware ā minimal data collection, parental consent flows.
- Monitoring: Basic uptime monitoring and error tracking (e.g., Sentry).
- Backups: Automated PostgreSQL backups via cron on VPS.
What's inside
7 sections: tech stack table, 6 Mermaid diagrams, 5 implementation phases, project tree, key decisions, environment config, non-functional requirements
Change this for your project
- Replace
otterly-funwith your project name in the directory tree and README - Replace
https://supabase.yourdomain.comwith your actual Supabase URL - Replace
your-anon-key,your-service-role-key, andyour-resend-api-keywith your own credentials - Replace
josefinaalgotsson/otterly-funwith your repository URL
Where it goes
Save in docs/ or the repository root. Gives agents and new contributors a map of the codebase.
Worth borrowing
- Separate parent-facing public routes from trainer dashboard routes using Next.js route groups
- Use optional
auth_user_idon the parents table to defer authentication until needed - Store attendance as JSONB in session_logs to avoid schema changes for flexible tracking
Related Documents
Design Document: BharatSeva AI
Describes a 10-agent AWS system that helps India's informal workers access government schemes via voice-first, serverless architecture.
OpenClaw Enterprise Transformation Plan
Transforms a single-user AI agent into a dual-mode platform supporting both viral open-source and Fortune 500 enterprise deployments through phased security, IAM, audit, multi-tenancy, and Kubernetes features.
Qwen Image and Edit: Open-sourcing and Local GGUF Generations with Lightning
Documents the Qwen-Image and Qwen-Image-Edit models, covering architecture, training, benchmarks, ComfyUI setup, and prompting techniques for local GGUF deployment.
University of Guelph Rocketry Club - Complete Tech Stack
Documents the full tech stack of a university rocketry club website with AI chatbot, member management, and project showcases.