|
|
7787ed4ea4
|
§10 split landing into a public "/" + gated "/dashboard", both plugin-replaceable (todo §10 follow-up); per human feedback, "/" is now an ungated public landing (default views/home.ejs: brand + intro + prominent Log in / Create account links, or "go to dashboard" when signed in) and "/dashboard" is the gated post-login app home (anonymous → /login?return_to=/dashboard). Both are fully replaceable via two optional RouteHandlers on PluginManifest — home? (public /) and dashboard? (gated /dashboard) — rendered against the plugin's own views with the native shell via ctx.chrome (full route parity: HEAD, void-return, response hooks, fresh CSRF cookie; a home handler is public so ctx.user may be null). Single-slot + loud: findConflicts errors on >1 owner of either slot (new "home"/"dashboard" kinds), discovery rejects a non-function handler, and "dashboard" is reserved so a plugin folder can't shadow it ("/" can't be shadowed — route paths carry the /<id> prefix). Post-login + already-signed-in redirects and the global Dashboard/People nav hrefs moved to /dashboard. Tests-first (348 units): public-/ + gated-/dashboard + dual plugin-override in app.test; per-slot conflict in plugin.test; non-function/reserved/two-owners in discovery.test. Docs: plugin-contract "The landing pages" section + README. E2E: visual.spec plants a session for /dashboard design-system tests + a cookie-free public-landing test; full-flow repointed to /dashboard. stability-reviewer: APPROVE, no Critical/High/Medium. typecheck + 348 units + visual(10) + full-flow(7) green.
|
2026-06-20 17:43:01 +02:00 |
|
|
|
2eb5b84ccf
|
§10 gate the dashboard + make "/" replaceable by a plugin (todo §10); "/" is now gated to a signed-in session (anonymous → /login via loginRedirect, query preserved as return_to) and fully replaceable via a new optional home?: RouteHandler on PluginManifest — a handler with the same signature as any route (the most ergonomic shape). The app.ts "/" branch gates first, then renders the single home plugin's handler against its own views/ with the native shell via ctx.chrome (HEAD / void-return / response-hook parity with a plugin route), else the built-in mock-data People list. home mounts at the root above the /<id> namespace, so it can't shadow or be shadowed by a built-in route. Single-slot + loud: findConflicts errors on >1 home (new "home" kind), discovery rejects a non-function home — never last-write-wins. Tests-first (338 → 344 units): app.test.ts gate + home-override; plugin.test.ts home conflict; discovery.test.ts home validation. Docs: plugin-contract.md (manifest table + "The dashboard (home)" section + conflict row), README. E2E: visual.spec plants a dev-signed session (the anonymous plugin-gate probe uses the cookie-free request fixture); all e2e web/gateway healthchecks repointed from the gated "/" to /public/css/styles.css. stability-reviewer: APPROVE, no Critical/High/Medium. typecheck + 344 units + visual(9) + full-flow(7) E2E green.
|
2026-06-20 17:18:30 +02:00 |
|
|
|
09d616ddd3
|
Loosen plugin id rule (todo §2); allow digits and dashes anywhere (^[a-z0-9-]+$)
|
2026-06-16 11:53:14 +02:00 |
|
|
|
1623a81ddc
|
Refine plugin contract (todo §2); derive id/mount from folder (isValidPluginId), apiVersion literal not HOST_API_VERSION, nav icon = Lucide, drop redundant basePath
|
2026-06-16 10:58:29 +02:00 |
|
|
|
a0d39ef624
|
Make checkApiVersion semver-based (todo §2); strict parseSemver via official semver regex (no dep), major/minor compatibility rules
|
2026-06-16 10:46:02 +02:00 |
|
|
|
3be67ff8e4
|
Specify the plugin contract (todo §2); typed manifest + version/conflict rules in src/plugin.ts, authoritative docs/plugin-contract.md
|
2026-06-15 17:07:55 +02:00 |
|