Skip to content

Architecture

Stack

Layer Technology
Framework Next.js 15 App Router
CMS Payload CMS v3 (embedded in Next.js)
Database Neon Postgres (via @payloadcms/db-postgres)
File storage Vercel Blob (audio, saint images)
Styling Tailwind CSS v4
PWA @ducanh2912/next-pwa — service worker + Web Push
Hosting Vercel (single deployment, app + admin + API)

Payload runs inside the Next.js process — there is no separate CMS server. The admin panel is served at /admin by Payload's Next.js plugin (@payloadcms/next).

Auth model

No login. Every godchild has a private URL:

/[slug]/[token]
  • slug — godchild's name slug, e.g. marie
  • token — 24-char hex token, generated once by Payload's beforeChange hook via crypto.randomBytes(12).toString('hex')

Two-layer validation:

  1. Edge middleware (middleware.ts) — fast format check: token must be ≥ 16 chars. Rejects garbage URLs with a 404 before hitting Node.
  2. Layout (app/[slug]/[token]/layout.tsx) — full DB lookup via lib/auth.ts → resolveGodchild(). Invalid slug/token → 404. Also checks active: true.

Middleware runs on the edge runtime; Payload's local API needs Node, so the real DB check cannot happen there.

URL structure

/[slug]/[token]              Dashboard
/[slug]/[token]/chapelet     Rosary (mystery picker)
/[slug]/[token]/chapelet/[mystery]  Mystery detail
/[slug]/[token]/prieres      Prayer library
/[slug]/[token]/saint        Patron saint
/[slug]/[token]/briques      All briques archive
/admin                       Payload admin panel
/api/push/subscribe          POST — save push subscription

Key files

middleware.ts               Edge format guard
lib/auth.ts                 resolveGodchild() — DB token lookup
lib/mystery-of-day.ts       Returns today's mystery type from weekday
lib/push.ts                 Web Push subscription helpers
payload.config.ts           Payload configuration (collections, DB, secret)
payload-types.ts            Auto-generated TypeScript types (do not edit)
collections/                One file per Payload collection
components/                 UI components (BriqueCard, MysteryAccordion, etc.)
app/[slug]/[token]/         Godchild-facing routes
app/(payload)/              Payload admin (auto-managed by @payloadcms/next)

PWA

The service worker is generated by @ducanh2912/next-pwa at build time. Web Push requires VAPID keys (see Getting started). Push subscriptions are stored in the Godchildren collection (push_subscription field).

iOS requires the app to be installed via "Add to Home Screen" before push works (iOS 16.4+).