# 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.