Files
coreci-chat/apps/control-plane/app/dashboard/page.tsx
T
CIAgent bcca7686ee feat(P2): Wave B identity & RBAC — WorkOS SSO, tenant provisioning, RBAC at gateway
REQ-001: SSO session via WorkOS (getAuthorizationUrl + exchangeCodeForSession)
REQ-002: tenant provisioning on first signup (admin role)
REQ-003: invitations via single-use acceptance link
REQ-004: RBAC role assignment (admin/operator/viewer)
REQ-005: RBAC enforcement at API gateway from first endpoint (/api/me)

---ci---
phase: 2
milestone: v0.1
status: execute
---/ci---
2026-08-25 01:47:56 +00:00

73 lines
2.5 KiB
TypeScript

/**
* /dashboard — M1 admin dashboard shell (REQ-002).
*
* The 5-step onboarding checklist is rendered here (all grey — steps light up
* as later waves ship). Wave E wires live Relay Agent health + targets; this
* shell proves the SSO → /dashboard redirect works end-to-end.
*/
import { getMe } from "./me.js";
export default async function DashboardPage() {
const me = await getMe();
if (!me) {
// Not authenticated — bounce to login. getMe() returns null on 401.
return (
<main style={{ fontFamily: "system-ui", maxWidth: "32rem", margin: "4rem auto", padding: "0 1rem" }}>
<h1>CoreCI Chat</h1>
<p>You are not signed in.</p>
<p>
<a href="/login">
<button style={{ padding: "0.6rem 1.2rem", font: "inherit" }}>Go to login</button>
</a>
</p>
</main>
);
}
const steps = [
{ id: "byom", label: "Configure BYOM", wave: "C" },
{ id: "relay", label: "Install Relay Agent", wave: "D" },
{ id: "target", label: "Register Target", wave: "D" },
{ id: "verify", label: "Verify Green Status", wave: "E" },
{ id: "team", label: "Invite Team", wave: "B" },
];
return (
<main style={{ fontFamily: "system-ui", maxWidth: "48rem", margin: "2rem auto", padding: "0 1rem" }}>
<header style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
<h1>CoreCI Chat Dashboard</h1>
<span style={{ color: "#666", fontSize: "0.85rem" }}>
{me.role} · tenant {me.tenantId.slice(0, 8)}
</span>
</header>
<section>
<h2>Onboarding</h2>
<ul style={{ listStyle: "none", padding: 0 }}>
{steps.map((s) => (
<li key={s.id} style={{ padding: "0.4rem 0", display: "flex", gap: "0.6rem", alignItems: "center" }}>
<span
aria-label={s.id + " status"}
style={{
width: "0.9rem",
height: "0.9rem",
borderRadius: "50%",
background: "#ccc",
display: "inline-block",
}}
/>
<span>{s.label}</span>
<span style={{ color: "#999", fontSize: "0.75rem" }}>(Wave {s.wave})</span>
</li>
))}
</ul>
</section>
<p style={{ marginTop: "2rem" }}>
<a href="/api/auth/logout">Sign out</a> ·{" "}
<a href="/dashboard/team">Team</a>
</p>
</main>
);
}