Rewrite the calendar frontend in Next.js
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>
This commit is contained in:
138 files changed
+15942
-24010
No files matched your search
@@ -0,0 +1,69 @@
|
||||
# Deployment and switchover
|
||||
|
||||
How the Next.js app replaces the Angular build on `calendar.nachklang.art`. **The deploy itself is
|
||||
done by a person** (never by Claude). Steps marked *unverified* could not be checked without access
|
||||
to the Plesk server.
|
||||
|
||||
## Order matters
|
||||
|
||||
1. **API first**: merge and deploy the API branch `feature/calendar-ical-escaping-subscriptions`
|
||||
(rebuild + restart; no new env vars - it uses the existing `API_BASE_URL` and
|
||||
`*_CREDENTIAL` values). The old Angular app keeps working against it; the new app's "Abonnieren"
|
||||
dialog needs it.
|
||||
2. **Then the frontend.**
|
||||
|
||||
## Build
|
||||
|
||||
Node version: `.nvmrc` says 26, copied from the API repo - *unverified* that Plesk offers it; use
|
||||
the version the API runs on.
|
||||
|
||||
```bash
|
||||
npm ci
|
||||
NEXT_PUBLIC_API_BASE_URL=https://api.nachklang.art \
|
||||
NEXT_PUBLIC_ADMIN_APP_URL=https://admin.nachklang.art \
|
||||
npm run build
|
||||
```
|
||||
|
||||
- Both values are **inlined at build time** - they must be set for `npm run build`, not just at
|
||||
runtime. (Values from the Angular `environment.prod.ts`.)
|
||||
- `npm run build` runs `postbuild`, which copies `.next/static` into `.next/standalone/.next/static`.
|
||||
Without it the standalone server serves the pages without CSS and JS.
|
||||
- The build fetches the public events from the API to prerender `/`. If it can't reach the API it
|
||||
still succeeds.
|
||||
|
||||
## Run (Plesk Node.js / Passenger)
|
||||
|
||||
- Application startup file: `.next/standalone/server.js`.
|
||||
- The server listens on `PORT` (and `HOSTNAME`). Whether Passenger sets `PORT` itself or needs it
|
||||
configured is *unverified* - check how the feedback app is set up on the same server.
|
||||
- Optional runtime env: `API_BASE_URL` (internal address for the landing page's server-side fetch).
|
||||
- The subdomain changes from serving static files to a Node.js app. *Unverified* how Plesk handles
|
||||
that switch for an existing domain (document root vs. application root).
|
||||
|
||||
Checked locally (2026-09-28): `PORT=4300 node .next/standalone/server.js` serves `/` with events,
|
||||
CSS/JS (200), the favicon, and redirects `/admin` without a cookie to `/admin/login`.
|
||||
|
||||
## Things that must already be true (unchanged from the Angular app)
|
||||
|
||||
The origin stays `https://calendar.nachklang.art`, so nothing should need changing - inferred from
|
||||
the Angular app already using the same cookie auth:
|
||||
|
||||
- the API's CORS list contains `https://calendar.nachklang.art` (verified in `app.factory.ts`);
|
||||
- the admin app's `NEXT_PUBLIC_ALLOWED_REDIRECT_ORIGINS` contains it (otherwise signing in lands on
|
||||
the admin start page instead of coming back);
|
||||
- the API's better-auth trusted origins contain it (otherwise sign-out fails).
|
||||
|
||||
## Smoke test after the switch
|
||||
|
||||
1. `/` loads styled, shows "Nächste Termine", and the Apple link opens a subscription.
|
||||
2. `/admin` while signed out → admin login → back to `/admin` after signing in.
|
||||
3. The list shows all calendars; an edit saves; "Abonnieren" lists links.
|
||||
4. An account without calendar permission sees "Kein Zugriff" (no redirect loop).
|
||||
5. "Abmelden" signs out and offers to sign in again.
|
||||
6. On a phone: list, "+" button, bottom sheet.
|
||||
7. An existing iCal subscription still updates (the feed URL is unchanged).
|
||||
|
||||
## Rollback
|
||||
|
||||
Keep the last Angular build (`dist/nachklang-calendar`) for about a week and switch the subdomain
|
||||
back to it if needed. The API change is backwards compatible with the Angular app, so it can stay.
|
||||
Reference in new issue
Block a user