Replaces the Angular 18 app with Next.js 16 / React 19 / Tailwind 4 / shadcn, the same stack and design system as nachklang-feedback, planned in docs/rewrite-plan.md. - Admin: all calendars in one mobile-friendly list (month groups, calendar chips, Kommend/Vergangen/Alle, search, sort, filters in the URL), an edit sheet for create/edit/duplicate/delete, publish confirmation, and an "Abonnieren" dialog with subscription links for every calendar. - Public landing page: subscribe links from env instead of hardcoded, plus the next public events, server-rendered and revalidated every 5 minutes. - All times handled explicitly as Europe/Berlin; whole-day events stored as 00:00-23:59. Fixes carried over from the Angular app: the move dialog leaking a cancelled calendar change, saves that looked saved when they failed, in-place Date mutation, and duplicated calendar-id mappings. - Same shared-session auth as before (proxy.ts gate, /admin/me, 401 vs 403). - 112 Vitest tests over lib/; docs in docs/ (architecture, features, gotchas, API wish list, deployment). Needs the API branch feature/calendar-ical-escaping-subscriptions deployed first (GET /calendar/events/subscriptions). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2.5 KiB
2.5 KiB
Features
What the calendar app does, as of the Next.js rewrite (September 2026).
Public page (/)
- Subscribe to the public calendar: Apple Kalender (
webcal://), Google Kalender (deep link), or copy the iCal URL (shows the URL if the clipboard isn't available). - "Nächste Termine": the next four public events with date, time and place; an event with a web link opens it. Refreshed every five minutes; hidden if the API can't be reached.
- Link to the Verwaltung (
/admin).
Verwaltung (/admin)
Sign-in happens in the admin app (one account for all Nachklang apps). Accounts need the calendar permission; without it the page says so instead of redirecting.
List
- All calendars in one list, grouped by month, colour-coded per calendar.
- Calendar chips toggle calendars on and off, with a count each; Geburtstage is off by default.
- Kommend / Vergangen / Alle. "Vergangen" shows the newest first; "Alle" scrolls to a "Heute" marker.
- Search over title and location.
- Sort by start or by creation date (the latter as a flat list).
- The view is in the URL, so a link reproduces it.
- Drafts show an "Entwurf" badge and a "Veröffentlichen" button, which asks for confirmation and says who will see the event.
- Repeating events (birthdays) show a "jährlich" badge and appear at their next occurrence.
- Failed calendars are marked on their chip with a retry banner; the rest of the list stays usable.
Edit sheet (bottom sheet on phones, side panel on larger screens)
- Create ("Neuer Termin" in the header, "+" button on phones), edit, duplicate, delete.
- Fields: Kalender, Titel, Ganztägig, Beginn, Ende, Ort, Link, Beschreibung (multi-line), Status (Entwurf / Veröffentlicht; "Privat" is kept but not selectable).
- Moving the start moves the end with it. Whole-day events take dates only.
- A link without
https://is completed; anything that isn't a web address is flagged. - Moving an event into Geburtstage makes it yearly; moving it out removes that again.
- Errors appear next to their field; a failed save keeps the edits and says why.
- Closing with unsaved changes asks first; so does leaving the page.
- Shows who created and last changed the event.
Abonnieren (header)
- Subscription links for every calendar, including the internal ones with their password: Apple, Google, or copy. Chor and Geburtstage share a password.
Not (yet) possible
- Restoring deleted events and editing recurrence need API work first - see api-wishlist.md.
- A month-grid view was deferred (decision Q6); the agenda list came first.