astro-app (the Astro frontend) and studio (Sanity Studio). Shared tooling — Playwright, semantic-release, GitHub Actions — lives at the repo root.
Full directory tree
Key directories
astro-app/src/components/blocks/custom/
23 CMS-connected custom blocks. Each is an
.astro file that imports from ui/ primitives and receives flat spread props matching the Sanity block schema. Auto-discovered by block-registry.ts — no manual registration.astro-app/src/components/ui/
fulldev/ui primitives installed via the shadcn CLI (
npx shadcn@latest add @fulldev/{name}). These are owned copies — not installed as npm dependencies — so they can be modified freely.studio/src/schemaTypes/
All Sanity schemas. Documents define top-level content types. Blocks define page builder sections. Objects are shared field groups. The
defineBlock helper merges block-base fields (spacing, background, maxWidth) into every block automatically.astro-app/src/lib/sanity.ts
Single source of truth for all GROQ queries. Uses
defineQuery() for type safety. Contains the Sanity client config and block resolver functions that hydrate display-mode blocks (e.g., resolveBlockSponsors()).astro-app/src/pages/portal/
All pages here export
export const prerender = false. The Cloudflare Worker runs auth middleware before each handler. Astro.locals.user carries the validated session.tests/
Playwright config at repo root runs E2E tests across 5 browser/device projects (Chromium, Firefox, WebKit, Pixel 7, iPhone 14). Integration tests validate schema correctness without a browser.
Key files
| File | Purpose |
|---|---|
astro-app/src/components/block-registry.ts | Uses import.meta.glob() to auto-discover every .astro file in blocks/ and blocks/custom/. Maps filename (camelCased) to component. No manual registration needed. |
astro-app/src/components/BlockRenderer.astro | Accepts a block prop, looks it up in the registry, and renders <Component {...block} />. Single dispatch for all 130+ block types. |
astro-app/src/components/BlockWrapper.astro | Wraps every block in a <section> with backgroundVariant, spacing, and maxWidth classes from block-base fields. |
astro-app/src/lib/sanity.ts | Sanity client (CDN vs live), all defineQuery() GROQ queries, and block resolver functions. |
studio/src/schemaTypes/helpers/defineBlock.ts | Merges shared block-base fields into every block schema. Keeps block definitions DRY. |
astro-app/astro.config.mjs | Sets output: 'static', registers @astrojs/cloudflare, @sanity/astro, @tailwindcss/vite, and @astrojs/react. Reads multi-site env vars. |
.releaserc.json | semantic-release config: conventional commits → version bump → CHANGELOG → GitHub Release → preview sync → Discord. |
playwright.config.ts | Defines 5 browser projects, axe-core a11y plugin, and base URL for E2E tests. |