Files
Calendar_Frontend/CLAUDE.md
Paddy 5d7221b87b Delete the dead Session model
Nothing has referenced it since the auth cutover: the session is an httpOnly
cookie this app can neither read nor construct, so there is no session type
for it to hold.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 22:28:56 +02:00

4.0 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Commands

npm start          # Dev server at http://localhost:4200/ (live reload)
npm run build      # Production build
npm run watch      # Build with watch mode (development config)
npm test           # Run unit tests (Jasmine/Karma in Chrome)

No linter is configured in this project.

Architecture

Angular 18 single-page app for managing calendar events for the "Nachklang" organization. Uses Angular Material for UI, RxJS for async data, and reactive forms. No NgRx — state lives in component local variables.

Environments (src/environments/): apiUrl and adminAppUrl.

  • Dev: http://localhost:3000 (expects backend running locally) / http://localhost:3002
  • Prod: https://api.nachklang.art / https://admin.nachklang.art

Authentication

This app has no login form and no accounts of its own. Since the auth cutover (docs/calendar-auth-migration.md in the API repo) it shares one identity with the tickets, feedback and admin apps: accounts live in the admin app, and the session is an httpOnly cookie on .nachklang.art that the API's host sets. Consequences that cannot be designed around:

  • withCredentials: true is mandatory on every call (api.service.ts sets it once). Without it the browser sends no cookie and the API answers 401.
  • This app can never read or verify the session. It calls GET /admin/me and believes the answer; the API's requireAppAccess('calendar') is the actual gate.
  • 401 and 403 mean different things and must not be collapsed. 401 means "nobody is signed in" and is the only one worth redirecting to the login page - redirecting on 403 produces a loop where signing in succeeds and lands straight back on the refusal. See failure in admin.component.ts.
  • Sign-out ends the session for all four apps; there is only one.

The dev server must be reachable at a port the API trusts. ng serve defaults to 4200, which is in better-auth's dev localhostOrigins and in the admin app's NEXT_PUBLIC_ALLOWED_REDIRECT_ORIGINS; another port fails sign-out and the return redirect, not the sign-in.

The public calendar stays anonymous. GET /calendar/events/public/json needs no session at all, because nachklang.art reads it to show the next upcoming event.

Routing (app.routing.ts):

  • /LandingpageComponent
  • /adminAdminComponent (main calendar management page)
  • **NotfoundComponent

Service layer (src/app/services/):

  • api.service.ts — all HTTP calls to the backend REST API; carries the session cookie via withCredentials, holds no credential itself
  • admin-auth.service.ts — where signing in happens: the admin app's login URL (with a ?redirect= back here) and sign-out
  • utils.service.ts — caches the signed-in user's display name for unsaved draft rows. Cosmetic only; the server takes the author from the session

Data models (src/app/models/): Event, User, Session

Admin page (src/app/pages/admin/) is the core of the app. It owns events state and passes it down to EventsTableComponent via @Input(). Key features: multi-calendar support (public, members, choir, management, birthdays), event filtering (future/past/all), sorting, and an event-move dialog (EventMovePopupComponent via Angular Material Dialog).

Calendar-specific behavior: Birthday calendar auto-sets recurrence to YEARLY. Events have a status field (DRAFT / DELETED).

Session lifecycle: AdminComponent calls me() on init. 401 redirects to the admin app's login carrying this URL as the return target; 403 (or a signed-in account without the calendar permission) shows a refusal with Reload/Sign out; anything else shows "cannot be reached". None of those three redirect, on purpose.

Dead since the cutover: the unrouted LoginComponent. src/app/models/session.ts is gone; there is no session type here any more, because this app never handles one.