# Plan: rewrite the calendar frontend in Next.js Status: agreed 2026-09-27; phases 0-8 done 2026-09-28, not yet committed or deployed. Branch: `feature/nextjs-rewrite`. Goal: replace the Angular 18 app with a Next.js app that matches `nachklang-feedback` in stack, look and auth behaviour, works properly on phones, and fixes the bugs found in the current implementation instead of porting them. --- ## 1. Decisions | # | Topic | Decision | |---|-------|----------| | Q1 | Repo | Rewrite in place in `Calendar_Frontend` on `feature/nextjs-rewrite`; the Angular tree is replaced, history keeps it. | | Q2 | Hosting | `output: "standalone"` Node app on Plesk/Passenger, same as feedback. | | Q3 | Stack | Copy feedback exactly: Next 16, React 19, Tailwind 4, shadcn `base-luma` preset `b7ClO5que`, Inter, lucide, ESLint. Port `lib/env.ts`, `lib/admin-auth.ts`, the `adminApi` request/error pattern, `proxy.ts`, and the admin layout's 401/403/unavailable handling. | | Q4 | Language | German only, no i18n. | | Q5 | API scope | Frontend-only, **except** the small API PR in §5 (Q21/Q22). Everything else goes to `docs/api-wishlist.md`. | | Q6 | Admin layout | Agenda list grouped by month; editing happens in a Sheet (bottom drawer on mobile, side panel on desktop). Month grid is a later feature. | | Q7 | Calendars | All calendars at once, colour-coded, toggled with filter chips. Filter state lives in the URL (`?cal=public,choir&range=future&q=…`). Birthdays off by default. | | Q8 | Move | No separate "Move" action: calendar is a form field; the app calls `PUT /move/:id` when it changed. | | Q9 | Landing page | Port the current page, add a "Nächste Termine" list from the anonymous public JSON, read the API URL from env. | | Q10 | Tests | Vitest for pure logic (dates/timezone, whole-day, URL normalisation, validation, filter/sort, calendar mapping). No e2e. | | Q11 | API | Read; findings in §3. | | Q12 | Form | Fields and rules in §4.3. | | Q13 | Libraries | Plain `useState` + pure `validateEvent()` + a small `useEvents` hook. No react-hook-form/zod/TanStack Query. | | Q14 | Recurrence | Not editable. Birthdays get `YEARLY` automatically (moved from `api.service.ts` into form logic), shown as a "jährlich" badge. | | Q15 | Save/delete | Sheet stays open until the API confirms; failure keeps the edits and shows the error; 401 → login. Dirty-close confirmation. Delete via AlertDialog, no undo. Quick "Veröffentlichen" on draft list items. | | Q16 | Extras | All four: duplicate, text search, mobile "+" FAB, iCal-link copy for internal calendars (via the Q22 endpoint). | | Q17 | Cutover | Verify locally on port 4200; the user switches the Plesk subdomain to a Node app and deploys. Old static build kept for ~1 week as rollback. | | Q18 | Docs | Create `docs/architecture.md`, `docs/features.md`, `docs/api-wishlist.md`, `docs/gotchas.md`; update `CLAUDE.md`; add Next `AGENTS.md` note like feedback. | | Q19 | Timezone | All form date handling explicitly in `Europe/Berlin` via `@date-fns/tz`; send UTC ISO strings. | | Q20 | Whole-day | Date-only inputs, inclusive end date; saved as start 00:00 / end 23:59 Berlin. No bulk migration of old rows. | | Q21 | Descriptions | Textarea stays; API PR adds RFC 5545 escaping + line folding to the iCal generator first. | | Q22 | Internal iCal links | New API endpoint `GET /calendar/events/subscriptions` (editors only) returning the subscribe URLs. | | Q23 | Recurring in filters | "Has a `repeatFrequency`" (not "calendar 5") means always current; sorted by next occurrence. | | Q24 | API sequencing | One API PR on its own branch, reviewed and deployed before the frontend goes live. | --- ## 2. Problems in the Angular app this rewrite fixes Found by reading the code on 2026-09-27; do not port these. - 14-column table with editing inside the rows; unusable on phones. Toolbar is four `