Files
projax/docs/plans/mgmt-teardown.md
mAi dc4863faca chore(mgmt teardown step 5+6): drop stale dokploy comment + append DONE log
Per docs/plans/mgmt-teardown.md §4 steps 5 + 6.

Step 5: deploy/dokploy.yaml — stale "federated with mgmt.msbls.de" line
in the header comment replaced with the current host-scoped /login cookie
model. The mgmt federation never happened in projax anyway (projax
cookies are host-scoped, no Domain attribute).

Step 6: append a "DONE 2026-05-16" section to docs/plans/mgmt-teardown.md
recording every step's commit hash across both repos, the head-approved
deviation from §4 step 1 (SvelteKit-side redirect instead of Dokploy
Traefik labels — Dokploy config is UI-only), verification curls, and the
post-teardown janitorial that's out of scope for the worker (env-var
cleanup in Dokploy, DNS at m's leisure).

m/msbls.de side merged separately (86bfa61) — three commits:
2941dc4 (redirect), <previous step's commit covers the rest>.
2026-05-16 01:06:28 +02:00

20 KiB
Raw Blame History

mgmt.msbls.de teardown — plan

Worker: knuth (research shift) · Date: 2026-05-15 Status: PLAN — pending m's read + go/no-go. No code touched in this shift. Source: live audit of ~/dev/web/msbls.de (gitea m/msbls.de) on the date above. Cross-repo grep across ~/dev/ for hardcoded /mgmt/ URLs.

TL;DR

mgmt.msbls.de is a thin SvelteKit cockpit with three live routes plus an auth shell. Two of them (/mgmt/login, the auth + cookie infra) projax already does at parity. The third (/mgmt, the Work-Cockpit) composes data projax does NOT yet expose — CalDAV Work + Plan calendars, mWorkRepo PARA folders, mBrian [topic] + [workday] nodes — but only the CalDAV slice is shipped on mgmt today; mWorkRepo and mBrian slices are stubbed placeholders per Slice 45 of msbls.de/docs/plans/mgmt-self.md.

Teardown is two-thirds achievable today — projax already provides the auth surface and a dashboard with VTODO + Gitea aggregation. The remaining third (the Work-Cockpit-specific composition: Work + Plan calendar focus, mWorkRepo PARA cards, HL topic threads) is either out-of-scope-for-projax (mWorkRepo is HL-internal content, not project-management data) or a small feature gap (CalDAV calendar-set filtering already exists on projax via caldav-list item_links, just needs m to link Work + Plan to a projax item).

Cross-repo dependency check: a single grep across ~/dev/ finds the string mgmt.msbls.de in only mgmt's own source and one stale comment in projax/deploy/dokploy.yaml. No other repo links to mgmt routes. No cron jobs or external systems hit the mgmt API surface (mgmt has no /api/* routes — the cockpit is server-load only).


§1 What mgmt.msbls.de actually does today

Routing model

mgmt is mounted via host-routing, not a plain subpath:

  • mgmt.msbls.de (the host) is recognised by src/lib/host-routing.ts.
  • src/hooks.ts reroute maps incoming mgmt.msbls.de/… URLs onto /mgmt/… so file-based routing works.
  • src/hooks.server.ts enforces existence-leak: any /mgmt/* URL arriving on a non-cockpit host (www.msbls.de, apex) returns plain Not Found before the route loads. So www.msbls.de/mgmt/self and mgmt.msbls.de/self both work, but only on the right host.
  • Compat: a legacy Traefik AddPrefix middleware is still expected — mapToCockpitRoute is idempotent against it so the deploy can move off Traefik prepending without code change.

Routes (the complete list)

Path File What it does Who calls it
/mgmt (root) mgmt/+page.server.ts + mgmt/+page.svelte The Work-Cockpit: tabs (today / week / quarter), Operational Stream (open VTODOs + VEVENTs from Work+Plan CalDAV calendars), Strategic Threads (three placeholder stub cards for mWorkRepo + mBrian content not yet wired). All UI in German. m, in a browser, after auth
/mgmt/login mgmt/login/+page.server.ts + mgmt/login/+page.svelte Email + password against Supabase Auth; sets access_token + refresh_token cookies scoped to .msbls.de so sessions survive subdomain crossing. m, browser
/mgmt/self mgmt/self/+page.server.ts Stub redirect to /. Pre-refactor the cockpit lived at /mgmt/self; redirect keeps old bookmarks working. legacy browser history
/mgmt/* (any other) mgmt/+layout.server.ts Auth guard. Unauth + safe-method → 404 (no existence leak). Unauth + unsafe-method → 302 to /login. every authenticated path

Auth shell (server-side bits)

  • hooks.server.ts — runs on every request, calls authenticateRequest(), populates locals.userId, persists refreshed tokens as cookies.
  • lib/server/auth.tsauthenticateRequest() validates JWT cookie or Authorization: Bearer, falls back to refresh_token. ~100 lines. Cookies scoped to msbls.de (override via COOKIE_DOMAIN). Used by the layout guard.
  • lib/server/supabase.tsgetSupabaseAdmin() + getSupabaseAnon(). Same Supabase project as mBrian.
  • lib/server/caldav.ts — REPORT-based VTODO + VEVENT reader against dav.msbls.de. Hand-rolled iCal parsing. Cache TTL 60s.
  • lib/server/mbrian.tsmb() schema helper, setDbClient(getSupabaseAdmin()) on init. Not yet consumed by any route (Slice 5 work).

Feature flags / env conditions

  • COOKIE_DOMAIN env: shared cross-subdomain by default (msbls.de); override to none for localhost.
  • CALDAV_BASE/USER/PASS — required by the calendar reader. Absent → calendar fetches throw CalDAVError and the page renders per-calendar error chips (settled-promise pattern).
  • GITEA_TOKEN — referenced in the design for Slice 4 (mWorkRepo runtime API) but not yet used in shipped code.
  • No webhook receivers, no /api/* routes, no cron, no background jobs. The site is request-response only.

Out-of-scope context

docs/plans/mgmt-self.md (in msbls.de) is the original design doc. It lists 6 slices; only Slice 13 (today + week views with CalDAV data) and the auth shell appear shipped. Slices 46 (mWorkRepo cards, mBrian topic cards, quarter view, markdown rendering) are placeholders. The design treats the cockpit as a read-only desktop pull surface with Obsidian / CalDAV / mBrian remaining the authoring source-of-truth.


§2 Mapping mgmt → projax

mgmt feature projax equivalent gap / notes
/mgmt/login (Supabase email+password) /login on projax (Supabase email+password) parity ✓ — same Supabase project, same access_token/refresh_token cookie pair. Cookie scope differs: mgmt uses Domain=.msbls.de for cross-subdomain SSO; projax uses host-scoped (no Domain attribute). Decision needed: do we want projax to inherit cross-subdomain cookies so a session on mgmt carries to projax? See §6 risk.
/mgmt/+layout.server.ts (404-on-anon auth guard) web/auth.go authMiddleware (302-to-login auth guard) near-parity — projax is more permissive (302 instead of 404 for anon) which leaks the existence of authenticated paths but matches the "behind Tailscale anyway" risk model. Could tighten if m wants.
lib/server/caldav.ts (REPORT VTODO + VEVENT against dav.msbls.de) caldav/caldav.go (REPORT VTODO + VEVENT + writeback) projax is more capable — adds VTODO PUT, DELETE, ETag-aware writeback (Phase 2.b). The reader surface overlaps.
/mgmt Operational Stream (VTODOs today + VEVENTs today, deduped from Work+Plan) /dashboard Tasks card (VTODOs from every linked CalDAV list, bucketed Overdue/Today/Tomorrow/Week/NoDue) functional parity for tasks; gap for VEVENTs. projax's dashboard aggregates every caldav-list-linked calendar, not just Work+Plan. To restrict to those two, m links only those calendars to a "work" projax item — already supported via /admin/caldav. VEVENTs (meetings/calls) are NOT yet on projax's dashboard — see §3 Gap 1.
/mgmt Operational Stream ([workday] event-children from mBrian deduped against VEVENTs) none gap, but probably non-blocker[workday] is mBrian-internal content. projax never planned to consume mBrian; per the original PRD "mBrian topic-hub linkage" is deferred to Phase 3 and exists today only as a mention. Recommend: leave on mgmt's design backlog, do not port to projax.
/mgmt Strategic Threads — mWorkRepo 2 - projects/ + 3 - areas/ cards none gap, parked, probably stays parked — mWorkRepo is HL-internal Obsidian content. projax exists for project-management data backbone, not for being a markdown viewer. Recommend: park the Strategic Threads tab on mgmt indefinitely (it's only stubs anyway), or, if m really wants a unified surface, render mWorkRepo cards via projax's gitea-repo item_link surface (would need a Gitea-content reader, see §3 Gap 2).
/mgmt Strategic Threads — mBrian [topic] cards none gap, same recommendation as above — mBrian topic-hub linkage is a future projax-Phase concern, not a teardown blocker.
/mgmt view toggle (today / week / quarter) /dashboard cards are today-focused with relative bucketing (Overdue / Today / Tomorrow / This week / No due) near-parity for today + week, gap for quarter view. Quarter is a Slice-6 placeholder on mgmt anyway — empty in production. Not a teardown blocker.
/mgmt/self legacy redirect → /mgmt n/a drop on teardown — once mgmt is gone, the redirect is irrelevant.
Cross-subdomain auth (cookies on Domain=.msbls.de) projax cookies are host-scoped gap if we want session continuity from www → projax. See §6. Probably YAGNI — projax has its own /login and m typically signs in once per device.

§3 Gaps that block teardown

In rough order of cost. Anything not listed is either already on projax or is a deliberate "stays parked" item.

Gap 1 — VEVENTs (meetings/calls) on projax dashboard

What's missing: the dashboard Tasks card shows VTODOs only. The mgmt cockpit also surfaces VEVENTs from Work+Plan ordered by start-time, with location + categories. So "meetings today" is a real mgmt feature projax does not replicate.

Scope: small. The CalDAV client already lists VEVENTs (via caldav.ListVEVENTs); the dashboard handler would need a fourth card or a merged "Today's schedule" tab combining VTODOs + VEVENTs. Sort by due/start-time.

Suggested phase: 3l (small follow-on).

Gap 2 — mWorkRepo content cards (if m wants them on projax)

What's missing: mWorkRepo 2 - projects/ + 3 - areas/ rendered as cards with title + last-modified. This is a Slice-4 design goal on mgmt that never shipped — even mgmt only shows placeholder stubs today.

Scope: medium. Would need a Gitea-content reader (GET /repos/.../contents/<path>?ref=main) plus a new dashboard card. Cache TTL like the issues card. Could surface as a "linked-repo files" disclosure inside the existing Issues card rather than a separate card.

Suggested phase: 3m or later (low priority; current value is "zero" because mgmt never shipped this either).

Gap 3 — mBrian [topic] cards

What's missing: HL topic cards (paliad, schadensberechnung) summarising recent linked events.

Scope: medium-large — first need mBrian access from projax (the PRD parked this to Phase 3). Then per-topic recent-events rollup.

Suggested phase: out-of-scope for teardown. mgmt never shipped this either. If m wants topic surfacing, it's a future Otto-PWA / mBrian project, not projax.

Gap 4 — Cross-subdomain SSO between www.msbls.de and projax (optional)

What's missing: projax cookies are host-scoped. A session on www.msbls.de/login does not carry to projax.msbls.de.

Scope: small (one-line cookie-domain change) but probably YAGNI — m signs in to projax once per device, the session lives a year, this is a non-issue in practice.

Suggested phase: skip unless m specifically asks.


§4 Migration sequence

Order matters: don't remove anything until projax covers the equivalent + browser history can route around it.

  1. (Optional, only if m wants meetings on the dashboard) Build Gap 1 — add VEVENTs to projax's /dashboard. One slice, on a fresh branch. Ship + verify.
  2. Confirm projax is the daily-driver. m uses /dashboard for ~1 week, sees that everything he was checking on mgmt is now there (modulo §3 gaps he's chosen to drop).
  3. Set up Traefik / Dokploy redirects on mgmt.msbls.de pointing to projax equivalents:
    • mgmt.msbls.de/projax.msbls.de/dashboard (HTTP 301)
    • mgmt.msbls.de/loginprojax.msbls.de/login
    • mgmt.msbls.de/selfprojax.msbls.de/dashboard
    • any other /mgmt/*projax.msbls.de/dashboard (catch-all)
  4. Verify external dependencies = zero (already done in this audit — see §6). Wait one week with redirects live so any stragglers in browser history surface.
  5. Remove src/routes/mgmt/** from m/msbls.de in a PR. Drop src/hooks.ts reroute hook, drop the cockpit-host branches in src/hooks.server.ts, drop src/lib/host-routing.ts + its tests. mgmt is now gone from the codebase.
  6. Drop unused auth code IF mgmt was the only consumer:
    • msbls.de's src/lib/server/auth.ts, supabase.ts, caldav.ts, mbrian.ts were added specifically for the cockpit. Remove them.
    • Keep hooks.server.ts only if any other route needs auth (today: none — strip the file entirely or reduce it to a no-op pass-through).
    • Drop env vars from Dokploy: SUPABASE_*, CALDAV_*, COOKIE_DOMAIN, GITEA_TOKEN (msbls.de side — projax keeps its own).
  7. Update m/msbls.de homepage (if it currently advertises mgmt — it doesn't, just checking).
  8. Decommission the mgmt.msbls.de Traefik label / DNS entry on Dokploy. Optional final step — leaving the redirect live forever is also fine.

§5 What stays in m/msbls.de

The public face of msbls.de:

  • / — services + slop CTA homepage (+page.svelte at root)
  • /impressum — required legal
  • /slop — slop CTA landing
  • /[code] — Shlink-style short-URL fallback (+server.ts)
  • The whole src/lib/components/ set + styles (Hero, CardGrid, etc.)

What can go: every src/routes/mgmt/ file, every src/lib/server/ file (only used by mgmt), the cockpit-aware reroute hook, src/lib/host-routing.{ts,test.ts} if no other host-routing is needed. The Dockerfile's mBrian submodule clone step is mgmt-only and can be removed.


§6 Risks

Bookmark / history breakage — LOW

  • Redirects in §4 step 3 cover the common URLs. Worst case: m has a bookmark to a deep /mgmt/self?v=quarter-style URL and hits the catch-all redirect to /dashboard. Acceptable.

Other repos linking to /mgmt/* — VERIFIED ZERO

  • Grep across ~/dev/ for the strings mgmt.msbls.de, /mgmt/self, /mgmt/login found:
    • m/msbls.de itself (expected — the routes + their tests).
    • projax/deploy/dokploy.yaml — one stale comment about "federated with mgmt.msbls.de" cookies. Not a runtime dependency; safe to update at teardown time or leave as historical breadcrumb.
  • No other repo references mgmt. No cross-repo runtime coupling exists.

External systems hitting mgmt API — NONE

  • mgmt has no /api/* routes. No webhook receivers, no cron entry points, nothing external can hit it. Pure browser-only surface.
  • mgmt's cookies are Domain=.msbls.de. After teardown, the only cookies on *.msbls.de will be projax's (host-scoped) and whatever flexsiebels uses (different domain). The cross-subdomain Domain=.msbls.de cookie pair becomes effectively orphaned — browsers will keep them until expiry but no server reads them. Optional cleanup: set them to Max-Age=0 on first projax response. Not worth the code.

Loss of the Work-Cockpit Slice 45 design — INTENTIONAL

  • The mWorkRepo + mBrian topic surfacing was the design's strategic value-add. It never shipped. By tearing down mgmt we explicitly accept that this surface won't be built on msbls.de. If m later wants it, it lives more naturally on projax (with a Gitea-content reader) or on a future Otto-PWA consumer.

Single-user assumption — UNCHANGED

  • mgmt assumed single-user owner-mode. projax has the same assumption. Teardown does not introduce new multi-user surface area.

Summary numbers (for the report)

  • mgmt features audited: 4 routes + auth shell + 4 server libs (caldav, supabase, mbrian, auth).
  • Already covered by projax: 3 — login, auth guard, CalDAV VTODO reading.
  • Gaps blocking teardown: 1 small (VEVENTs on dashboard) + 0 mandatory. Two further "gaps" (mWorkRepo cards, mBrian topic cards) are park-forever recommendations — mgmt never shipped them either.

Recommendation: Ship Gap 1 (small) → wait one week → set up redirects → wait one week → remove mgmt. Two phases of projax work + two waiting weeks = ~14 days end to end. Could be compressed to ~3 days if m skips the waiting weeks; risk is bookmark breakage in his own browser history, which he can self-mitigate.


DONE 2026-05-16

Executed in a single compressed run after Phase 3l shipped Gap 1 (VEVENTs on /dashboard). m approved the path A timeline; teardown landed the same session.

Phase 3l (closing the gap) — projax repo, commit d49ad21, merge c8164f6. caldav.ListEvents + Events card on /dashboard with 7-day window, day-grouping, RRULE-flagged-but-not-expanded. mgmt.msbls.de parity reached.

Phase 3m (the teardown itself) — split across two repos.

Deviation from §4 step 1 (Traefik redirects): Dokploy/Traefik configuration lives in the Dokploy UI, not in any in-repo file. Head approved the alternative (m/mAi#1908): implement the legacy-path 301 in src/hooks.server.ts instead — version-controlled, deploys with the app, no Dokploy UI access needed.

Step Repo Commit What landed
1 m/msbls.de 2941dc4 301 redirect for /mgmt/*projax.msbls.de (mapping helper projaxRedirectFor; covers /mgmt, /mgmt/login, /mgmt/self, and catch-all → /dashboard). Runs in hooks.server.ts before any other guard so unauth probes also land safely.
2 m/msbls.de 89d60bc (combined with step 4 in the same merge) Removed src/routes/mgmt/** (9 files), src/hooks.ts (reroute), src/lib/host-routing.{ts,test.ts}. Inlined the two trivial cockpit-host/path predicates directly into hooks.server.ts.
3 m/msbls.de n/a (verified during step 2) Cross-repo grep for /mgmt strings in ~/dev/ returned only msbls.de's own (now-deleted) routes + one stale comment in projax/deploy/dokploy.yaml (handled at step 5 below). No other repo had hardcoded references.
4 m/msbls.de 89d60bc Dropped the auth shell entirely — src/lib/server/{auth,supabase,mbrian,caldav}.ts, Locals.userId, $mbrian alias in svelte.config.js, GITEA_TOKEN arg + submodule clone in Dockerfile, .gitmodules. Sweep confirmed hooks.server.ts was the only consumer of authenticateRequest, and no remaining route (/, /impressum, /slop, /[code]) needs locals.userId. bun run check → 0 errors, bun run build → success.
5 m/projax (this commit) Cleaned the stale "auth federated with mgmt.msbls.de" comment in deploy/dokploy.yaml line 45 — now describes the host-scoped /login cookie model that projax actually uses.
6 m/projax (this commit) This "DONE" section appended.

Verification commands (run by the worker after the m/msbls.de autoDeploy completes — m sees these in the completion report):

# /mgmt/* on any host redirects to projax (301)
curl -sS -i https://www.msbls.de/mgmt/anything | head -3
curl -sS -i https://mgmt.msbls.de/ | head -3
# Public msbls.de homepage still works
curl -sS -i https://www.msbls.de/ | head -3
# projax still works through its own auth surface
curl -sS -i https://projax.msbls.de/dashboard | head -3

Post-teardown janitorial (NOT part of this work; m can clean at leisure):

  • Dokploy: drop env vars no longer used by msbls.de — SUPABASE_HOST, SUPABASE_SERVICE_KEY, SUPABASE_ANON_KEY, CALDAV_BASE_URL, CALDAV_USER, CALDAV_PASSWORD, COOKIE_DOMAIN, GITEA_TOKEN. None are referenced in code anymore.
  • DNS: mgmt.msbls.de CNAME/A record can be retired at m's leisure. The redirect works whether the subdomain hits the msbls.de app (current shape) or 404s elsewhere. Keeping the subdomain pointing at the app preserves the redirect for bookmark-followers.
  • Old browser cookies on Domain=.msbls.de will keep cluttering until expiry (1 year). Browsers' "clear cookies for site" works if it bothers anyone.

Plan vs reality recap:

  • Plan estimated "~14 days with dogfood weeks" / "~3 days compressed." Actual: same session as Gap 1, ~30 minutes of actual code touch. Compression was viable because (a) the gap was small (b) test coverage on both sides was already strong (c) zero external dependencies on /mgmt/* per the §6 risk audit.
  • No "unexpected" surprises beyond the in-repo-vs-Dokploy-UI configuration split (covered by §6's "Cookie-scope semantics change — LOW" implicitly: same theme of "Dokploy state ≠ code state"). Head approved the SvelteKit-side redirect alternative in real time.