Cover admin provision-now, public self-service redeem, and admin invite-by-email across CMS + public-site tracks. Add standalone AuthBlocks password-reset team brief.
30 KiB
Phase 19 — AuthBlocks User Management in the CMS
Status: proposed (rev. 2 — scope expanded by Daniel 2026-06-19). Author: product-designer. Date: 2026-06-19. Implementer: TBD (separate delegation).
Wire the AuthBlocks user-administration surface (create users, manage existing accounts, manage
registration invites, manage role permissions) into the DeepDrftManager CMS so an admin can run
account management from inside the same authenticated CMS they already use — and stand up the
public-facing self-service registration form on the DeepDrftPublic site so an invited user can
redeem a registration code and create their own account.
Daniel's framing: "this is already part of the AuthBlocks library so we just need to wire it up
properly." That framing is correct for the CMS surface — and the wiring there is further along than
it implies. Almost the entire CMS-side integration already landed as a side-effect of the prior
AuthBlocks startup separation (PLAN_authblocks_trackmanager.md, landed 2026-05-25) and the
login/logout integration; what remains there is a thin navigation + verification + polish slice,
not an integration project.
Scope expansion (Daniel, 2026-06-19). The original (rev. 1) spec deferred public self-service
registration entirely and treated "create user" as a single CMS path. Daniel reversed both: he wants
all three account-creation paths wired, with each placed on its correct host. Two of the three are
CMS-side (and ride the already-done CMS wiring above); the third is public-facing and requires a
genuine cold-start AuthBlocks integration on DeepDrftPublic, which today has no AuthBlocks
reference at all. The public-registration work is therefore a distinct track with its own host,
routing, and layout considerations — not part of the CMS nav slice.
The spec below separates what is already done from the genuine remaining work, and separates the CMS track (waves 19.1–19.3, the original slice) from the new public-site track (wave 19.4).
0. The three account-creation paths (verified against AuthBlocks source)
Daniel asked for the registration model to be double-checked against C:\Development\AuthBlocks.
Verified — his three-path understanding is correct and complete. The model:
| # | Path | Component(s) | Route | Host | Backed by | Email? |
|---|---|---|---|---|---|---|
| 1 | Admin provisions a user directly (bypasses email/code loop) | SuperRegister.razor |
/account/superregister |
CMS | POST api/auth/admin-register (UserAdmin-gated) — working |
No |
| 2 | Public self-service — invited user redeems a code and self-registers | Register.razor |
/account/register |
PUBLIC SITE | POST api/auth/register (unauthenticated) — working |
No (consumes code) |
| 3 | Admin provisions a registration token + triggers the invite email | NewRegistration.razor → NewRegistrationForm.razor |
/useradmin/registrations/new |
CMS | POST api/pendingregistration/create (UserAdmin-gated) — working, sends email server-side |
Yes — real, not stubbed |
Path 3's email is real. This is the headline correction to rev. 1, which worried the
token-provisioning path might be stubbed like Reset Password. It is not. PendingRegistrationRoutes.Create
(AuthBlocksLib/Routes/PendingRegistrationRoutes.cs:62) generates a token, persists the pending
registration, builds the invite link ({ReturnHost}?UserEmail=&RegistrationToken=), renders
RegistrationEmailTemplate.Create(...), and sends it via IGeneralEmailSender.SendEmailAsync —
a Mailtrap-backed MailtrapEmailSender registered in AuthBlocksExtensions (line 109) and configured
in DeepDrftAPI from environment/authblocks.json (AuthBlocks:Email:Host / :Token,
Program.cs:106–109; ApplicationName="DeepDrft", SupportEmail from config). On email-send failure
the route rolls back the pending-registration row and returns 500. So the full invite→email→redeem
loop is functional end-to-end across paths 2 and 3: an admin provisions (path 3) → the prospective user
receives an email with a code + link → they land on the public /account/register form (path 2) with
email + token pre-filled from the query string → they set a password and the account is created.
The one genuinely stubbed surface is Reset Password — Users.razor:55 (// todo integrate with email for secure reset) has an empty handler and no backing API endpoint exists (AuthRoutes
maps login/register/admin-register/refresh/logout/me/roles — no reset route). That is the subject of
the separate authblocks-password-reset-brief.md; it must not be filed as a DeepDrft bug.
Two distinct admin "create" verbs — both stay, they are not duplicates. SuperRegister (path 1)
creates a live account immediately with a password the admin sets. The registration-token form (path
3) creates a pending invite — no account yet — and lets the user set their own password via email. They
serve different needs (provision-now vs. invite-by-email); both belong in the CMS nav. (Note the older
rev. 1 "canonical create-user" question conflated SuperRegister with NewUser at
/useradmin/users/new — that NewUser ModelView create form still exists as a third bare admin
create path, but it is not one of Daniel's three; treat it as redundant with SuperRegister and
do not surface it in nav. See OQ2.)
1. What AuthBlocks ships, and how it is packaged
Read from local source at C:\Development\AuthBlocks (not public docs). The key question the brief
raised — is the user-admin surface consumable or host-bound? — resolves cleanly: it is
consumable.
The user-admin surface is a published RCL, despite the "Web" name
AuthBlocksWeb is an Microsoft.NET.Sdk.Razor project (not Sdk.Web) with no Program.cs — it
is a Razor Class Library, not a runnable host. pack.ps1 packs it as Cerebellum.AuthBlocks.Web
and pushes it to nuget.org alongside the other four packages. So the user-admin Razor components are
distributed as a normal RCL and are consumed by reference, exactly like any MudBlazor-based component
package. No extraction fork is needed — the architectural risk the brief flagged ("if the pages
are host-bound and need extracting into an RCL") does not materialize. The pages are already in the
RCL.
What's in the package (the consumable surface)
Components under AuthBlocksWeb/Components/:
- Account pages (
Pages/Account/):Login,Logout,AccessDenied.Register.razor→/account/register(path 2 — public self-service via invite code;@rendermode InteractiveServer; readsUserEmail+RegistrationTokenfrom the query string and pre-fills, so a deep link from the invite email lands ready to submit; callsAuthStateProvider.RegisterAsync→POST api/auth/register; no role gate — it is meant to be reachable by an unauthenticated visitor).SuperRegister.razor→/account/superregister(path 1 — admin creates a live account immediately, with a role multiselect; gated[HierarchicalRoleAuthorize(UserAdmin)]; callsIAuthApiClient.AdminRegisterAsync→POST api/auth/admin-register).
- User admin pages (
Pages/UserAdmin/), each@page-routed and gated[HierarchicalRoleAuthorize(SystemRoleConstants.UserAdmin)]:Users/Users.razor→/useradmin/users— searchable user grid; per-row Reset Password (stubbed —// todo integrate with email, no backing endpoint), Deactivate/Reactivate, edit modal.Users/NewUser.razor→/useradmin/users/new— bare create-user form (redundant withSuperRegister; not one of Daniel's three paths — do not surface in nav).Registrations/Registrations.razor→/useradmin/registrations— pending-invite grid (email, consumed?, dates), withNewRegistration.razor→/useradmin/registrations/new(path 3 —NewRegistrationFormposts toPendingRegistrationClient.CreatePendingRegistration→POST api/pendingregistration/create, which mints the token and sends the invite email) and the edit-registration modal.Permissions/Permissions.razor→/useradmin/permissions— user↔role assignment.
- Menu fragments (
Components/Layout/):AccountNavMenu,UserAdminMenu(aMudNavGroupwith the three user-adminMudNavLinks, itself wrapped in aHierarchicalRoleAuthorizeViewso it only renders forUserAdmin+). - Shared (
Components/Shared/):LogoutButton,StatusMessage. - DI entry point (
Startup.cs):ConfigureAuthServices(IServiceCollection, string apiBaseUrl)registers the cascading auth state, the JWT client stack, and every user-admin client + ViewModel (UsersClient/UsersViewModel,RoleClient,UserRolesClient/PermissionsViewModel,PendingRegistrationClient/RegistrationsViewModel), all pointed atapiBaseUrl.
The pages lean on Cerebellum.BlazorBlocks.Web for their grid scaffolding (ModelView,
ModelPageViewModel, ConfirmCancelModal) and MudBlazor for chrome — both already present in the CMS.
The API side is already hosted
The clients those ViewModels use call the AuthBlocks API surface, which DeepDrftAPI already
mounts via app.MapAuthBlocks() (Program.cs:184): api/auth/* (incl. admin-register, gated
UserAdmin; and roles), api/users/*, api/roles/*, api/user-roles/*,
api/pending-registration/*. AddAuthBlocks + UseAuthBlocksStartupAsync (migrate + seed) are wired,
and the Auth DB + secrets live in DeepDrftAPI/environment/. This all landed with the startup
separation.
2. What is ALREADY wired in DeepDrftManager (do not redo)
Verified against the current DeepDrftManager source. These are the integration steps a naive plan
would propose — and they are already done:
- Package reference.
DeepDrftManager.csproj:11referencesCerebellum.AuthBlocks.Web(10.3.33), which transitively bringsAuthBlocksWeb.Client,AuthBlocksLib,AuthBlocksModels. - Service wiring.
Program.cs:35callsAuthBlocksWeb.Startup.ConfigureAuthServices(builder.Services, contentApiUrl)— so the user-admin clients and ViewModels are already in the container, already pointed at DeepDrftAPI. - Page discovery.
Routes.razor:2setsAdditionalAssemblies="new[] { typeof(AuthBlocksWeb._Imports).Assembly }"andProgram.cs:131mirrors it for endpoint mapping. The Blazor router already discovers every AuthBlocksWeb page, including/useradmin/users,/useradmin/registrations,/useradmin/permissions,/useradmin/users/new,/account/superregister. They are route-reachable today by typing the URL. - Default layout.
Routes.razor:6setsDefaultLayout="typeof(Layout.CmsLayout)". Since the AuthBlocks pages declare no@layout, they already render inside CmsLayout chrome. - Role gating already satisfied. The pages gate on
SystemRoleConstants.UserAdmin. The DeepDrft admin is seeded in roleAdmin, andSystemRole(id 1,Admin) is the parent ofUserAdmin(id 2) —Admin.InheritsFrom/hierarchical authorize means the existing admin already passes theUserAdmingate with no role change, no new seed, no DB edit. - Auth-state + redirect plumbing.
AuthorizeRouteViewwithRedirectToLogin/RedirectToAccessDenied(Routes.razor) already protects the surface coherently.
Net: an authenticated DeepDrft admin can, right now, navigate to /useradmin/users and the page
should render and call DeepDrftAPI. The reason it feels unbuilt is that nothing in the CMS UI links
to these pages — CmsLayout has no nav drawer at all (just an app bar with a Home button), so the
surface is invisible and unverified.
This is the crux: the CMS-side work is not integration, it is exposure + verification + fit-and-finish.
2b. What is NOT wired on DeepDrftPublic (the public-registration track — genuine cold start)
The public self-service registration form (path 2) lives in the same RCL (Cerebellum.AuthBlocks.Web)
as the CMS pages. But unlike the CMS, DeepDrftPublic has no AuthBlocks footprint at all — verified:
- No package reference. Neither
DeepDrftPublic.csprojnorDeepDrftPublic.Client.csprojreferencesCerebellum.AuthBlocks.Web(or any AuthBlocks package). - No service wiring.
DeepDrftPublic/Program.csnever callsConfigureAuthServices— theAuthStateProvider/ JWT client stack thatRegister.razordepends on is absent from the container. - No page discovery. No
AdditionalAssembliesentry for the AuthBlocks RCL, so the router cannot reach/account/registereven if the package were referenced.
So path 2 is a from-cold integration on the public site, not a "flip it on" task. The render-mode
substrate, at least, is compatible: DeepDrftPublic is already a Blazor Web App with both
AddInteractiveServerComponents + AddInteractiveWebAssemblyComponents and the matching render modes
(Program.cs:33–34, 147–148), so Register.razor's @rendermode InteractiveServer is satisfiable
without a render-mode change.
The public-track integration steps (mirror of §2 items 1–4, but on the public host):
- Package reference — add
Cerebellum.AuthBlocks.WebtoDeepDrftPublic.csproj(the host owns the page discovery + DI; the client assembly need not reference it unless a client-rendered surface is wanted —RegisterisInteractiveServer, so server-host wiring suffices). - Service wiring — call
AuthBlocksWeb.Startup.ConfigureAuthServices(builder.Services, contentApiUrl)inDeepDrftPublic/Program.cs, pointed at the same DeepDrftAPI base URL the public site already uses forapi/track/*(it resolves fromenvironment/api.jsonApi:ContentApiUrl). This registers theAuthStateProviderand JWT client stackRegister.razorneeds. Open scope question (OQ6): this also pulls in the entire AuthBlocks client surface (all user-admin clients/VMs) and the cascading auth state — heavier than the public site needs. Acceptable for v1 (it is inert without the gated pages mounted), but worth a conscious "is the public site now auth-aware?" decision (it gains a logged-in concept it did not have). - Page discovery — add the AuthBlocks
_Importsassembly toAdditionalAssemblieson the public site's router (and mirror for endpoint mapping) so/account/registeris route-reachable. This also exposes/account/login,/account/superregister, and the/useradmin/*pages on the public host. The/useradmin/*and/account/superregisterpages self-gate toUserAdmin(a public visitor fails the gate → RedirectToLogin/AccessDenied), so they are not a data-exposure risk, but surfacing admin routes on the public origin at all is a posture choice. Recommendation: if the framework supports it cleanly, register only theRegisterpage (or scope discovery), or accept the gated routes as present-but-unreachable-in-practice. Flag as OQ7. - Layout —
Register.razordeclares no@layout, so it inherits the public site'sDefaultLayout(the full public chrome: player bar, nav, footer). Decide whether self-registration should render in the full public layout or a lean auth layout (mirroring the CMS'sCmsHomeLayoutsplash idiom). For v1, the public layout is acceptable; a lean layout is polish. Flag as OQ8. - CORS — DeepDrftAPI's
ContentApiPolicymust allow the public site origin for theapi/auth/*callsRegistermakes. The public origin is already an allowed origin forapi/track/*(same proxy hop), and the policy is origin-scoped not path-scoped, so this should already be satisfied — but it is a verification item (mirror of the CMS's G2 CORS check), not an assumption. - Entry point / link — once the form is reachable, decide whether/where the public site links to
it. The invite email's deep link lands directly on
/account/register?UserEmail=&RegistrationToken=, so the form works without any public nav link (the email is the entry point). A visible "Register" link in the public nav is optional and arguably unwanted (registration is invite-only — a public "Register" link invites confusion/abuse since there is no self-serve code issuance). Recommendation: no public nav link; the email deep link is the sole entry point. Flag as OQ9.
This is why the public track is its own wave (19.4), parallel to but independent of the CMS nav work.
3. The genuine remaining work
G1 — Navigation: there is no way to reach the surface from the UI (the real gap)
CmsLayout.razor is an app bar + a single Home MudIconButton — no MudDrawer, no nav menu. The
catalogue, releases, upload, and now user-admin surfaces are all reachable only by typed URL or
in-page buttons. Mounting UserAdminMenu requires a navigation container to mount it into.
Three shapes, meaningfully different (diverge-before-converge):
- G1-a — Minimal: app-bar overflow menu. Add a
MudMenu(or a fewMudIconButtons) to the existing app bar with links to the three user-admin routes (+ SuperRegister). Smallest change; keeps CmsLayout's current spare aesthetic. Cost: doesn't scale — the CMS already has catalogue/releases/upload that arguably belong in a real nav too, and an overflow menu gets crowded. - G1-b — Recommended: a real
MudDrawernav in CmsLayout. Add a left drawer (toggle in the app bar) holding the existing primary destinations (Catalogue, Releases, Upload) and the shippedUserAdminMenufragment (which self-gates toUserAdmin+). This is the idiomatic Blazor/MudBlazor CMS shape, it reuses AuthBlocks' own menu component verbatim, and it gives the CMS the navigation spine it's currently missing. Cost: slightly larger CmsLayout change; a small visual-design pass on the drawer. - G1-c — Maximal: dedicated "Administration" section. A drawer plus a distinct admin sub-area (its own landing page summarizing user counts / pending registrations, mirroring the catalogue dashboard idiom). Cost: net-new surface (an admin dashboard) beyond what AuthBlocks ships; scope creep for v1.
DECIDED: G1-b (Daniel, 2026-06-19). A real MudDrawer nav in CmsLayout mounting UserAdminMenu
- the existing CMS destinations. It solves the actual gap (no nav) with the least bespoke code, reuses
the shipped
UserAdminMenu, and is the natural home for the CMS's other destinations too. G1-c's admin dashboard remains deferred (good later idea, not a v1 gate); G1-a is the rejected stopgap.
Borrowed precedent: this is the standard MudBlazor admin-template layout (persistent left
MudDrawer+MudNavMenu/MudNavGroup), whichUserAdminMenuis already authored against — it is aMudNavGroup. We are adopting the pattern the component was built for, not inventing one.
G2 — Verification pass (the surface is wired but unproven end-to-end)
Because nothing exercised these pages in the CMS, treat first-light as verification, not assumption. Confirm against a running DeepDrftAPI + Auth DB:
/useradmin/userslists users (theUsersClient→api/users/*round-trip works cross-origin / cross-host, with the bearer token the CMS already holds)./account/superregister(path 1) creates a live account immediately —admin-registerisUserAdmin-gated server-side and the admin's token must carry the role claim end-to-end./useradmin/registrations/new(path 3) provisions a token and sends the invite email — verify the email actually arrives (Mailtrap), the link/code in it are correct, and the rollback fires if the send fails. This is the surface most likely to surface a config gap (AuthBlocks:Email:Host/:Tokenmust be real, not placeholder, in DeepDrftAPI'senvironment/authblocks.json)./useradmin/registrationslists invites;/useradmin/permissionsreads + assigns roles.- CORS / token presentation: the prior plan widened DeepDrftAPI CORS for the Manager origin for
login; confirm the same allowance covers
api/users/*/api/pendingregistration/*etc. (it should — same origin, same policy). - Two admin create verbs both stay —
SuperRegister(path 1, provision-now) and the registration-token form (path 3, invite-by-email). The bareNewUser(/useradmin/users/new) is redundant withSuperRegisterand is not surfaced in nav (OQ2). Both nav-surfaced paths are verified.
This pass is where any latent break surfaces (a client config typo, a missing role claim in the CMS-issued token, a package-version mismatch). It is real work even though no code may change if it all passes.
G3 — Theming / fit-and-finish
The AuthBlocks pages are MudBlazor-default-styled and were authored against AuthBlocks' own theme, not
the DeepDrft CMS palette (DeepDrftPalettes.Cms, mounted in CmsLayout with IsDarkMode="false").
Expect minor visual seams: the AuthBlocks ThemeColorDemo/MudBlazor defaults vs. the CMS's DM-Sans /
charleston palette. Scope for v1: accept MudBlazor-default styling inside the CMS palette (the
MudThemeProvider in CmsLayout already themes Mud components, so the pages inherit the CMS palette for
free) and only fix outright legibility/contrast breaks. A deeper bespoke restyle of the AuthBlocks
grids is explicitly out of v1 — flag as deferred polish.
G4 — Package version alignment (housekeeping, flag don't gate)
DeepDrftManager references Cerebellum.AuthBlocks.Web 10.3.33; AuthBlocks source is at 10.3.35.
Minor lag. Bumping to 10.3.35 is low-risk and gets the latest user-admin fixes, but is not required
for this phase to function. Note it; let Daniel decide whether to bump in this pass or separately.
4. Scope boundaries
In for v1 (two tracks):
CMS track (waves 19.1–19.3):
- G1-b: a
MudDrawernav inCmsLayoutmountingUserAdminMenu(+ the existing CMS destinations). - All three CMS-side account paths surfaced in nav: path 1 (
SuperRegister, provision-now) and path 3 (/useradmin/registrations/new, invite-by-email), plus the users/permissions grids. - G2: end-to-end verification of list/create/deactivate users, registrations (incl. the real invite email send), permissions.
- G3: accept-the-palette theming; fix only legibility breaks.
Public-site track (wave 19.4) — the reversed deferral:
- Path 2 — public self-service registration (
/account/register) wired on DeepDrftPublic: package reference +ConfigureAuthServices+ page discovery + layout + CORS verification (§2b). The invite email's deep link is the entry point.
Deferred (note, don't build):
- Admin dashboard (G1-c) — a user-admin landing summarizing counts / pending invites. Good later; not a v1 gate.
- Reset Password — the AuthBlocks
Userspage stubs it (// todo integrate with email; no backing endpoint exists inAuthRoutes). It is an upstream AuthBlocks gap, not a DeepDrft wiring task. Daniel is handling it as a separate AuthBlocks-repo effort with another team — see the standaloneproduct-notes/authblocks-password-reset-brief.md. Do not implement password reset inside DeepDrftHome. - Bespoke restyle of the AuthBlocks grids to the editorial DeepDrft aesthetic (CMS or public).
- A lean public auth layout for
/account/register(full public chrome is acceptable for v1 — OQ8). - A visible public-nav "Register" link (registration is invite-only; the email deep link suffices — OQ9).
- G4 version bump — housekeeping, Daniel's call on timing.
Explicitly not needed (the brief's worried-about fork):
- Extracting AuthBlocks pages into a new RCL. They already ship in
Cerebellum.AuthBlocks.Web. - New DI/service wiring, new routing, new role seeding, new Auth connection string. All present.
5. Phased breakdown (for clean dispatch)
Two tracks. The CMS track (19.1–19.3) is the original exposure+verify+polish slice. The public-site track (19.4) is a parallel, independent cold-start integration on a different host. They share only the DeepDrftAPI auth surface (already mounted) and can proceed concurrently.
CMS track
- 19.1 — CmsLayout navigation (cold-start, the only CMS code wave). Add a
MudDrawer+ toggle toCmsLayout.razor; mount the shippedUserAdminMenufragment (self-gates toUserAdmin+) and the existing CMS destinations (Catalogue/catalogue, Releases/releases, Upload/tracks/upload). Surface both admin account paths: path 1 (SuperRegister,/account/superregister) and path 3 (/useradmin/registrations/new, reachable via theUserAdminMenuRegistrations link → its New button). Do not surface the redundant bareNewUser(OQ2). Scope:CmsLayout.razor(+ a small.razor.cssif the drawer needs sizing). No service, API, data, or AuthBlocks-source change.- Acceptance: an authenticated
Adminsees a nav drawer; the User Administration group appears and links to Users / Registrations / Permissions; a "Create user" affordance reachesSuperRegister; a non-UserAdminuser does not see the group; existing CMS destinations are reachable from the drawer.
- Acceptance: an authenticated
- 19.2 — End-to-end verification (after 19.1; may surface follow-ups). Exercise G2 against a running DeepDrftAPI. Confirm list/create/deactivate users, invite-email send (path 3), permission round-trips, and cross-host token + CORS. File any latent break as a follow-up (likely a one-line config fix — esp. the Mailtrap creds — or an upstream AuthBlocks issue). Mostly test, not code.
- 19.3 — Theming legibility sweep (after 19.1, parallel-ok with 19.2). Walk each user-admin page in the CMS palette; fix only contrast/legibility breaks. Defer bespoke restyle.
Public-site track
- 19.4 — Public self-service registration on DeepDrftPublic (cold-start, parallel to 19.1). Wire
path 2 per §2b: add the
Cerebellum.AuthBlocks.Webpackage reference toDeepDrftPublic, callConfigureAuthServicesinProgram.cspointed at the existing DeepDrftAPI base URL, add page discovery so/account/registeris reachable, settle the layout (OQ8) and route-exposure posture (OQ7), and verify CORS for the public origin. This is real host-integration code on the public site (unlike the CMS, where wiring pre-exists) — scope:DeepDrftPublic.csproj,DeepDrftPublic/Program.cs, the public router, possibly a lean layout. No AuthBlocks-source change.- Acceptance: an invited user clicking the deep link in their registration email lands on
/account/registerwith email + token pre-filled, sets a username/password, and the account is created (the row inpending_registrationis consumed); the form renders coherently in the chosen public layout; an unauthenticated visitor can reach the form (it is not role-gated). The full path-3→path-2 loop (admin provisions in CMS → email arrives → user redeems on public site) works end-to-end.
- Acceptance: an invited user clicking the deep link in their registration email lands on
Dependency shape: 19.1 → {19.2, 19.3} (CMS track); 19.4 is independent and parallel to the
CMS track (it touches a different host; its only dependency, the DeepDrftAPI api/auth/register
endpoint, is already live). The full invite→redeem acceptance test for 19.4 benefits from 19.1+19.2
being able to generate a real invite, but 19.4 can be built and unit-verified against a token minted
directly via the API. Recommended kick-off: 19.1 and 19.4 in parallel.
6. Open questions for Daniel
Resolved (Daniel, 2026-06-19):
- Nav shape (G1) — DECIDED G1-b. Real
MudDrawernav mountingUserAdminMenu+ existing CMS destinations. Locked. - Admin create paths — DECIDED: surface path 1 (
SuperRegister) + path 3 (registration-token form); do NOT surface the bareNewUser. Both of Daniel's two admin paths stay (they are not duplicates — provision-now vs. invite-by-email); the rev-1 "which single canonical create path" question dissolves because there are legitimately two.NewUseris redundant withSuperRegisterand is hidden from nav. - Reset Password — DECIDED: non-functional in v1, handled separately. Confirmed an upstream
AuthBlocks gap (stub + no endpoint), not a DeepDrft bug. Daniel is running it as a separate
AuthBlocks-repo effort with another team (see
authblocks-password-reset-brief.md). The 19.2 verification pass must not file it.
Still open:
- Admin dashboard (G1-c) — defer or include? Recommend defer. Net-new surface beyond what AuthBlocks ships; v1 should expose the working pages, not build a new one.
- Package bump (G4) — now or separate? Bump
Cerebellum.AuthBlocks.Web10.3.33 → 10.3.35 in this pass, or leave it? Recommend leave it unless 19.2 surfaces a fix that needs it. Note: if 19.4 adds the package to DeepDrftPublic, pin both hosts to the same version to avoid a split-version RCL. - Public-site auth footprint (19.4). Wiring
ConfigureAuthServicesinto DeepDrftPublic pulls in the entire AuthBlocks client surface + cascading auth state — the public site gains a "logged-in" concept it does not have today. Acceptable for v1 (inert without gated pages mounted), but it is a real posture shift. Recommend accept it (it is the supported wiring path; scoping it down is bespoke work for no v1 benefit) — confirm Daniel is comfortable the public site becomes nominally auth-aware. - Public route exposure (19.4). Adding the AuthBlocks RCL to the public router's
AdditionalAssembliesexposes not just/account/registerbut also/account/login,/account/superregister, and the/useradmin/*routes on the public origin (all self-gating toUserAdmin, so not a data leak — but admin routes visible on the public host). Recommend: accept them as present-but-gated for v1 (simplest); narrow discovery to justRegisterlater if the exposure bothers us. Flag if Daniel wants the narrow path now. - Public-registration layout (19.4). Render
/account/registerin the full public chrome (player bar/nav/footer) or a lean auth layout (mirroring the CMSCmsHomeLayoutsplash)? Recommend full public chrome for v1, lean layout as polish. - Public "Register" nav link (19.4). Add a visible Register link to the public nav, or rely solely on the invite email's deep link? Recommend deep-link-only — registration is invite-only; a public "Register" link with no self-serve code issuance invites confusion/abuse.
Items 6–9 shape the public-site track (19.4). 3, 4 are CMS scope/timing calls. None block 19.1.