Files
user-engine/wiki/ArchitectureBlueprint.md

22 KiB

User Engine Architecture Blueprint

Status: initial architecture blueprint Date: 2026-05-22 Related product docs: ../INTENT.md, ProductRequirementsDocument.md Primary platform references:

  • /home/worsch/net-kingdom/canon/standards/iam-profile_v0.2.md
  • /home/worsch/net-kingdom/docs/platform-identity-security-architecture.md
  • /home/worsch/net-kingdom/docs/responsibility-map.md
  • /home/worsch/key-cape/SCOPE.md
  • /home/worsch/flex-auth/docs/iam-profile-consumption.md

1. Architecture Decision

user-engine should be implemented as the headless user-domain and profile service in the NetKingdom repository landscape.

It owns user-domain records, account state, external identity links, profile/preference values, application registrations, customization catalogs, profile projections, and lifecycle/profile events.

It does not own authentication, MFA, password/passkey credentials, OIDC token issuance, final resource authorization, runtime secret custody, or UI experience. Those remain with the existing NetKingdom-aligned components:

  • key-cape or Keycloak implements the NetKingdom IAM Profile.
  • local-identity supports local/bootstrap development identity.
  • flex-auth owns final authorization decisions and policy/audit envelopes.
  • OpenBao and Railiance platform services own runtime secrets and durable platform backing services.
  • Future user-account and user-manager repos/apps own the UI surfaces.

The useful product boundary is:

Identity provider tells user-engine who the actor is.
flex-auth tells user-engine what the actor may do.
user-engine manages user-domain facts and profile projections.
Applications and UIs consume user-engine through stable headless APIs.

2. Fit In The NetKingdom Landscape

2.1 Identity Integration

Applications and user-engine should target the NetKingdom IAM Profile, not a concrete provider. In production and platform mode, requests arrive with tokens issued by either:

  • key-cape lightweight mode, backed by Authelia/LLDAP/privacyIDEA where used;
  • Keycloak expanded mode, used for enterprise federation, SAML brokering, or complex realm/delegated-admin needs.

In local development, local-identity can issue local OIDC tokens that are accepted only in non-production environments. Production user-engine deployments must reject local or loopback issuers as required by the IAM Profile.

Required token inputs for user-engine are the same provider-neutral facts used by flex-auth:

  • iss, sub, aud, tenant, principal_type
  • groups, roles, scope or scp
  • assurance
  • optional human display/contact claims such as preferred_username, email, and name
  • optional agent/delegation claims for agentic use cases

user-engine must treat iss + sub as the stable identity link key. Email, username, or display name must never be primary keys.

2.2 Authorization Integration

user-engine enforces access, but it should not become the policy decision point. For every protected action, it should present a normalized request to flex-auth and enforce the returned decision locally.

Protected resource examples:

Resource Example actions
user-engine:user read, create, update, deactivate, delete_request
user-engine:identity-link read, link, unlink
user-engine:profile read, update, resolve, project
user-engine:membership read, assign, remove
user-engine:application register, update, deactivate
user-engine:catalog register, activate, deprecate, migrate
user-engine:audit read

The authorization flow should be:

  1. Validate or receive a validated IAM Profile token.
  2. Normalize identity claims into an actor envelope.
  3. Resolve the actor's linked user where needed.
  4. Call flex-auth with actor, tenant, resource, action, scope, assurance, and contextual attributes.
  5. Enforce deny/allow/obligations locally.
  6. Apply attribute-level projection filtering for visibility, mutability, and sensitivity.
  7. Emit audit and domain events.

Memberships and profile facts can be authorization-relevant inputs, but they are not authorization decisions. user-engine may export subject, tenant, team, and membership facts to flex-auth subject manifests or resolver adapters; flex-auth remains the decision boundary.

2.3 Deployment And Operations Integration

user-engine can run in three modes:

Mode Purpose Dependencies
Standalone Small app, prototype, local dev, single service Local DB, local/external OIDC, optional in-process policy adapter
Platform Shared service for multiple NetKingdom applications IAM Profile issuer, flex-auth, PostgreSQL, event/audit sink, OpenBao-backed secrets
Enterprise Federated, provisioned, multi-tenant landscape Keycloak expanded mode, SCIM/import adapters, stronger audit retention, directory/group resolvers

Production platform mode should use Railiance-provided backing services:

  • PostgreSQL for canonical user-engine state.
  • OpenBao for database credentials, API client secrets, signing keys, and webhook secrets.
  • Railiance platform event or message services for outbox/event delivery.
  • Cluster ingress, network policy, TLS, and observability from the Railiance stack.

NetKingdom should meta-orchestrate the trust and responsibility boundaries. Railiance should execute deployment mechanics. If user-engine becomes a shared platform service that holds user, account, catalog, and membership resources across the landscape, NetKingdom's responsibility map should be updated there, not in user-engine intent, to preserve self-coherent repo intent.

3. Responsibility Boundaries

Concern Owner user-engine role
OIDC discovery, login, token issuance key-cape, Keycloak, local-identity in dev Consume tokens and identity facts
Passwords, MFA, passkeys, sessions key-cape/Keycloak/MFA stack No storage or credential lifecycle
External identity links user-engine Map iss + sub identities to local user records
Canonical user/account/profile data user-engine Source of truth
Application profile catalogs user-engine Source of truth and validation authority
Groups/roles in tokens IAM provider, mapped to IAM Profile Consume as identity facts; do not make final decisions
Membership/domain facts user-engine, optionally synced with IAM/flex-auth Manage user-domain relationships; export facts where useful
Final authorization flex-auth and PDP adapters Ask, enforce, audit obligations
Runtime secrets OpenBao/Railiance platform Consume scoped secrets only
Self-service UI future user-account Provide APIs/projections
Admin UI future user-manager Provide APIs/projections

4. Conceptual Component Model

               +---------------------+
               | key-cape / Keycloak |
               | IAM Profile issuer  |
               +----------+----------+
                          |
                          | OIDC token / normalized claims
                          v
+-------------------------+--------------------------+
|                    user-engine                     |
|                                                    |
|  API adapters                                      |
|    - REST/HTTP API                                 |
|    - internal service API                          |
|    - future SDKs                                   |
|                                                    |
|  Domain core                                       |
|    - users and accounts                            |
|    - identity links                                |
|    - tenants, applications, teams, memberships     |
|    - global, tenant, app, and membership profiles  |
|    - preference values                             |
|                                                    |
|  Catalog and projection engine                     |
|    - catalog registry                              |
|    - attribute governance                          |
|    - effective profile resolver                    |
|    - projection filters                            |
|                                                    |
|  Integration layer                                 |
|    - flex-auth check client                        |
|    - IAM Profile claim adapter                     |
|    - event outbox                                  |
|    - audit writer                                  |
+------------+--------------------------+------------+
             |                          |
             | policy checks            | state/events/audit
             v                          v
       +-----------+           +----------------------+
       | flex-auth |           | PostgreSQL / outbox  |
       +-----------+           | event/audit sinks    |
                               +----------------------+

The domain core should be usable without HTTP. API adapters should call domain services rather than placing lifecycle or profile resolution logic in route handlers.

5. Domain Model Blueprint

5.1 Stable Identifiers

Use stable internal identifiers and explicit external links.

Entity Identifier rule
User Internal user_id, opaque and stable
External identity Unique (issuer, subject) plus provider metadata
Tenant NetKingdom-aligned identifiers such as tenant:platform, tenant:coulomb, tenant:customer:<id>
Application Stable application id, preferably namespaced
Catalog (application_id, namespace, catalog_id, version)
Attribute Catalog-qualified key, not a global loose string
Membership (user_id, scope_type, scope_id, role_or_relation) where applicable

5.2 Core Entities

Minimum persistent entities:

  • User: stable person/human-representing subject.
  • Account: lifecycle state and platform/application relationship.
  • ExternalIdentity: identity provider link, keyed by iss + sub.
  • Tenant: platform or tenant plane scope.
  • Application: profile-consuming application registration.
  • Team or GroupScope: optional team/project scope for membership profiles.
  • Membership: user relationship to tenant, application, team, project, or other scope.
  • ProfileValue: scoped profile/preference values.
  • Catalog: application-owned customization descriptor.
  • AttributeDefinition: catalog-defined attribute metadata.
  • ProjectionDefinition: reusable projection rules.
  • AuditRecord: durable user-engine audit trail.
  • OutboxEvent: reliable integration event queue.

5.3 Account Lifecycle

Initial account states should align with the PRD while staying compatible with external provisioning:

  • invited
  • active
  • disabled
  • suspended
  • deletion_pending
  • deleted

Account records should separately track management mode:

  • local
  • externally_provisioned
  • federated
  • service_managed

State transitions must be explicit, audited, and authorized. Deletion should default to a staged deletion_pending flow so downstream projections and events can settle before irreversible erasure.

6. Catalog And Profile Architecture

6.1 Catalog Descriptor

The first catalog descriptor should be JSON/YAML with JSON Schema-compatible validation plus user-engine governance metadata.

Required catalog-level fields:

  • namespace
  • catalog id
  • semantic version
  • owning application id
  • lifecycle state: draft, active, deprecated, retired
  • allowed profile scopes
  • projection types
  • migration metadata

Required attribute-level fields:

  • key
  • value type and validation schema
  • defaulting behavior
  • allowed scopes
  • owner
  • visibility
  • mutability
  • sensitivity
  • inheritance/override rule
  • projection eligibility
  • UI hints for future generated forms

Catalog activation should validate:

  • namespace ownership
  • attribute key uniqueness within the catalog version
  • valid scope references
  • supported validation schemas
  • no incompatible sensitivity downgrade from previous active versions
  • migration requirement when changing type, scope, or sensitivity

6.2 Layered Profile Scopes

Initial layers:

  1. Global user profile
  2. Tenant user profile
  3. Application user profile
  4. Membership/team profile
  5. Admin override, only for attributes that explicitly allow it

The effective profile resolver should be deterministic and inspectable. A projection response should be able to explain which layer supplied a value and which values were hidden by visibility/sensitivity policy.

Suggested default precedence:

catalog default
  < global value
  < tenant value
  < application value
  < membership/team value
  < allowed admin override

Precedence should be configurable only through catalog-defined override rules, not per-request ad hoc logic.

6.3 Projection Types

Minimum projection types:

  • self_service: fields the current user may see or change.
  • admin: fields visible to a scope administrator.
  • application_runtime: fields a registered application may consume.
  • oidc_claims: fields safe to map into OIDC-style profile claims.
  • audit: redacted change summary for audit and diagnostics.
  • agent_context: policy-filtered profile/preferences for delegated or autonomous agent use.

Projection defaults should be deny-by-default for sensitive attributes. Sensitivity and mutability should be enforced in the projection layer even after flex-auth authorizes the broader action.

7. API Surface Blueprint

The first API should be headless and UI-neutral.

Suggested high-level resources:

GET    /health
GET    /ready

GET    /me
PATCH  /me/profile
GET    /me/applications/{application_id}/profile
PATCH  /me/applications/{application_id}/profile
GET    /me/identities

GET    /users/{user_id}
PATCH  /users/{user_id}
POST   /users/{user_id}/lifecycle/{transition}

GET    /tenants/{tenant_id}/users
GET    /tenants/{tenant_id}/memberships
POST   /tenants/{tenant_id}/memberships
DELETE /tenants/{tenant_id}/memberships/{membership_id}

GET    /applications
POST   /applications
GET    /applications/{application_id}
PATCH  /applications/{application_id}

GET    /applications/{application_id}/catalogs
POST   /applications/{application_id}/catalogs
POST   /applications/{application_id}/catalogs/{catalog_id}/activate
POST   /applications/{application_id}/catalogs/{catalog_id}/deprecate

GET    /profiles/effective
GET    /projections/{projection_type}

GET    /audit

API design rules:

  • Every mutating endpoint requires an authenticated IAM Profile actor.
  • Every scoped endpoint must carry an explicit tenant/application/team context.
  • Admin endpoints are scope-admin endpoints, not platform-root shortcuts.
  • The me API uses the linked current actor, not a client-supplied user id.
  • Applications may register catalogs only for namespaces they own.
  • Attribute updates must validate against the active catalog version.
  • Projection responses must not leak hidden sensitive values in validation errors, explanations, or audit summaries.

8. Event And Audit Blueprint

user-engine should implement a transactional outbox so profile changes, membership changes, catalog changes, and lifecycle changes cannot commit without a corresponding event record.

Initial domain events:

  • user.created
  • user.updated
  • user.activated
  • user.disabled
  • user.suspended
  • user.deletion_requested
  • user.deleted
  • identity.linked
  • identity.unlinked
  • profile.updated
  • membership.changed
  • application.registered
  • catalog.registered
  • catalog.activated
  • catalog.deprecated
  • projection.changed

Audit records should include:

  • actor identity envelope
  • subject user or resource
  • action
  • tenant/application/scope
  • authorization decision id or correlation id from flex-auth where available
  • high-level change summary
  • sensitivity-aware redaction
  • timestamp and source client

Audit is part of user-engine's own accountability, but platform-wide durable audit retention should integrate with the Railiance/NetKingdom audit sink when available.

9. Standalone To Platform Progression

9.1 Standalone Setup

Standalone mode should prove reuse without a full platform:

  • local or external OIDC issuer;
  • SQLite or local PostgreSQL;
  • local config file for application registration;
  • in-process authorization adapter for development only, or a small allowlist policy with clear production warnings;
  • same catalog and profile APIs as platform mode.

Recommended decision: do not implement passwords or MFA in standalone mode. Use local-identity for local OIDC or an external OIDC provider. This keeps the standalone path useful without starting identity-provider creep.

9.2 NetKingdom Platform Setup

Platform mode should be the normal integrated setup:

  • key-cape or Keycloak issues IAM Profile tokens.
  • flex-auth authorizes user-engine actions.
  • PostgreSQL stores canonical state.
  • OpenBao provides runtime secrets.
  • event/audit outbox drains to platform services.
  • app and tenant identifiers follow NetKingdom tenant semantics.

9.3 Enterprise Setup

Enterprise mode adds:

  • Keycloak expanded mode for inbound enterprise federation and SAML/Entra/AD brokering;
  • SCIM-aligned import/provisioning adapters;
  • directory/group resolver integration for group overage and freshness;
  • stronger audit retention, export, and review workflows;
  • tenant and admin delegation models.

SCIM should initially be a compatibility target and adapter boundary, not the MVP's source of truth.

10. Implementation Roadmap

Phase 0 - Contracts And Skeleton

  • Add SCOPE.md for user-engine.
  • Add API and catalog descriptor draft specs.
  • Define resource/action vocabulary for flex-auth.
  • Define user-engine event names and audit schema.
  • Choose implementation stack and repository layout.

Phase 1 - Headless Core MVP

  • Implement domain core for users, accounts, identity links, applications, catalogs, profile values, and effective profile resolution.
  • Implement persistence with migration support.
  • Implement REST API and health/readiness endpoints.
  • Implement transactional audit and outbox tables.
  • Add SDK/client generation or a minimal typed client.

Phase 2 - NetKingdom Integration

  • Add IAM Profile claim adapter and production issuer validation.
  • Add flex-auth check client and protected resource/action manifests.
  • Add OpenBao/Railiance-ready secret configuration.
  • Add event sink adapter for the platform event path.
  • Add conformance tests with local-identity and IAM Profile fixtures.

Phase 3 - Catalog And Projection Hardening

  • Add catalog versioning and activation/deprecation rules.
  • Add migration checks for catalog changes.
  • Add projection definitions for self-service, admin, application runtime, OIDC claims, audit, and agent context.
  • Add attribute-level sensitivity, mutability, visibility, and explanation tests.

Phase 4 - Enterprise Adapters

  • Add SCIM-aligned inbound provisioning adapter.
  • Add Keycloak/expanded-mode provisioning integration where needed.
  • Add directory/group resolver integration for freshness/overage handling.
  • Add export/import and tenant onboarding diagnostics.

Phase 5 - UI Consumers

  • Build user-account as a self-service UI over the same APIs.
  • Build user-manager as a scoped admin UI over the same APIs.
  • Keep UI-specific form rendering downstream of catalog/projection metadata.

11. Testing And Conformance

Minimum test suites:

  • domain model unit tests;
  • catalog descriptor validation tests;
  • profile resolution precedence tests;
  • projection redaction and mutability tests;
  • IAM Profile token acceptance/rejection tests;
  • flex-auth allow/deny/obligation integration tests;
  • tenant isolation tests;
  • account lifecycle transition tests;
  • audit/outbox atomicity tests;
  • local standalone smoke test;
  • platform-mode smoke test with local-identity or fixture issuer.

Production-readiness checks should include:

  • rejects local-development issuers in production;
  • validates issuer, audience, expiry, not-before, signature, and algorithm either directly or through a trusted upstream gateway;
  • enforces tenant context on every scoped request;
  • denies profile access when flex-auth denies;
  • redacts sensitive attributes in all non-eligible projections;
  • persists audit records for administrative and lifecycle changes;
  • drains outbox without losing committed changes.

12. Open Decisions

Decision Recommendation
Implementation language/framework Choose after first API/design spike; keep domain core independent from HTTP
Standalone authentication Use local-identity or external OIDC; do not implement passwords/MFA
First database PostgreSQL for platform, optional SQLite for local standalone
Catalog descriptor format JSON/YAML using JSON Schema-compatible validation plus user-engine governance metadata
Membership source of truth user-engine owns user-domain memberships; IAM/flex-auth consume or mirror only what they need
SCIM timing Adapter boundary after MVP, not initial source of truth
NetKingdom responsibility-map update Do in net-kingdom if/when user-engine becomes a shared platform service

13. First Implementation Slice

The smallest useful slice should be:

  1. Authenticate a request with a local IAM Profile fixture or local-identity.
  2. Link iss + sub to a user_id.
  3. Register one application.
  4. Register one catalog with a few profile/preference attributes.
  5. Store global and application profile values.
  6. Resolve an effective application profile projection.
  7. Authorize the read/update path through a pluggable flex-auth interface, using a local test adapter until flex-auth is wired.
  8. Emit audit and outbox events for every mutation.

This slice proves the product thesis without duplicating identity provider, MFA, authorization engine, UI, or deployment-platform responsibilities.