Admin
The private console that writes Portfolio contracts, IAM access, and deploys—after a live capability check, not a hidden button.
- Next.js Server Components
- Supabase SSR and RLS
- Typed CMS contracts
- RBAC and revalidation

The product tension
If I have to ship a pull request to fix a typo, the public site will rot. If Admin is just hidden buttons, anyone with a cookie becomes an editor. I needed a private operations app that writes the same Work and Writing contracts Portfolio reads, and that re-checks who I am on every privileged call.
What I built
I built Admin as an IAM-gated Next.js console. Workspaces cover Portfolio CMS, users and access, Vercel deploys for Studio and Admin, and a private career tracker. There is no Studio CMS workspace; Studio owns its own registries.
Authorization. admin.console.enter is the door. admin.full_access mutates. admin.viewer reads unpublished Portfolio content and deployments. Proxy admission is not enough: each elevated route reauthorizes, then may create a service-role client. Role names in the JWT are not the check.
Contracts. Forms validate with @jayantgoyal/portfolio-contracts—the same columns, JSON case-study shape, and assets the public loader selects. Saves revalidate Portfolio. Identity name stays read-only from shared config.
Other domains. Career reads a private schema after admin.career.read. Deployment actions use a server-only Vercel token. Assignment and revocation of Admin access go through transactional IAM functions that write an audit event.
How the system fits together
Admin is a client of Portfolio, IAM, and providers. It does not become the owner of public copy or of Auth credentials.
The calls that shaped the build
- 01
I authorize the mutation, not the menu
Hiding a nav item is not security. Viewer and full-access see different workspaces, but writes still go through capability-checked server routes before a service-role client exists.
- 02
I kept one document shape for case studies
Admin cannot save a study the public renderer cannot parse. Decisions, architecture, and publication flags are fields, not a blob of HTML.
- 03
I left Studio out of this console
A reserved Studio nav with no workspace is honest. Inventing Admin screens for tools I already register in code would duplicate ownership.
Trust boundaries
The app is private. MFA step-up applies when a factor exists. Service-role and Vercel tokens never ship to the browser. Public Portfolio queries never receive unpublished rows or privileged credentials. Career data is not a public grant.
What I chose—and accepted
A second application to deploy, plus IAM ceremony on every write. Scripts against the database are faster for me and invisible to an audit. I still want the form, the contract, and the revalidation on the path a future editor would use.
Why the work matters
I can publish or unpublish a case study without mixing CMS JSON into the Next app. The public site stays free of service-role. Access changes leave an IAM audit trail. Admin sits on the home grid as the operations half of the publishing system, not as a fifth product family.
What I would improve next
Preview and revision history before a Work save goes live. Until then, publication remains an explicit flag, not an autosave side effect.