18 KiB
id, type, title, domain, status, version, created, updated, scope, workplan, related
| id | type | title | domain | status | version | created | updated | scope | workplan | related | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| netkingdom-user-engine-boundary-contract | standard | NetKingdom User Engine Boundary Contract v0.1 | netkingdom | accepted | 0.1 | 2026-05-22 | 2026-05-22 | user-domain-boundaries |
|
|
NetKingdom User Engine Boundary Contract v0.1
Purpose
This contract defines how user-engine integrates into the NetKingdom
landscape without duplicating IAM, authorization, application registration,
deployment, audit, or UI responsibilities.
user-engine owns user-domain facts and profile projections. NetKingdom owns
the cross-repo boundary contract. Implementations and adapters must preserve
the ownership rules below even when they use local fixtures for development or
standalone deployments.
Ownership Model
user-engine is a headless user-domain and profile service. It is not an
identity provider, MFA system, policy decision point, runtime secret store,
deployment engine, or UI repository.
| Concern | Owner | user-engine responsibility |
|---|---|---|
| OIDC discovery, login, token issuance | key-cape, Keycloak, or local-identity in dev |
Consume verified IAM Profile claims |
| Passwords, passkeys, sessions, MFA | IAM/MFA stack | No storage or lifecycle responsibility |
| Stable identity links | user-engine | Map (issuer, subject) to user_id |
| Account lifecycle and profile facts | user-engine | Canonical source of truth |
| Product memberships | user-engine unless explicitly imported | Own, validate, export as read models |
| Coarse authentication groups and roles | IAM provider normalized through the IAM Profile | Consume as actor facts |
| Fine-grained authorization | flex-auth |
Ask, enforce, and audit decisions |
| Runtime secrets | OpenBao/Railiance platform services | Consume scoped secret references through adapters |
| Deployment mechanics | Railiance and application repos | Publish requirements and readiness signals |
| Self-service/admin UI | future UI repos | Provide APIs and projections only |
Source-Of-Truth Matrix
| Resource kind | Source of truth | user-engine relation | Boundary rule |
|---|---|---|---|
| OIDC issuer and discovery metadata | IAM Profile implementation | Consume issuer metadata and JWKS through adapters | Never hardcode provider-specific paths where discovery is available |
| Login, session, MFA, and token lifecycle | key-cape, Keycloak, or local-identity in non-production |
Accept only verified claim envelopes | user-engine must not issue, refresh, or revoke tokens |
| Identity claims | IAM Profile implementation | Normalize into an actor envelope | Claims are authentication facts, not final authorization decisions |
| Human subject | IAM provider for authentication identity; user-engine for domain record | Link (issuer, subject) to user_id |
Email, username, and display name are mutable attributes, not keys |
| Local/bootstrap identities | local-identity |
Allowed only in local/test/standalone modes | Production adapters must reject local or loopback issuers |
| User record | user-engine | Canonical owner | Other systems may reference user_id but must not mutate the record directly |
| Account lifecycle | user-engine | Canonical owner | IAM disablement may trigger import/sync events, but user-engine records lifecycle state |
| Groups | IAM provider | Consume from claims or imports as identity facts | Groups do not overwrite user-engine-owned memberships |
| Coarse roles | IAM provider, normalized into roles |
Consume as actor facts for policy input | Roles are not user-engine resource ownership |
| Fine-grained roles, scopes, policies | flex-auth |
Register resources/actions and request decisions | user-engine does not interpret policy packages locally in production |
| Tenant identifiers | NetKingdom/IAM Profile contract | Store tenant-scoped records and memberships | Tenant admin authority never implies tenant:platform authority |
| Product memberships | user-engine unless an import contract says otherwise | Canonical owner for local facts | Every imported membership carries source, version, freshness, and delete semantics |
| External/provisioned memberships | Provisioning system under import contract | Store as externally mastered facts | user-engine may expose/read them but must not silently take ownership |
| Applications as profile consumers | user-engine | Own application record and allowed profile scopes | Does not replace IAM clients, protected systems, or deployments |
| OIDC clients | IAM provider | Store binding metadata only | Client secrets and redirect validation stay with IAM |
| Protected systems | flex-auth |
Store binding metadata and resource/action vocabulary reference | flex-auth remains PDP and protected-system registry owner |
| Catalog namespaces | user-engine | Canonical owner and validator | Namespaces bind to one owning application and version policy |
| Profile and preference values | user-engine | Canonical owner | Attribute definitions must resolve to a catalog namespace or governed global key |
| Effective-profile projections | user-engine | Canonical resolver and projection API | Projections are read models with version/freshness metadata |
| Claims enrichment inputs | IAM-side adapter | Optional profile read from user-engine | Adapter owns cache, freshness, and failure mode; login must not synchronously depend on user-engine |
| Runtime secrets and DB credentials | OpenBao/Railiance platform services | Consume logical secret names through SecretProvider |
Secret values must not be stored in profile/catalog records |
| Deployment metadata | Railiance/application repo | Store binding references where needed for onboarding | Railiance executes deployment and readiness mechanics |
| Authorization decisions | flex-auth |
Enforce returned decisions and obligations | Sensitive writes fail closed when decisions are unavailable |
| Local audit record | user-engine | Canonical owner for local mutation trail | Must carry correlation fields to decision and event records |
| Decision audit | flex-auth |
Store returned decision id | user-engine audit must link to the decision id where a check occurred |
| Platform audit sink | NetKingdom/Railiance audit service | Emit redacted summaries | Sensitive profile payloads are not exported by default |
| Domain events | user-engine outbox | Canonical source for user-domain lifecycle events | Events are durable after commit and carry schema/version identifiers |
Membership Synchronization Contract
Every membership fact that crosses a system boundary must carry this envelope:
| Field | Requirement |
|---|---|
membership_id |
Stable id for the fact in the owning system |
owner_system |
One of user-engine, iam, provisioning, or another explicit source |
source_system |
System that last supplied the fact |
subject_user_id |
user-engine user_id when resolved |
issuer and subject |
Original identity key when a user link is not yet resolved |
tenant |
Tenant context such as tenant:platform or tenant:coulomb |
scope_type |
tenant, application, team, catalog, or a contract extension |
scope_id |
Stable id inside the scope type |
relation |
Role, relation, or membership kind |
freshness |
Timestamp, version, sequence, or lease/expiry marker |
delete_semantics |
tombstone, disable, expire, or hard_delete_requested |
conflict_rule |
owner_wins, newer_version_wins, or an explicit manual-review rule |
correlation_id |
Request/import/export correlation id |
Allowed ownership classes:
| Class | Rule |
|---|---|
user_engine_mastered |
Created and mutated in user-engine; exported outward as read models only |
iam_imported_seed |
IAM group/role data may seed a local membership once, but does not continue overwriting it unless a contract says so |
externally_provisioned |
Provisioning source remains owner; user-engine stores the fact with source/version/delete semantics |
flex_auth_export |
user-engine exports subject facts to flex-auth for policy input; flex-auth does not become the membership store |
iam_export_requested |
Optional adapter-owned export for coarse IAM groups/claims; user-engine remains owner unless explicitly transferred |
Conflict handling:
- owner wins by default;
- non-owner updates are rejected or stored as pending import review;
- stale imports are ignored when their freshness marker is older than the current fact;
- cross-tenant imports must be rejected unless the import contract explicitly maps source tenant to target tenant;
- deletes from a non-owner source disable only that source's externally mastered fact and must not remove user-engine-owned memberships.
Freshness and invalidation:
- membership writes emit outbox events with a version stamp;
- exports to flex-auth carry the membership version used to build the subject fact;
- consumers must be able to tell whether an authorization decision used stale membership facts;
- high-risk membership changes invalidate request caches and short-lived decision caches.
Application Onboarding Contract
A platform application is represented by several records. They are bound together, but not merged into one ownership domain.
| Binding | Owner | Required fields |
|---|---|---|
| user-engine application | user-engine | application_id, display name, owner, allowed profile scopes, projection types, lifecycle state |
| IAM OIDC client | key-cape or Keycloak |
client id, issuer, redirect URIs, allowed scopes, assurance requirements |
| flex-auth protected system | flex-auth |
protected-system id, resource/action vocabulary, policy package binding |
| Catalog namespace | user-engine | namespace, owning application id, catalog id, versioning and deprecation policy |
| Deployment metadata | Railiance/application repo | environment, service name, tenant placement, ingress/readiness endpoints |
| Audit/event identity | user-engine plus platform sink | source application id, event subject prefix, correlation-id policy |
Minimum binding record:
application_id: string
tenant_scope: string
iam:
issuer: string
oidc_client_id: string
flex_auth:
protected_system_id: string
resource_vocabulary_version: string
catalog:
namespace: string
active_catalog_version: string
deployment:
environment: string
service_name: string
audit:
event_source: string
correlation_policy: required
Safe onboarding checklist:
- Register or approve the application owner and tenant scope.
- Create the IAM OIDC client with redirect URIs, scopes, and assurance requirements.
- Register the flex-auth protected system and policy package.
- Create the user-engine application record and bind the IAM/flex-auth ids.
- Register the catalog namespace and publish the first catalog version.
- Define projection types the application may request.
- Register event source and audit redaction rules.
- Record Railiance deployment metadata and readiness endpoints.
- Verify one authorized profile read, one denied profile read, one authorized mutation, one denied mutation, and correlated audit/event output.
Projection And Claims-Enrichment Boundaries
Projection types are distinct contracts:
| Projection type | Consumer | Required boundary |
|---|---|---|
self_service |
Current user | Includes only fields visible/editable by the subject under policy |
admin |
Tenant or platform admin tools | Requires flex-auth checks and tenant/platform authority separation |
application_runtime |
Registered applications | Limited to allowed profile scopes and catalog namespace bindings |
audit |
Operators and audit sinks | Redacted summaries with correlation metadata, not full sensitive payloads |
agent_context |
Autonomous or delegated agents | Policy-filtered context with actor/delegation evidence |
claims_enrichment |
IAM-side enrichment adapter | Optional, cache/freshness governed, and never token issuance itself |
Required projection metadata:
- projection type;
- target user id;
- tenant and application context;
- catalog/profile version stamps;
- redaction policy used;
- authorization decision id where a decision was needed;
- freshness timestamp;
- correlation id.
Claims enrichment rules:
- user-engine must not issue tokens;
- IAM owns token issuance and the enrichment adapter;
- enrichment adapters must define cache TTL, stale-read policy, and failure behavior;
- privileged or destructive login claims must not depend on stale profile enrichment;
- when user-engine is unavailable, the adapter either omits optional enriched claims or fails according to IAM-side policy, not user-engine policy.
Authorization Contract
user-engine is a policy enforcement point. flex-auth is the policy decision
point for production authorization decisions.
Minimum authorization request:
actor:
issuer: string
subject: string
tenant: string
principal_type: human | service | agent
roles: [string]
groups: [string]
scopes: [string]
assurance: object
resource:
type: string
id: string
action: string
context:
tenant: string
application_id: string | null
target_user_id: string | null
projection_type: string | null
correlation_id: string
Resource/action vocabulary:
| Resource | Baseline 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, import, export |
user-engine:application |
register, read, update, deactivate |
user-engine:catalog |
register, activate, deprecate, migrate |
user-engine:projection |
read, render, invalidate |
user-engine:audit |
read, export_summary |
Performance model:
- single sensitive writes use synchronous flex-auth checks and fail closed;
- list screens and bulk admin operations should use batch checks;
- request-scoped memoization is allowed for identical checks within one request;
- short-lived decision caches are allowed only for low-risk reads when the policy package permits caching and names invalidation events;
- local policy fixtures are allowed only for tests and standalone development;
- production adapters must record the flex-auth decision id or equivalent decision correlation.
Audit Correlation Contract
Every user-engine mutation and sensitive read must create or reference a correlation bundle:
| Field | Requirement |
|---|---|
correlation_id |
Stable id propagated across request, decision, audit, and event records |
request_id |
Transport/request id where available |
actor |
IAM Profile actor envelope or redacted service/agent equivalent |
tenant |
Tenant context for the action |
application_id |
Application context where applicable |
target_user_id |
Target user where applicable |
resource and action |
user-engine resource/action pair |
authorization_decision_id |
flex-auth decision id when an authorization check occurred |
user_engine_audit_id |
Local audit record id |
outbox_event_id |
Event id when a domain event is emitted |
redaction_policy |
Policy used to summarize sensitive fields |
change_summary |
Redacted mutation summary |
Platform audit sinks receive summaries. They must not receive full profile payloads, secret values, or catalog-sensitive values unless a future contract explicitly authorizes that export path.
user-engine Repo Readiness
The user-engine repository may start production-code implementation when these artifacts exist and remain aligned with this contract:
| Artifact | Required purpose | Current expected path |
|---|---|---|
| Scope boundary | State in/out-of-scope responsibilities | /home/worsch/user-engine/SCOPE.md |
| Architecture notes | Explain IAM, flex-auth, platform, UI, and deployment boundaries | /home/worsch/user-engine/wiki/ArchitectureBlueprint.md |
| Repo layout decision | Keep domain logic independent from transports and adapters | /home/worsch/user-engine/docs/development.md |
| Local development contract | Define standalone vs platform configuration and guardrails | /home/worsch/user-engine/docs/configuration.md |
| NetKingdom integration notes | Translate this contract into repo-local ports/adapters | /home/worsch/user-engine/docs/interfaces/netkingdom-integration.md |
| Implementation workplans | Carry implementation tasks in user-engine, not NetKingdom | /home/worsch/user-engine/workplans/USER-WP-0001 through USER-WP-0006 |
Readiness checklist:
- source-of-truth boundaries are documented before new stores are added;
- membership imports/exports identify owner, source, freshness, and delete semantics;
- application records bind, but do not own, IAM clients and flex-auth protected systems;
- projections include version/freshness and redaction metadata;
- claims enrichment is optional and adapter-owned;
- authorization ports can support synchronous, batch, memoized, and safe-cache modes;
- audit records can correlate with flex-auth decisions and outbox events;
- implementation work remains in user-engine workplans while NetKingdom keeps only boundary and orchestration responsibilities.