Commit Graph

15 Commits

Author SHA1 Message Date
f189f88942 §7 reference plugin (todo §7); plugins/scheduling is the worked example of the plugin contract — a list page fetching upstream data, a CSRF-guarded form forwarding writes upstream, permission-gated nav. shifts.ts: an injectable-fetch upstream REST client (stateless stand-in for the customer backend) + thin handler factories (list filters by ?q + degrades to a recoverable page on upstream-down; create CSRF-guards via ctx.verifyCsrf, validates, forwards, PRG, 502 on upstream 4xx). plugin.ts: apiVersion literal, namespaced scheduling:read/write perms, nav gated so the whole Scheduling header vanishes for non-holders. Views compose the core building blocks around the native app shell, incl. the plugin's own partials/shift-form. New host capability so a plugin page is native + secure (src/chrome.ts buildPluginChrome): ctx.chrome = brand/global-nav/user/theme/csrf for partials/shell (global menu = Dashboard + every plugin nav fragment + gated admin section, role-filtered + current-marked); ctx.verifyCsrf = the host's bound double-submit verifier (secret stays in the host). Both added to RequestContext (defaulted in buildContext), built per plugin route in app.ts (CSRF cookie set when fresh). Dashboard merges plugin nav fragments too (gated => invisible to anonymous, visual E2E byte-identical). Out of the box: bootstrap grants the demo admin scheduling:read/write (seedAdmin generalized to a roles list, env ADMIN_ROLES); dev compose runs a tiny stdlib mock upstream (examples/shifts-upstream, SCHEDULING_UPSTREAM). plugins/ added to tsconfig + the npm test glob. Tests-first across shifts/chrome/app/dashboard/bootstrap. README Building-a-plugin + Layout and docs/plugin-contract.md (ctx.chrome/verifyCsrf, upstream pattern) updated. typecheck + 296 units + the Ory-free visual E2E green (plugin discovered at boot, routes/nav gated, dashboard unchanged); live full-stack boot-verified (stack up with plugin + mock upstream serving the seeded shifts, bootstrap grants in real Keto all allowed:true) then torn down. apiVersion stays 1.0.0 (contract still assembled in §7). Authenticated browser happy-path deferred to §8 full E2E (line 114). 2026-06-19 14:48:27 +02:00
d1fbf8fa1f Comment/README cleanup (todo §4); tighten the kratos/keto client module-headers (drop forward-refs + caller-listings, keep rationale), retarget the stale safeUrl() ref in plugin-contract.md to §5/§7 2026-06-18 11:52:49 +02:00
caadaf5da3 Reviewer-run fixes (todo §4); re-mint try/catch degrades an Ory outage to anonymous (not 500), RESERVED_PLUGIN_IDS refuses a plugin folder that would shadow a host route 2026-06-18 11:45:04 +02:00
228a206469 Auth guards (todo §4); guards.ts: requireSession/can/check + GuardError, app.ts maps GuardError → 303 /login or 403 (never 500) 2026-06-18 10:10:15 +02:00
a8ebf81588 Address whole-project review (todo §2); wire plugin hooks (onBoot/onRequest/onResponse), document template trust boundary, tidy discovery 2026-06-16 16:23:08 +02:00
ff7b55be4c Wire branding into the app shell (todo §2); render config logo + default theme, fall back to the brand mark 2026-06-16 16:07:24 +02:00
952dd03cc2 Add config/menu.ts central override + branding (todo §2); loadMenuConfig validates+merges, override applied to nav, branding into shell 2026-06-16 15:52:03 +02:00
3cdefff233 Serve per-plugin static assets (todo §2); /public/<id>/ → plugins/<id>/public/ via routePublic, core public/ unaffected 2026-06-16 15:18:20 +02:00
fe89dd1c06 Add per-plugin view resolver (todo §2); render plugins/<id>/views/<view>.ejs with nested names + traversal guard, core partials reachable via include() 2026-06-16 13:41:02 +02:00
9b6684c653 Mount plugin routes via the router (todo §2); match method+path under /<id>, resolve :params, permission gate, RouteResult→response 2026-06-16 12:22:15 +02:00
0ebe8144c2 Document how plugins get into the container (README); bind-mount to /app/plugins/<id> or bake in, front-and-center under Building a plugin 2026-06-16 11:58:28 +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