user-engine/workplans/USER-WP-0020-self-service-and-user-administration-portal.md
tegwick 6d64ec2ccf
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Close portal MVP and preserve expansion backlog
2026-07-30 00:52:50 +02:00

13 KiB

id type title domain repo status owner topic_slug created updated depends_on state_hub_workstream_id
USER-WP-0020 workplan Production self-service and user administration portal communication user-engine finished codex netkingdom 2026-07-27 2026-07-30
USER-WP-0014
USER-WP-0015
USER-WP-0019
35b9c315-e721-4e0b-9710-bad04f8d2519

USER-WP-0020 - Production self-service and user administration portal

Turn the transport-neutral UI contracts from USER-WP-0014 into a real, secure browser application and HTTP API backed by user-engine. The first production acceptance case is onboarding bernd.worsch@binky-hedgehog.com as tenant administrator for tenant:friendly:binky.

user-engine remains authoritative for user-domain records, profiles, memberships, invitations, registration sessions, and onboarding state. KeyCape/NetKingdom remains authoritative for login, credentials, MFA, authentication sessions, and OIDC tokens. flex-auth remains authoritative for authorization decisions.

T01 - Ratify the portal boundary and threat model

id: USER-WP-0020-T01
status: done
priority: high
state_hub_task_id: "9886ac8d-7456-4de0-b019-351dfd74ec20"

Define browser/API trust boundaries, public and authenticated routes, role projections, CSRF/session/XSS controls, rate limits, account-enumeration resistance, invitation abuse controls, audit correlation, privacy retention, and recovery behavior. Define an explicit IdentityProvisioningPort; the domain must not import LLDAP, privacyIDEA, KeyCape, email, or flex-auth clients.

Keep enterprise federation, SCIM, corporate directory synchronization, and SAML administration out of scope while preserving provider-neutral identity links, membership envelopes, provisioning adapters, and external ownership metadata for that later stage.

T02 - Implement a production HTTP API

id: USER-WP-0020-T02
status: done
priority: high
state_hub_task_id: "fdb0c322-3efe-4077-bfba-1648787ef411"

Expose versioned APIs for registration start/resume/complete, invitation claim, current-user profile, tenant membership, onboarding, tenant-admin user management, and platform-admin tenant/user management. Consume verified KeyCape claims and require flex-auth decisions for protected writes. Add idempotency keys, optimistic concurrency, pagination, structured errors, OpenAPI, health/readiness, redacted audit, and transactional outbox behavior.

2026-07-28 implementation evidence: the deployed versioned API can create a tenant-scoped user and membership, establishes the lifecycle account in the requested tenant even for authorized cross-tenant platform operations, and invokes a provider-neutral provisioning port with roles, correlation, and a required idempotency key. Remaining API breadth and OpenAPI/outbox work keep this task in progress.

2026-07-29 increment: IdentityProvisioningPort now includes provider-neutral read-only drift inspection and active reconciliation. The HTTP adapter carries the same desired identity envelope used for provisioning, returns only machine-readable differences and changes, and retries one transient dependency failure under the required idempotency key. NetKingdom's live LLDAP adapter proved drift detection, convergence, and replay-safe cleanup. Remaining API breadth and OpenAPI/outbox delivery keep this task in progress.

T03 - Implement self-service login and registration UX

id: USER-WP-0020-T03
status: done
priority: high
state_hub_task_id: "45ed1485-003d-4e5f-99fb-91b1b430f3fa"

Build an accessible responsive browser flow for sign in, registration, invitation acceptance, email verification status, password-setup handoff, MFA-enrollment handoff, consent, profile completion, tenant selection, and resumable onboarding. Authentication and factor screens must redirect or handoff to NetKingdom-owned surfaces; the portal must never handle provider admin credentials or store password/MFA secrets.

2026-07-28 increment: the deployed portal presents an HTTPS-only interstitial to NetKingdom's 15-minute, single-use password setup surface after provisioning and lets an authorized administrator renew that handoff for an already-linked identity. The portal never receives the password. Adapter and browser regressions are included in the 105-test passing suite. Invitation, verification, consent/profile, tenant selection, MFA enrollment, and full accessibility breadth remain.

T04 - Implement tenant-admin and platform-admin UX

id: USER-WP-0020-T04
status: done
priority: high
state_hub_task_id: "16555b68-17ef-4902-bd30-f9a0cfe10f9e"

Tenant admins can invite, list, inspect, suspend, reactivate, and remove only users and memberships in tenants they administer, assign approved tenant roles, resend/expire invitations, and inspect redacted lifecycle/audit state. Platform admins can create/manage tenants, bootstrap the first tenant admin, inspect cross-tenant lifecycle gaps, and perform explicitly authorized recovery actions. Prove ordinary users and tenant admins cannot reach platform or other-tenant data.

2026-07-28 implementation evidence: the deployed admin surface lists tenant-scoped members, creates the user and approved role as a separate auditable step, provisions the login through the provider-neutral adapter, persists the external subject link, and suspends/reactivates both LLDAP login and the tenant account. Browser mutations require an OIDC session and per-session CSRF token. Platform tenant creation, invitation/recovery breadth, removal, and full cross-tenant conformance remain.

T05 - Add production persistence and operability

id: USER-WP-0020-T05
status: done
priority: high
state_hub_task_id: "65ff5c96-134a-4ec2-ad92-511f0e5f6f04"

Package the service and web assets, use the provider-backed Postgres adapter, run migrations safely, expose metrics and structured logs, deliver secrets through approved runtime references, implement backups/restore evidence, and document rollback and zero-downtime upgrade expectations. Browser state must never become authoritative.

2026-07-29 increment: the runtime now exposes protected Prometheus readiness and aggregate record metrics, rejecting requests without the trusted workload marker. NetKingdom deployed a daily atomic Postgres custom-format backup with catalog/checksum verification and retention, then restored it into an isolated ephemeral PostgreSQL instance and verified four public tables plus the schema ledger. A reversible live rollout gate proved rollback to the retained prior image and restoration of user-engine:portal-2bcda7f. The remaining production gaps are off-node backup custody and approved registry publication, so this task remains in progress.

2026-07-30 follow-up: the portal, provisioner, and prior rollback image are published through the workload-scoped Forgejo credential and anonymously verified by digest. The live portal and provisioner now use registry digests, and rollback/roll-forward no longer depends on containerd retaining local tags. An age-encrypted user-engine Postgres dump was uploaded through the established activity-core offsite lane with plaintext cleanup.

2026-07-30 completion: the approved ops-mason plan moved the portal edge marker and provisioner service token into one exact OpenBao workload path, delivered through separate bounded AppRoles and namespace-restricted ExternalSecret stores. A coordinated rotation converged all three derived Secrets before restarting the portal and provisioner, and both Deployments returned Ready. Exact-path access succeeds, sibling-path access is denied, the derived client/server tokens match, and a post-rotation disposable identity reconciliation passed. No secret value entered recorded evidence.

T06 - Security, accessibility, and workflow conformance

id: USER-WP-0020-T06
status: done
priority: high
state_hub_task_id: "39dc383c-7213-495d-8e12-58e614706afe"

Automate positive and negative flows for self-registration, invite-only registration where configured, duplicate identities, expired/replayed invitations, cross-tenant access, role escalation, CSRF, session expiry, provider outage, partial provisioning compensation, audit redaction, WCAG keyboard/screen-reader behavior, and mobile/desktop layouts.

2026-07-28 evidence: all 101 unit tests pass (three integration skips), mounted secret normalization has regression coverage, and a disposable live identity proved first create, replay/resume, tenant group projection, and cleanup through the restricted deployment path. The complete browser, authorization, failure, accessibility, and restore matrix remains.

The admin increment adds explicit regression coverage for missing/wrong CSRF, required API idempotency, provider-link persistence, and suspension calls.

2026-07-29 evidence: the provider-neutral adapter suite now covers drift inspection, convergence results, transient retry, and replay-safe identity cleanup; the full user-engine suite passes 107 tests with three provider integration skips. A live disposable identity was suspended, reported as drifted, reconciled to in_sync, and removed without leaving directory state.

T07 - Binky production acceptance

id: USER-WP-0020-T07
status: done
priority: high
state_hub_task_id: "b8d1c048-24d2-416c-908f-e500d63c6865"

Through the deployed portal—not a one-shot script—create or claim Binky, onboard bernd.worsch@binky-hedgehog.com, complete KeyCape login and MFA, assign only the Binky tenant-admin membership, and prove denial for tenant:platform, tenant:coulomb, and unrelated tenants. Confirm the same admin can invite and lifecycle-manage a disposable Binky test user.

2026-07-28: the deployed versioned portal API created the Binky tenant-admin user and membership, invoked the provider-neutral provisioning adapter, and persisted the LLDAP subject link with password_setup_required. A live newline-bearing proxy Secret exposed an HTTP transport bug; commit 0ef2ae5 normalizes required runtime values, adds regression coverage, passes all 105 tests (three integration skips), and is deployed on railiance01. The remaining reusable first-password gate is now deployed: an authorized portal action creates or renews a 15-minute, single-use NetKingdom URL. Live disposable-user conformance proved revocation, validation without consumption, OPAQUE password registration, directory login, replay denial, and cleanup. Remaining Binky acceptance is the human-selected password, MFA enrollment, and tenant claim/denial evidence; no one-shot operator password was used.

2026-07-29 human acceptance: bernd.worsch completed the portal-issued password setup, privacyIDEA TOTP enrollment, and a fresh KeyCape password-plus-OTP login. Two UX follow-ups were captured from the live journey: accept/display the email alias instead of requiring the directory uid wherever the provider permits, and make authenticator labels identify the account. privacyIDEA's future enrollment label is now Coulomb: {user}@{realm} at the otpauth issuer/account level; existing wallet entries require a local rename.

2026-07-29 follow-up: the first-factor edge now accepts either stable directory uid or full email using Authelia's documented LLDAP uid/mail filter. The resolved subject remains the uid, so this improves login comprehension without changing identity keys.

Live /api/v1/me acceptance confirmed the canonical KeyCape issuer, tenant:friendly:binky, Binky-only users/admins groups, roles user and tenant-admin, and AAL2 pwd + otp assurance with mfa: true. Attempts to open tenant:platform and tenant:coulomb administration were both denied.

T08 - Closure and next-stage handoff

id: USER-WP-0020-T08
status: done
priority: medium
state_hub_task_id: "ecbdeef3-a0a9-40d6-9722-5cc650d78a49"

Close after the portal is production-operable and the Binky acceptance case passes. Record enterprise federation follow-up triggers: customer demand for SAML/OIDC federation, SCIM, directory synchronization, just-in-time provisioning, or customer-owned identity lifecycle. Do not pre-implement those integrations here.

Milestone closure (2026-07-30)

The production Binky MVP is complete and live. Its API covers verified current user, registration start/completion, tenant-scoped paginated membership listing, user creation, provider-neutral provisioning, and suspend/reactivate lifecycle with structured errors, correlation, idempotency gates, durable transactions, audit, and outbox records. Its browser journey covers KeyCape sign-in, provider-owned password setup and MFA, tenant administration, and CSRF-protected lifecycle management.

Acceptance evidence includes AAL2 login, platform/unrelated-tenant denial, provider drift and reconciliation, replay-safe deletion, secret rotation, database restore, and deployment rollback/roll-forward. Broader invitation and platform recovery APIs, expanded onboarding/administration UX, automated outbox delivery, and the full accessibility/provider-outage matrix transfer to USER-WP-0021; they are not silently treated as implemented here.

Enterprise federation remains trigger-driven. Create a separate implementation plan only when a tenant requires SAML/OIDC federation, SCIM, directory synchronization, just-in-time provisioning, or customer-owned lifecycle.