generated from coulomb/repo-seed
Implement durable store contract and registration roadmap
This commit is contained in:
@@ -7,20 +7,141 @@ adapters without changing domain code.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from contextlib import AbstractContextManager
|
||||
from typing import Any, Iterable, Mapping, Protocol
|
||||
|
||||
from user_engine.domain import (
|
||||
Account,
|
||||
Actor,
|
||||
Application,
|
||||
ApplicationBinding,
|
||||
AuditRecord,
|
||||
AuthorizationDecision,
|
||||
AuthorizationRequest,
|
||||
CanonEntityReference,
|
||||
Catalog,
|
||||
ExternalIdentity,
|
||||
FamilyInvitation,
|
||||
Membership,
|
||||
OutboxEvent,
|
||||
ProfileValue,
|
||||
TenantAccount,
|
||||
User,
|
||||
)
|
||||
|
||||
|
||||
class UserEngineStore(Protocol):
|
||||
"""Durable persistence boundary for user-engine service behavior.
|
||||
|
||||
Implementations may be in-memory, Postgres-backed, or platform-provided,
|
||||
but must preserve the same logical keys, readiness contract, and atomic
|
||||
mutation semantics exposed here.
|
||||
"""
|
||||
|
||||
schema_version: str | None
|
||||
|
||||
@property
|
||||
def ready(self) -> bool:
|
||||
"""Return whether the store is schema-compatible for service use."""
|
||||
|
||||
def migrate(self) -> None:
|
||||
"""Apply or verify user-engine-owned schema migrations."""
|
||||
|
||||
def transaction(self) -> AbstractContextManager[None]:
|
||||
"""Return a context manager for one atomic mutation unit."""
|
||||
|
||||
def save_user(self, user: User) -> None:
|
||||
"""Create or replace a user record."""
|
||||
|
||||
def user(self, user_id: str) -> User | None:
|
||||
"""Return a user by id."""
|
||||
|
||||
def save_account(self, account: Account) -> None:
|
||||
"""Create or replace a primary account record."""
|
||||
|
||||
def user_account(self, user_id: str) -> Account | None:
|
||||
"""Return the primary account for a user."""
|
||||
|
||||
def save_identity(self, identity: ExternalIdentity) -> None:
|
||||
"""Create or replace an external identity link."""
|
||||
|
||||
def find_identity(self, issuer: str, subject: str) -> ExternalIdentity | None:
|
||||
"""Return an external identity by issuer and subject."""
|
||||
|
||||
def identities_for_user(self, user_id: str) -> tuple[ExternalIdentity, ...]:
|
||||
"""Return all external identities linked to a user."""
|
||||
|
||||
def save_tenant_account(self, account: TenantAccount) -> None:
|
||||
"""Create or replace a tenant-scoped account record."""
|
||||
|
||||
def tenant_account(self, tenant: str, user_id: str) -> TenantAccount | None:
|
||||
"""Return a tenant-scoped account record."""
|
||||
|
||||
def save_membership(self, membership: Membership) -> None:
|
||||
"""Create or replace a membership fact."""
|
||||
|
||||
def memberships_for_user(
|
||||
self, user_id: str, *, tenant: str | None = None
|
||||
) -> tuple[Membership, ...]:
|
||||
"""Return memberships for a user, optionally scoped to a tenant."""
|
||||
|
||||
def memberships_for_tenant(self, tenant: str) -> tuple[Membership, ...]:
|
||||
"""Return memberships scoped to a tenant."""
|
||||
|
||||
def save_application(self, application: Application) -> None:
|
||||
"""Create or replace an application registration."""
|
||||
|
||||
def application(self, application_id: str) -> Application | None:
|
||||
"""Return an application by id."""
|
||||
|
||||
def save_binding(self, binding: ApplicationBinding) -> None:
|
||||
"""Create or replace an application binding."""
|
||||
|
||||
def binding(self, application_id: str) -> ApplicationBinding | None:
|
||||
"""Return an application binding by application id."""
|
||||
|
||||
def save_catalog(self, catalog: Catalog) -> None:
|
||||
"""Create or replace a catalog."""
|
||||
|
||||
def catalog(self, catalog_id: str) -> Catalog | None:
|
||||
"""Return a catalog by id."""
|
||||
|
||||
def all_catalogs(self) -> tuple[Catalog, ...]:
|
||||
"""Return all catalogs."""
|
||||
|
||||
def save_family_invitation(self, invitation: FamilyInvitation) -> None:
|
||||
"""Create or replace a family invitation."""
|
||||
|
||||
def family_invitation(self, invitation_id: str) -> FamilyInvitation | None:
|
||||
"""Return a family invitation by id."""
|
||||
|
||||
def family_invitations_for_user(
|
||||
self, user_id: str
|
||||
) -> tuple[FamilyInvitation, ...]:
|
||||
"""Return family invitations for a user."""
|
||||
|
||||
def save_profile_value(self, value: ProfileValue) -> None:
|
||||
"""Create or replace a profile value."""
|
||||
|
||||
def values_for_user(self, user_id: str) -> tuple[ProfileValue, ...]:
|
||||
"""Return profile values for a user."""
|
||||
|
||||
def append_audit(self, record: AuditRecord) -> None:
|
||||
"""Append a local audit record."""
|
||||
|
||||
def audit_log(self) -> tuple[AuditRecord, ...]:
|
||||
"""Return local audit records in write order."""
|
||||
|
||||
def append_outbox(self, event: OutboxEvent) -> None:
|
||||
"""Append an outbox event."""
|
||||
|
||||
def pending_outbox(self) -> tuple[OutboxEvent, ...]:
|
||||
"""Return pending outbox events in write order."""
|
||||
|
||||
def record_counts(self) -> Mapping[str, int]:
|
||||
"""Return adapter-neutral record counts for diagnostics."""
|
||||
|
||||
|
||||
class IdentityClaimsAdapter(Protocol):
|
||||
"""Normalize verified identity claims into a user-engine actor."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user