11c98daed065dbaeaf2609e105ec7ecbac2f234e
3
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
be79499635 |
Give the nav's dead links somewhere to land
Three of the app's routes were referenced but never existed, so the redesign's
navigation pointed at 404s from several directions.
/dashboard was the post-login and fallback redirect target in nine places --
login, onboarding, middleware, the admin/nodes/systems/tokens/settings guards,
and the marketing header -- but app/dashboard/ was never created. Signing in
normally dropped the user on a 404. The real signed-in home is "/", which
app/page.tsx already renders as LiveView for an authed user with an org, and
which the nav labels "Live"; all nine now point there.
Nav also linked /watch and /network, neither of which existed. /watch is the
alerts screen under its redesign name, so it re-exports app/alerts/page.tsx
and /alerts stays reachable for old links. /network is new: the "my equipment"
hub the redesign moved /nodes, /systems and /tokens behind and then never
built, which had left /systems and /tokens with no entry point in the UI at
all. Its hooks all run before the admin/operator guard, per
|
||
|
|
83416fe169 |
Split platform-admin from org-owner, hide Trips from non-founding orgs
SAAS_PLAN.md B7. "admin" meant two different things before this: platform operator (SAAS_PLAN.md's own framing) and, by accident of how app/settings/layout.tsx was gated, the only role that could ever reach an org's own billing/members/node-ownership settings. A paying customer who is their own org's owner couldn't reach their own Settings page - the gate checked isAdmin, which only platform admins ever have. settings/layout.tsx now admits org_role === "owner" as well as platform admins (isAdmin stays valid too, for support access to any org's settings). Nav.tsx shows the Settings link on the same condition, and moves Admin (the platform-operator screens: feature flags, users, audit, correlation debug) out of the customer-facing link group entirely - it was already gated server-side, this is just the nav no longer implying it's part of the product. Trips - an internal utility feature riding along on this stack, not a tenant-scoped product surface (see [[trips-feature-intentional]]) - drops out of the customer-facing viewer link group and only shows for the founding org (new lib/tenancy.ts mirrors app/internal/tenancy.py's FOUNDING_ORG_ID) or a platform admin, matching the mutation-route gating routers/trips.py already got in the backend tenancy commit. Reads stay open to any signed-in user, same as before - trips' own visibility model (public/private per trip) predates and is unrelated to org tenancy, and restricting it further wasn't asked for. Also closes two DEFERRED.md items now that they have somewhere to write to: app/settings/organization's "Save changes" button now actually calls c2api.getOrg()/updateOrg() (routers/org.py, shipped in the backend tenancy commit) instead of being permanently disabled. app/settings/nodes gained an EnrollmentTokensPanel (mint/list/revoke against the same commit's /org/enrollment-tokens routes) - without this, B2b's whole point (a customer enrolls their own node with their own token instead of an admin-issued key) had no way to actually be used outside a raw API call. Left alone, and written up as new DEFERRED.md entries instead of guessed at: node/system *write* routes (approve, create, delete) stay platform-admin-only rather than being loosened to org owner/operator - a real gap per SAAS_PLAN.md 2.4, but a separate authorization design that the plan's 12-item build order doesn't enumerate. And settings/members + settings/nodes' ownership table both still call GET /admin/users (platform-admin-only) - a pure org owner who reaches the page via this commit's gate will get 403s from it. Today's only real user is also a platform admin, so this is invisible until a second, non-admin org owner exists. Typecheck: clean (tsc --noEmit via the WSL-native ~/drb-frontend copy). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
53965e1a19 |
Rebuild the frontend as a product rather than an internal tool
The UI worked but read as an operator console: no public face, no way to describe or sell the thing, and no account surface beyond the node list. This adds the missing halves and reorganises what was already there around the incident, which is the unit of value the rest of the pipeline is built to produce. A shared design system replaces per-page styling: components/ui (Button, Card, Badge, EmptyState, Skeleton, PageHeader), a type scale and shadow set in the Tailwind config, and light-mode tokens in globals.css. The existing html:not(.dark) remap mechanism is extended rather than replaced -- a parallel theming system would have been two sources of truth for the same colours. Public marketing pages (/, /features, /pricing, /faq) load without a session. middleware.ts gained a PUBLIC_PATHS allowlist to permit that; it remains a UX redirect and is still NOT an authorisation boundary, which the comment there says explicitly. Real enforcement is unchanged and still lives server-side in c2-core's auth.py. Chrome switching is done by pathname in ChromeSwitcher instead of by route group, because a route group would have collided on / and forced most of app/ to move for no behavioural gain. Billing and API keys ship as typed stubs, not integrations. lib/billing.ts and lib/apiKeys.ts define the data model and the screens consume it, but every mutating call throws with a message naming the backend route that has to exist first, and the sample data is labelled as sample. Nothing here can charge anyone or mint a real credential -- picking a payment processor and holding its keys is a decision for a human, and a half-wired checkout is worse than an obviously absent one. The severity work from the c2-core change lands here too. severity is now a filter and sort dimension on the incident list rather than decoration, since a busy dispatch channel is only readable if you can collapse it to moderate and above. routine gets a muted treatment because it is the majority of traffic, legacy "unknown" still renders nothing, and TypeBadge handles the new "other" incident type. Severity rendering moved into lib/severity.tsx so the incident list, incident detail and call rows cannot drift apart. Deliberately not touched: calls, map, alerts, nodes, systems, tokens, trips and admin. They already share the palette and stay coherent, and rewriting them would have buried the parts that actually needed to change. No colour tokens were renamed, so nothing regressed there. Verified with tsc --noEmit (npm run typecheck), clean. No runtime verification was possible and none was done. No new environment variables. |