united-tattoo/docs/architecture.md

22 KiB
Raw Blame History

United Tattoo Backend Architecture Document

Version: 1.0
Date: 2025-09-17
Output Template: .bmad-core/templates/architecture-tmpl.yaml (architecture-template-v2)
Basis: docs/PRD.md, repo config (wrangler.toml, open-next.config.ts, next.config.mjs, package.json), lib/*, sql/schema.sql

Introduction

This document outlines the backend architecture for United Tattoo, including platform/runtime, data, integrations, security, operations, and nonUI concerns. It is the blueprint for AI-driven and human development to implement the PRD.

Relationship to Frontend Architecture: A separate Frontend Architecture document should cover UI state, routing, component patterns, and UX specifics. Core technology selections herein (Cloudflare, Next.js App Router, D1/R2, Auth.js, Zod) apply project-wide.

Starter Template or Existing Project

Decision: Existing project (this repository) on Next.js App Router with OpenNext for Cloudflare.

  • Pre-configured stack: Next 14.2.16, Tailwind, ShadCN, OpenNext Cloudflare adapter, Wrangler, Vitest.
  • Structure: app/ routes, components/, lib/, sql/, etc.
  • Built-in patterns: SSR with App Router, route handlers under app/api, middleware guards, Zod validations, D1/R2 bindings.
  • Constraints: Cloudflare Workers runtime; D1 (SQLite semantics), R2 for media and ISR cache. Images unoptimized (Next images disabled by config). Change Log
Date Version Description Author
2025-09-17 1.0 Initial backend architecture document Architect

High Level Architecture

Technical Summary

United Tattoo runs as a serverless, modular monolith on Cloudflare Pages + Workers using the OpenNext adapter. Next.js App Router handles SSR/ISR and routing; Cloudflare D1 stores structured data (users, artists, appointments, settings) and R2 stores media plus incremental cache. Back-end concerns (auth, RBAC, validations, uploads, booking, payments, notifications, calendar sync) are implemented via Next.js route handlers and server actions with strict Zod validation and middleware-based RBAC. The architecture prioritizes image-forward delivery performance, reliability, and maintainability aligned to the PRD.

High Level Overview

  1. Style: Serverless modular monolith (single app, bounded modules by domain).
  2. Repo: Single repository (this project).
  3. Services: Single deployable (OpenNext worker) with internal modules (auth, artists, portfolio, booking, payments, notifications, calendar).
  4. Primary flows:
    • Public SSR pages, search/discovery (later), booking/consultation routing, client portal (later).
    • Admin onboarding, artist/portfolio CRUD, uploads to R2, moderation queue (later), activity logs (later).
    • Payments via Stripe for deposits; later add PayPal.
    • Two-way Google Calendar sync for artists (planned now).
  5. Key decisions:
    • Cloudflare-first stack (D1, R2, Pages/Workers) with OpenNext.
    • REST via route handlers + Server Actions for same-origin mutations.
    • Zod across edges; strict RBAC via middleware.
    • Sentry + OpenTelemetry for observability; Upstash Redis for rate limiting.

High Level Project Diagram

graph TD
  subgraph Users
    V[Visitor]
    C[Client]
    A[Admin/Artist]
  end

  V -->|HTTP(S)| CDN[Cloudflare CDN]
  C -->|HTTP(S)| CDN
  A -->|HTTP(S)| CDN

  CDN --> W[OpenNext Worker (Next.js App)]
  W --> D1[(Cloudflare D1)]
  W --> R2[(Cloudflare R2 - Media)]
  W --> R2INC[(R2 - ISR/Incremental Cache)]

  W --> STRIPE[Stripe API]
  W --> RESEND[Resend Email]
  W --> TWILIO[Twilio SMS]
  W --> GCAL[Google Calendar API]

  style W fill:#222,stroke:#999,color:#fff
  style D1 fill:#114,stroke:#99f,color:#fff
  style R2 fill:#141,stroke:#9f9,color:#fff
  style R2INC fill:#141,stroke:#9f9,color:#fff,stroke-dasharray: 5 5

Architectural and Design Patterns

  • Serverless Modular Monolith (chosen): Single worker with domain modules. Rationale: Simpler ops, Cloudflare-native, low latency, satisfies PRD scope; avoids premature microservices.
  • Communication: RESTful route handlers + Server Actions. Alternative: GraphQL (deferred). Rationale: Simplicity, aligns with Next App Router, easy cache/policy control.
  • Data Access: Thin repository-like helpers (lib/db.ts) with prepared SQL on D1. Alternative: Kysely/Prisma (N/A on Workers) → stay with direct SQL for D1. Rationale: Control, performance, D1 fit.
  • Validation: Zod at boundaries (API/server actions/forms). Rationale: Single schema source; consistent erroring.
  • AuthZ: Middleware-based RBAC on path prefixes + helper functions. Rationale: Centralized enforcement.
  • Caching: R2-based ISR via OpenNext override; CDN caching for assets/API where applicable. Rationale: Cost/perf balance.
  • Rate limiting: Redis (Upstash). Alternative: KV tokens. Rationale: Simplicity and global availability.

Tech Stack

Cloud Infrastructure

  • Provider: Cloudflare
  • Key Services: Pages + Workers (OpenNext), D1 (SQL), R2 (object storage + ISR cache)
  • Regions: Global edge (Cloudflare network), D1 region as configured by account

Technology Stack Table

Category Technology Version Purpose Rationale
Language TypeScript 5.x (lockfile-resolved) Primary backend language Strong typing, tooling, Next.js alignment
Framework Next.js (App Router) 14.2.16 SSR/ISR, routing, APIs, server actions Matches UI, supports OpenNext
Platform OpenNext (Cloudflare) ^1.8.2 (lockfile pin) Next->Workers build, ISR in R2 Official adapter, ISR override support
Runtime Cloudflare Workers nodejs_compat enabled Serverless execution Edge-native, low latency
Config/Deploy Wrangler ^4.37.1 (pin in lock) Build/preview/deploy worker + bindings Cloudflare-native tooling
DB Cloudflare D1 Managed Relational store for core data Simple, sufficient for scope, low-ops
Storage Cloudflare R2 Managed Media assets; ISR cache bucket Cost-effective, global access
Auth NextAuth (Auth.js) ^4.24.11 (pin in lock) JWT sessions + providers Standard pattern with Next
Validation Zod 3.25.67 Input/env validation Ubiquitous + types inference
Testing Vitest + RTL ^3.2.4 + latest RTL Unit/component testing Fast, TS-native
Observability Sentry + OpenTelemetry Latest stable Errors, traces, metrics Full visibility across Workers + Next
Rate Limiting Upstash Redis Managed Rate limit auth/forms/APIs Simplicity, global
Payments Stripe (primary); PayPal later Latest SDK Deposits, refunds Start with Stripe per customization
Email Resend Latest SDK Transactional emails Simple, modern API
SMS Twilio Latest SDK Notifications (reminders, etc.) Reliable, well-documented
Calendar Google Calendar API v3 Two-way artist sync Per customization → implement now

Note: Exact semver pins should be recorded from the lockfile in CI. Next 14.2.16 and zod 3.25.67 are exact; others are resolved via lock.

Data Models

Core entities mapped from PRD and schema:

  • User: id, email, name, role (CLIENT|ARTIST|SHOP_ADMIN|SUPER_ADMIN), avatar.
  • Artist: id, userId, name, bio, specialties[], instagramHandle, isActive, hourlyRate.
  • PortfolioImage: id, artistId, url, caption, tags[], orderIndex, isPublic, createdAt.
  • Appointment: id, artistId, clientId, title, description, startTime, endTime, status, depositAmount, totalAmount, notes.
  • Availability: id, artistId, dayOfWeek, startTime, endTime, isActive.
  • SiteSettings: id, studioName, description, address, phone, email, socialMedia{}, businessHours[], heroImage, logoUrl.
  • FileUpload: id, filename, originalName, mimeType, size, url, uploadedBy.

Relationships:

  • User 1to1/01 Artist (user_id).
  • Artist 1tomany PortfolioImage.
  • User (client) 1tomany Appointment; Artist 1tomany Appointment.
  • Artist 1tomany Availability.

Components

  • Auth & RBAC

    • Responsibility: JWT sessions; role enforcement.
    • Interfaces: /auth routes (NextAuth), middleware guards, helpers isAdmin/hasRole.
    • Dependencies: NextAuth, middleware.ts.
    • Tech: NextAuth with Credentials (dev), Google/GitHub optional.
  • Artist & Portfolio Service

    • Responsibility: CRUD artists, portfolio images, ordering, visibility.
    • Interfaces: app/api/artists/, app/api/portfolio/, server actions for admin UI.
    • Dependencies: D1 tables, R2 uploads.
    • Tech: lib/db.ts helpers; lib/r2-upload.ts.
  • Upload Service

    • Responsibility: R2 uploads (single/bulk), file validation, delete.
    • Interfaces: app/api/upload, admin UI dropzones.
    • Tech: R2 bucket binding; R2_PUBLIC_URL used to compose public URLs.
  • Booking & Scheduling

    • Responsibility: Booking/consultation routing, appointment CRUD, availability.
    • Interfaces: app/api/appointments/*; server actions for stepper.
    • Dependencies: D1, Notifications, Stripe.
    • Tech: Zod forms; quote estimation (to be implemented).
  • Payments

    • Responsibility: Deposit intents (Stripe), receipts, refunds; PayPal later.
    • Interfaces: app/api/payments/* webhooks; server actions for checkout init.
    • Dependencies: Stripe SDK, D1 to persist intents/receipts.
    • Tech: Stripe Checkout/PaymentIntents; signed webhooks; idempotency keys.
  • Notifications

    • Responsibility: Email (Resend) + SMS (Twilio), templates, preferences.
    • Interfaces: internal functions invoked from flows; background execution pattern if needed.
    • Dependencies: D1 preferences, external providers.
  • Calendar Integration

    • Responsibility: Google Calendar two-way sync for artists (now).
    • Interfaces: OAuth connect, webhook/push, polling fallback, reconciliation.
    • Dependencies: Google API, D1 for tokens, Appointments.

Component Diagram

graph LR
  AUTH[Auth & RBAC] --> API[Route Handlers / Server Actions]
  ART[Artists/Portfolio] --> API
  UP[Upload Service] --> API
  BK[Booking/Scheduling] --> API
  PAY[Payments (Stripe)] --> API
  NOTIF[Notifications] --> API
  CAL[Calendar Sync] --> API

  API --> D1[(D1)]
  API --> R2[(R2)]
  PAY --> STRIPE[Stripe]
  NOTIF --> RESEND[Resend]
  NOTIF --> TWILIO[Twilio]
  CAL --> GCAL[Google Calendar]

External APIs

  • Stripe API

    • Purpose: Deposits, refunds; store payment intents + receipts.
    • Auth: API keys (Wrangler secret); webhook signing secret.
    • Rate limits: Stripe-managed; implement retries with backoff; idempotency keys.
    • Endpoints: PaymentIntents, Checkout, Refunds, Webhooks.
  • Resend

    • Purpose: Transactional emails (booking confirmations, receipts).
    • Auth: API key (secret).
    • Integration: templated emails, error handling.
  • Twilio

    • Purpose: SMS notifications (confirmations/reminders).
    • Auth: Account SID/Token (secret).
    • Rate limits: provider-specific; implement basic backoff.
  • Google Calendar v3

    • Purpose: Two-way artist sync (now).
    • Auth: OAuth 2.0 per artist; token storage in D1; refresh handling.
    • Endpoints: Events, Watch (push), Channels (stop), CalendarList.

Core Workflows

Booking with Deposit (sequence)

sequenceDiagram
  participant U as User
  participant W as Worker(App)
  participant D as D1
  participant S as Stripe
  U->>W: Submit booking form (zod-validated)
  W->>D: Create pending Appointment (PENDING)
  W->>S: Create PaymentIntent (deposit) with idempotency
  S-->>W: Client secret
  W-->>U: Return client secret
  U->>S: Confirm payment
  S-->>W: Webhook event (payment_succeeded)
  W->>D: Update Appointment status + store receipt reference
  W-->>U: Confirmation (email/SMS)

Portfolio Upload (sequence)

sequenceDiagram
  participant A as Admin/Artist
  participant W as Worker(App)
  participant R as R2
  participant D as D1
  A->>W: Upload image(s) (validated)
  W->>R: Put object(s)
  W->>D: Insert portfolio_images rows
  W-->>A: URLs + metadata

REST API Spec (sketch)

openapi: 3.0.0 info: title: United Tattoo Backend API version: 1.0.0 description: REST endpoints backing booking, admin, and integrations servers:

  • url: https://your-preview-domain.pages.dev description: Preview
  • url: https://your-domain.com description: Production paths: /api/appointments: get: summary: List appointments post: summary: Create appointment (server action preferred) /api/portfolio: post: summary: Upload portfolio image (server action preferred) /api/payments/deposit-intent: post: summary: Create Stripe PaymentIntent for deposit /api/webhooks/stripe: post: summary: Stripe webhook receiver

Database Schema

  • Source of truth: sql/schema.sql (D1). Entities and indexes already implemented.
  • Note: Fix comment header mismatch (“united-tattoo-db” vs scripts using “united-tattoo”).
  • Migrations: wrangler d1 execute … --file=./sql/schema.sql (local/prod variants).

Source Tree

project-root/
├─ app/                       # App Router (public pages, admin area, api/)
│  ├─ api/                    # Route handlers
│  ├─ admin/                  # Admin UI sections
│  └─ ...                     # Site pages
├─ components/                # UI + composed components
├─ lib/
│  ├─ db.ts                   # D1 & R2 binding access + helpers
│  ├─ r2-upload.ts            # R2 upload manager
│  ├─ auth.ts                 # NextAuth config + RBAC helpers
│  ├─ env.ts                  # Zod env validation (see alignment note)
│  └─ validations.ts          # Zod schemas for domain + forms
├─ sql/
│  └─ schema.sql              # D1 schema SSoT
├─ wrangler.toml              # Worker config + bindings
├─ open-next.config.ts        # ISR cache override to R2
├─ next.config.mjs            # Next config (standalone, images unoptimized)
└─ package.json               # Scripts (build/preview/deploy/db/test)

Infrastructure and Deployment

Infrastructure as Code

  • Tool: Wrangler 4.x
  • Location: wrangler.toml
  • Approach: Wrangler-only “config of record” now; Terraform later if needed.

Deployment Strategy

  • Strategy: OpenNext build → Cloudflare Pages (Worker + assets).
  • CI/CD Platform: Gitea (planned) with required pipeline gates.
  • Pipeline Config: .gitea/workflows/* (to be added) or equivalent CI config.

Environments

  • dev: Local dev server (next dev) and/or Workers preview (OpenNext preview).
  • preview: Cloudflare Pages preview (pull requests).
  • production: Cloudflare Pages live.

Environment Promotion Flow

feature → PR → CF Pages preview → E2E/quality gates → merge → production deploy

Rollback Strategy

  • Primary Method: Re-deploy previous artifact via CF Pages rollback / previous commit.
  • Triggers: Elevated errors, failed SLOs, payment or booking failures.
  • RTO: < 30 minutes for deploy rollback; data roll-forward with compensating ops.

Error Handling Strategy

General Approach

  • Error Model: Domain errors (validation, auth, business) vs operational (transient, provider).
  • Propagation: Translate to typed JSON errors at API boundary; avoid leaking internals.

Logging Standards

  • Library: Console structured JSON (Workers) + Sentry/Otel exporters.
  • Format: JSON with fields: timestamp, level, correlationId, route, userId (if any).
  • Levels: debug/info/warn/error; No PII in logs.

Error Handling Patterns

  • External API Errors:
    • Retry: Exponential backoff (bounded), idempotency keys (Stripe).
    • Circuit Breaker: Soft disable non-critical providers on repeated failures.
    • Timeouts: Tight timeouts; fail fast, surface friendly errors.
  • Business Logic Errors:
    • Custom error types; map to 4xx with helpful messages; do not expose details.
  • Data Consistency:
    • D1 is transactional per statement; use idempotency on effects; write-ahead logic for webhooks.

Coding Standards (Backend)

Core Standards

  • Languages & Runtimes: TypeScript (Workers-compatible), Next.js App Router.
  • Style & Linting: ESLint + Prettier (enable in CI, even if build ignores failures).
  • Tests: Vitest for unit; RTL for component; Playwright for e2e (planned).

Critical Rules

  • Validate all external inputs with Zod at API boundary.
  • Use lib/db.ts helpers; do not inline raw env binding plucking in routes.
  • Payments: Always use idempotency keys for Stripe and verify signed webhooks.
  • No secrets in logs; use Wrangler secrets for all provider keys.
  • RBAC: All /admin and /api/admin routes must enforce SHOP_ADMIN or SUPER_ADMIN.
  • Rate limiting must wrap auth/forms/API entrypoints once Upstash is configured.

Test Strategy and Standards

Testing Philosophy

  • Approach: Pragmatic test-after with critical flows prioritized; expand coverage over time.
  • Coverage Goals: Unit 6070% rising; critical domain paths higher.

Test Types and Organization

  • Unit: Vitest; files *.test.ts under tests/ or next to modules.
  • Integration: D1 local (wrangler d1 execute) for repository tests; mock providers.
  • E2E: Playwright on CF Pages preview (booking flow, uploads, admin critical).

Test Data Management

  • Fixtures: tests/fixtures; factories for domain objects.
  • Cleanup: Explicit clean after each suite (D1 truncate helpers for local env).

Continuous Testing

  • CI Integration: Lint/typecheck → unit → build → migration dry-run → e2e on preview.

Security

Input Validation

  • Library: Zod
  • Location: Route handlers/server actions before processing
  • Required Rules:
    • Validate all inputs (query/body/params).
    • Whitelist approach; reject extras.

Authentication & Authorization

  • Auth Method: NextAuth JWT (Credentials for dev; OAuth optional).
  • Session: JWT; role included in token; maxAge defaults; future 2FA.
  • Required:
    • Enforce RBAC in middleware + route-level checks for admin endpoints.
    • Implement invites and 2FA per PRD in admin flows.

Secrets Management

  • Development: Wrangler secrets; .env only for local dev of non-secrets.
  • Production: Wrangler secrets; never commit secrets.
  • Code Rules: Never log secrets; never embed keys.

API Security

  • Rate Limiting: Upstash Redis (global) on auth/forms/APIs.
  • CORS: Strict same-origin for server actions; minimal cross-origin where necessary.
  • Security Headers: Enforce via centralized headers helper (CSP, X-Frame-Options DENY, Referrer-Policy strict-origin-when-cross-origin, Permissions-Policy).

Data Protection

  • At Rest: Provider-managed (D1/R2). Encrypt sensitive app-level data if needed before storage.
  • In Transit: HTTPS only.
  • PII: Store minimal; redact logs.

Dependency Security

  • Scanner: Enable dep audit in CI; weekly review cadence.
  • New Deps: Require review; follow Context7 MCP check (per repo rules).

Security Testing

  • SAST: ESLint/security rules; consider additional scanners.
  • DAST: E2E includes basic auth + booking hardening; expand later.

Backend Customization Choices (Confirmed)

  • Payments: Stripe first (PayPal later).
  • Email: Resend.
  • SMS: Twilio.
  • Rate Limiting: Upstash Redis.
  • Observability: Sentry + OpenTelemetry.
  • Calendar Integration: Google twoway sync now.
  • API Style: Next.js Route Handlers (REST) + Server Actions.
  • IaC/Config: Wrangler-only config of record (Terraform later).
  • Env/Secrets: Align env.ts to Cloudflare bindings (remove unused AWS_* + DATABASE_URL now). Note: the current names in env.ts are labeled AWS_ but map to Cloudflare R2 usage—document and align.
  • Security Headers: Centralized middleware/edge headers helper.

Next Steps

  • Frontend Architecture Mode: Generate a separate frontend architecture doc leveraging this backend document and PRD UI requirements (ShadCN, search/filters, parallax/split).
  • Product Owner Review: Validate scope and sequencing (Phases 14).
  • Dev Agent: Implement stories for Phase 1 (Admin invites, onboarding wizard stub, artist CRUD/portfolio upload MVP, D1/R2 confirmations).
  • DevOps: Add CI pipeline, lock exact versions from lockfile into doc, add .env.example listing required secrets (NEXTAUTH_URL, NEXTAUTH_SECRET, R2_PUBLIC_URL, STRIPE_KEYS, RESEND_API_KEY, TWILIO_KEYS, GOOGLE_OAUTH, UPSTASH).

Appendix

Bindings (wrangler.toml)

  • DB (D1), R2_BUCKET (media), NEXT_INC_CACHE_R2_BUCKET (ISR cache), WORKER_SELF_REFERENCE (service binding).

Runbooks

  • Preview: npm run pages:build && npm run preview
  • Deploy: npm run pages:build && npm run deploy
  • DB: npm run db:create; npm run db:migrate[:local]

References

  • PRD: docs/PRD.md
  • Schema: sql/schema.sql
  • Config: wrangler.toml, open-next.config.ts, next.config.mjs