fix: update CLAUDE.md
This commit is contained in:
parent
024cdad9dc
commit
ed4ce47ee4
1 changed files with 98 additions and 0 deletions
98
CLAUDE.md
Normal file
98
CLAUDE.md
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Church website for the Heilige Drei Könige Catholic parish, built on **Next.js 15 (App Router) + React 19 + Payload CMS v3 + PostgreSQL/PostGIS**. The frontend is fully server-rendered via Next; content is authored in the Payload admin and rendered from typed collection blocks. The repo is a **multi-tenant template**: one codebase serves multiple parish sites, selected at build/run time via `NEXT_PUBLIC_SITE_ID`.
|
||||||
|
|
||||||
|
## Common commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev # Next dev server (http://localhost:3000, admin at /admin)
|
||||||
|
npm run devsafe # Same but wipes .next first (use after Payload schema changes)
|
||||||
|
npm run build # Production build (output: 'standalone' for Docker)
|
||||||
|
npm start # Serve production build
|
||||||
|
npm run lint # Next/ESLint. Note: eslint.ignoreDuringBuilds is true in next.config
|
||||||
|
npm test # Vitest (run a single test: npx vitest run path/to/file.test.ts)
|
||||||
|
npm run storybook # Storybook on :6006 (see Storybook section for caveats)
|
||||||
|
|
||||||
|
# Payload
|
||||||
|
npm run payload migrate:create --name <name> # create a migration from current schema
|
||||||
|
npm run payload migrate # apply pending migrations
|
||||||
|
npm run generate:types # regenerate src/payload-types.ts
|
||||||
|
npm run payload jobs:run --cron "* * * * *" --queue default # run queued jobs locally
|
||||||
|
```
|
||||||
|
|
||||||
|
Node 22+ is required (`engines`). The `predev`/`prebuild` hooks run `scripts/copy-favicon.mjs` to copy the active site's `icon.ico` into `src/app/(home)/`.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Multi-site configuration
|
||||||
|
- `sites/<siteId>/config.ts` exports a `SiteConfig` (name, colors, fonts, contact info). Current sites: `dreikoenige`, `chemnitz`.
|
||||||
|
- `src/config/site.ts` picks one based on `NEXT_PUBLIC_SITE_ID` and exposes `siteConfig`. Unknown IDs throw at module load.
|
||||||
|
- Each site also provides its own `Logo.tsx`, `logoSvg.ts`, and `icon.ico`. When adding theming or site-specific assets, go through `siteConfig` — don't hardcode.
|
||||||
|
|
||||||
|
### Next App Router layout
|
||||||
|
`src/app/` uses two route groups:
|
||||||
|
- **`(home)`** — public site. Notably:
|
||||||
|
- `[[...slug]]/page.tsx` is the catch-all that renders any CMS `Pages` document via the shared `<Blocks>` composition.
|
||||||
|
- Dedicated routes exist for domain entities: `gemeinde/` (churches), `gruppe/` (groups), `gottesdienst/` (worship), `veranstaltungen/` (events), `blog/`, `pfarrei/` (parish), `sakramente/`, `spenden/` (donations), `suche/` (search), `gebetsanliegen-des-papstes/` (pope's prayer intentions).
|
||||||
|
- `api/draft/` enables Payload draft mode for live preview.
|
||||||
|
- **`(payload)`** — Payload admin (`/admin`) and Payload's own API routes. Don't edit files under this group by hand; they're scaffolded by `@payloadcms/next`.
|
||||||
|
|
||||||
|
### Payload as the content layer
|
||||||
|
`src/payload.config.ts` is the single source of truth. Collections, globals, the Lexical editor config, the jobs queue, and plugins (GCS storage, search) all live there.
|
||||||
|
|
||||||
|
- **Collections** (`src/collections/*.ts`): `Parish`, `Churches`, `Worship`, `Events`, `Blog`, `Groups`, `Pages`, `Announcements`, `LiturgicalCalendar`, `PopesPrayerIntentions`, `Classifieds`, `ContactPerson`, `Locations`, `DonationForms`, `Prayers`, `Magazine`, `Highlight`, `Documents`, `Media`, `Users`.
|
||||||
|
- **Globals** (`src/globals/`): `Menu`, `Footer`, plus a `ValidateHref` helper.
|
||||||
|
- **Blocks** (`src/collections/blocks/*.ts`): reusable Lexical-adjacent block schemas referenced by `Pages.content`, `Blog.content`, etc. Each block has a matching renderer branch in `src/compositions/Blocks/Blocks.tsx` — **adding a new block means updating both the schema and `Blocks.tsx`**.
|
||||||
|
- **Types**: `src/payload-types.ts` is generated — never edit by hand. Run `npm run generate:types` after schema changes. The TS path alias `@payload-config` resolves to the config file and `@/*` resolves to `src/*`.
|
||||||
|
- **DB**: Postgres adapter with `idType: 'uuid'` and `push: false` (migrations only, no dev-time schema push). PostGIS extension is required because `Locations` uses geo fields.
|
||||||
|
- **GraphQL is disabled**. Use the REST/local API.
|
||||||
|
- **Admin UI**: German only (`@payloadcms/translations/languages/de`); logo comes from the active site's `Logo.tsx` via `serverProps`.
|
||||||
|
|
||||||
|
### Data fetching pattern
|
||||||
|
Server components read via helpers in `src/fetch/` (e.g. `fetchPageBySlug`, `fetchBlogBySlug`, `fetchChurchBySlug`) rather than calling Payload directly from page files. These helpers accept a `draft` flag so draft mode works end-to-end. Authenticated previews use `isAuthenticated()` from `src/utils/auth.ts` plus the `<RefreshRouteOnSave>` client component.
|
||||||
|
|
||||||
|
### Rendering structure
|
||||||
|
- **`src/components/<Name>/`** — leaf/primitive UI (`Button`, `Title`, `Container`, …). Each folder usually contains the `.tsx`, a `styles.module.scss`, and a `.stories.tsx`.
|
||||||
|
- **`src/compositions/<Name>/`** — larger assemblies that combine components and sometimes fetch data (e.g. `Blocks`, `PageHeader`, `Footer`, `ContactSection`).
|
||||||
|
- **`src/pageComponents/<Entity>/`** — page-level components for specific routes (`Home`, `Parish`, `Event`, `Worship`, `Search`).
|
||||||
|
- **`src/utils/dto/`** — DTO mappers that normalize Payload shapes (e.g. `transformGallery`, `getPhoto`) before passing data into presentation components. When a block renderer needs data, prefer an existing DTO helper over inlining the reshape.
|
||||||
|
|
||||||
|
### Recurring masses / jobs queue
|
||||||
|
See the README for the full walkthrough. Key points for code changes:
|
||||||
|
- The task is `src/jobs/generateRecurringMasses.ts`; it's registered in `payload.config.ts` under `jobs.tasks`.
|
||||||
|
- `autoRun` only fires when `NODE_ENV === 'production'` (via `shouldAutoRun`). In dev, either trigger via the admin "Run now" button or the `npm run payload jobs:run` CLI command.
|
||||||
|
- Churches' `afterChange` hook queues a regeneration whenever the `recurringSchedule` field changes. The task only appends future occurrences — it will not overwrite existing `Worship` docs.
|
||||||
|
- `Worship` docs produced by the task are indistinguishable from hand-created ones; editors can still cancel/modify individual occurrences.
|
||||||
|
|
||||||
|
### Search
|
||||||
|
The `@payloadcms/plugin-search` plugin indexes `parish`, `pages`, `blog`, `event`, `group`. Two non-default tweaks in `payload.config.ts` worth knowing about:
|
||||||
|
1. `beforeSync` maps `originalDoc.name` → `searchDoc.title` because `Parish` and `Groups` don't have a `title` field.
|
||||||
|
2. `searchOverrides.fields` lifts the `doc.value` relationship's `maxDepth` to 1 so the results page (`/suche`) can read each referenced doc's `slug` to build URLs.
|
||||||
|
|
||||||
|
### Storage (GCS)
|
||||||
|
The `gcsStorage` plugin is registered unconditionally but `enabled: !!process.env.GOOGLE_BUCKET`. `alwaysInsertFields: true` keeps the collection schema (and therefore `payload-types.ts` / `importMap.js`) identical whether or not GCS is active — so you don't get spurious diffs switching between local-only dev and cloud dev. Public URLs are built manually via `generateFileURL` (`https://storage.googleapis.com/<bucket>/<prefix>/<filename>`).
|
||||||
|
|
||||||
|
### Styling
|
||||||
|
- SCSS Modules (`*.module.scss`) colocated with components.
|
||||||
|
- Root-level `_template.scss` and CSS variables from `siteConfig` drive theming.
|
||||||
|
- `next.config.mjs` pins `images.remotePatterns` to `storage.googleapis.com/<GOOGLE_BUCKET>/**`; local uploads are served from Next's default route.
|
||||||
|
|
||||||
|
### Storybook
|
||||||
|
`.storybook/main.ts` contains a custom **`mockServerModules` Vite plugin** that stubs out `payload` and every `@payloadcms/*` import with a Proxy-based no-op module. This is intentional — components that incidentally import Payload utilities won't blow up the browser build. If you add a component that genuinely needs server-only behavior in a story, refactor the story to pass data as props rather than trying to unmock.
|
||||||
|
|
||||||
|
### Migrations
|
||||||
|
Payload migrations live in `src/migrations/`. Every schema change should produce a new `<timestamp>_<name>.ts` + `.json` pair via `npm run payload migrate:create`. Production deploys must run `npm run payload migrate` against the prod DB (not yet wired into CD — see README todo).
|
||||||
|
|
||||||
|
## Path aliases
|
||||||
|
- `@/*` → `src/*`
|
||||||
|
- `@payload-config` → `src/payload.config.ts`
|
||||||
|
|
||||||
|
## Things to avoid
|
||||||
|
- Don't edit `src/payload-types.ts` — regenerate it.
|
||||||
|
- Don't edit files under `src/app/(payload)/admin/` or `src/app/(payload)/api/` — they're Payload-owned.
|
||||||
|
- Don't add a new block schema without also adding its renderer branch in `src/compositions/Blocks/Blocks.tsx` — the Pages route will silently drop unknown block types.
|
||||||
|
- Don't rely on `push: true` dev-mode schema sync; this project uses migrations exclusively.
|
||||||
Loading…
Reference in a new issue