Files
govoplan-postbox/docs/POSTBOX_CONCEPT.md

343 lines
16 KiB
Markdown

# Postbox Concept
## Purpose
GovOPlaN Postbox provides in-platform postboxes that are addressable containers for messages, files, workflow evidence, and operational handoff. They can be used internally, exposed through portals, and connected to campaign workflows.
The key distinction from a mailbox is ownership. A mailbox is usually bound to
a login, user credential, or external mail account. A GovOPlaN postbox is a
durable communication and content-access container bound to institutional
context: primarily a function in an organizational unit, and where explicitly
needed a role, process, portal, campaign, or service responsibility. It may look
like an inbox for a message task or like a vault for content shared with the
current holders of that responsibility; neither form is owned by one account.
The strategic target is an encrypted administrative postbox. The first
implementation may start with ordinary persisted messages, but the model must
not prevent later end-to-end encryption, role/function key epochs, signed
manifests, external-recipient tokens, or honest retraction semantics. The
cross-module target architecture is recorded in
`govoplan-core/docs/POSTBOX_E2EE_ARCHITECTURE.md`.
## Function-Organization-Bound Access
The primary access pattern is a postbox linked to an organizational unit and
one or more institutional functions. A person can access that postbox while
their identity/account has an effective matching function assignment in that
organizational unit and their account may perform the requested Postbox action.
Opening a function postbox does not require mapping the function to an RBAC
role.
Example:
- Organizational unit: `District Office North`
- Required function: `Case Clerk`
- Postbox: `District Office North / Case Clerk Intake`
Any identity/account currently holding the `Case Clerk` function for `District
Office North` can see the postbox if it also satisfies the generic Postbox
permission and applicable policy. When the function assignment or delegation
is removed or expires, access disappears without moving messages or
reassigning a mailbox.
The postbox exists independently of its holders. It remains addressable while
the function is vacant and may accept durable deliveries according to policy;
the UI must then show that no current human holder can open or act on the
content. Assigning one or several incumbents grants access in their explicit
function context. It does not transfer ownership of the container or rewrite
its history.
This makes postboxes useful for responsibilities that outlive individuals:
- intake desks
- function-based service queues
- campaign sender or response desks
- portal message inboxes for organizational responsibilities
- file or evidence drops linked to a function in an organization
### Incumbency, hand-over, and delegation
- Zero, one, or several people may hold a function at the same time.
- A postbox can remain vacant without being deleted, redirected to a personal
account, or losing content.
- A new assignment can grant access to the function's permitted history through
a current key epoch. Which historical epochs a new incumbent receives is an
explicit postbox policy, not an accidental consequence of account creation.
- A delegation is a time-bounded access grant in the represented function
context. Expiry removes future platform key access and action authority; it
cannot destroy plaintext or exports already obtained.
- Hand-over and revocation rotate the function/postbox key epoch. Per-content
data keys should normally be rewrapped; policy may require content
re-encryption for a stronger rotation event.
- Stored content is not silently substituted or overwritten. A correction,
replacement, or new version is a new linked object with provenance while the
previous signed/ciphertext manifest remains governed by retention policy.
## Directory And Authorization Model
The normalized ownership boundary is:
- Organizations owns units, structures, function types, and concrete
functions.
- Identity owns identities and account links.
- IDM owns effective identity-to-function assignments, validity, delegation,
acting-for context, and assignment lifecycle facts.
- Core/Access authorizes generic Postbox actions.
- Postbox owns templates, stable addresses, containers, messages, routing,
visibility decisions, grouping preferences, and retention.
The Postbox module stores postbox bindings and postbox-specific decisions, but
it must not duplicate identity, organization, assignment, hierarchy, or RBAC
resolution.
The minimum authorization inputs are:
- postbox id
- tenant id
- organizational unit id
- required function id or function type id
- actor identity id
- current effective function assignments, delegations, and acting context from
IDM
- generic Postbox permissions from Core/Access
- optional explicit administrative grants for postbox administration
The expected result is a narrow access decision:
- can discover
- can read
- can send or reply
- can attach or link files
- can administer bindings
Access changes must be auditable because a person can gain or lose postbox
visibility through function-assignment changes rather than direct postbox
membership edits.
Runtime integration must use the kernel capabilities:
- `identity.directory` to resolve identities and account links.
- `idm.directory` to resolve effective function assignments.
- `organizations.directory` to resolve function, function-type, unit, and
hierarchy facts.
- the Core/Access permission evaluator for generic Postbox actions.
- access explanation/audit contracts to attach permission and acting-context
provenance where available.
Postbox must not import Identity, IDM, Organizations, or Access ORM models.
Acting-in-place access requires an explicit selected acting context. A function
assignment is an organizational responsibility fact; it does not grant
unrelated application permissions.
## Templates And Stable Addresses
A reusable Postbox template can target a function type and an organization
scope, such as a unit type, structure, or subtree. Postbox resolves a stable
unit-specific address from the tenant, template revision, concrete unit,
concrete function, and optional case/service context.
Addresses should be resolved lazily and idempotently rather than eagerly
creating empty containers for every unit. They remain durable through vacancy
and reassignment. A delivery snapshots the template revision and normalized
organization/function references so later hierarchy changes do not rewrite
history.
Exact postboxes remain useful for exceptional responsibilities that do not
belong to a reusable function type.
## Unified Inbox Projections
A user with several functions can group selected visible postboxes into named
unified inbox views and keep other responsibilities separate. Grouping is a
query projection only. It never merges source containers, messages, read or
acknowledgement state, retention, encryption keys, or audit evidence.
Every item and action continues to show the source function, unit, postbox,
assignment/delegation context, and classification. Policy may require some
postboxes to remain separate.
## Hierarchy Routing
Hierarchy behavior is disabled by default. The system distinguishes:
- a linked copy delivered to a parent function postbox
- attention or escalation metadata sent to a parent responsibility
- shared visibility over the original message
These have different privacy, retention, acknowledgement, and audit effects
and must not be treated as synonyms.
The first production slice should implement explicit linked-copy routing with
a selected structure, target function mapping, maximum depth, stop condition,
classification gate, loop protection, and delivery-time route snapshot.
Organization changes do not retroactively expose old messages.
Vacancy is a visible delivery/attention state rather than an automatic grant
to an unrelated personal account. Policy may trigger a bounded escalation
after a delay.
## Campaign Distribution
Campaign can use Postbox as an explicit delivery channel through
`postbox.delivery`. A campaign may select Mail, Postbox, both, or a configured
fallback order for a target. It must never switch channels silently.
Validation and build preview stable function/unit/context destinations,
vacancies, hierarchy-copy effects, classifications, and duplicates. Delivery
uses idempotency keys and returns per-target evidence. Postbox owns acceptance,
routing, message state, read/acknowledgement state, and postbox ids; Campaign
owns campaign preparation, jobs, recipient reports, and channel-attempt
evidence.
## Domain Objects
The initial domain model should stay small:
- `PostboxTemplate` and immutable revisions: reusable function/scope
configuration.
- `PostboxAddress`: the stable tenant/function/unit/context destination.
- `Postbox`: the addressable container, materialized when needed.
- `PostboxBinding`: the binding to organization, role, portal, campaign, service, or explicit context.
- `PostboxMessage`: a platform-native message or message reference.
- `PostboxParticipant`: normalized sender, recipient, author, or actor reference.
- `PostboxAttachmentRef`: reference to a file, evidence item, generated campaign artifact, or external attachment.
- `PostboxDelivery` and `PostboxRoute`: idempotent producer acceptance and
linked copy/escalation provenance.
- `PostboxGrouping`: a per-user source-preserving inbox projection.
- `PostboxAccessEvent`: auditable record of access-affecting changes and sensitive actions.
Messages and files should be linked by stable ids and typed references. The postbox module should not import file, mail, or campaign internals.
## Capability Boundaries
Postbox should expose narrow capabilities through core:
- `postbox.directory`: find postboxes visible to an actor.
- `postbox.access`: answer access decisions for a postbox/action pair.
- `postbox.messages`: create, list, and read postbox messages through DTOs.
- `postbox.delivery`: accept messages or delivery artifacts from other modules.
- `postbox.evidence`: link durable evidence references without owning the evidence store.
Optional consumers:
- Campaign can use postboxes for function-targeted delivery, sender context,
reply intake, review queues, and access to campaign artifacts.
- Files can expose file references to a postbox when the actor has effective
source-postbox access.
- Portal can show portal-facing postboxes without owning the postbox access model.
- Mail can bridge external mailbox delivery into postboxes when configured, without making postboxes mailbox-bound.
## Operational Rules
- Current function assignment and delegation state controls current access.
- Historical message records remain durable even when no current person holds
the function; vacancy is a visible attention/access state, not a missing
postbox.
- Multiple incumbents receive independent device-bound key grants and remain
distinguishable in access and action evidence.
- Delegation start, expiry, withdrawal, key grant, and key-epoch rotation are
separate auditable events.
- Administration of bindings should require explicit postbox administration permission plus access/RBAC authority for the target organization.
- Sensitive access decisions and binding changes should emit audit events.
- Retention rules should be postbox-owned but able to reference campaign, file, and portal provenance.
- Expiry, withdrawal, and retraction UI must distinguish future access control
from already fetched or decrypted plaintext.
- Message metadata should preserve room for ciphertext manifests, wrapped keys,
key epochs, recipient device references, and external capability tokens even
before full E2EE ships.
### Retention, Audit, And Privacy
Postbox retention is owned by the postbox module because postbox messages are
platform-native communication records, not mailbox folders and not ordinary file
shares. Retention policies may reference provenance from campaign, file, portal,
mail, or workflow modules, but those modules should pass stable ids and typed
evidence references through capabilities instead of giving postbox direct access
to their internals.
The postbox module should emit audit events for:
- postbox creation, archival, and destructive retirement
- binding creation, changes, expiry, and removal
- sensitive access checks when an actor gains or loses visibility
- message creation, read/download of sensitive content, attachment linking, and
delivery handoff
- retention holds, retention expiry, export, and destruction decisions
Privacy behavior must separate current access from historical evidence. Losing
a function assignment or generic Postbox permission removes future visibility,
but it does not rewrite the fact that a person previously accessed a message or
that a message existed. Deletion and destructive retention actions must
preserve legally required audit/evidence records while removing or redacting
content according to the effective policy.
When E2EE is enabled later, retention and audit metadata must remain operable
without decrypting message content. UI copy should be honest: expiry,
withdrawal, or revocation can prevent future platform access, but it cannot
guarantee removal of plaintext already fetched, exported, printed, or delivered
outside the platform.
### Migration And Compatibility Ownership
Postbox-owned tables, DTOs, migrations, and capability names belong in
`govoplan-postbox`. Core may temporarily contain compatibility imports or
legacy migration references only when needed to keep existing installations
upgradable while code is being extracted.
Compatibility code must be narrow and documented:
- new postbox behavior is implemented in `govoplan-postbox`
- old import paths may re-export postbox DTOs or helpers during a transition,
but must not become active owners of postbox logic
- migrations that move tables to postbox ownership must preserve existing data
and have explicit downgrade/retirement notes
- optional integrations with campaign, files, portal, or mail remain capability
contracts, not direct imports
Once supported release migrations have crossed the compatibility window, legacy
core import aliases and old table ownership comments should be removed through
a normal cleanup issue.
## First Implementation Shape
The first implementation should define the backend manifest, permissions, DTOs, and migrations before building rich UI. A minimal API can then support directory lookup, access checks, message creation, message listing, and binding administration.
The WebUI should start as an administration and inbox surface:
- postbox directory
- function-bound access explanation
- message list and message detail
- template and binding editor for organization/function links
- audit-visible administrative actions
Campaign, files, portal, and mail behavior should arrive as optional integrations after the core postbox model is stable.
## E2EE Readiness Checklist
Before the data model is considered stable, verify that it can represent:
- message or attachment ciphertext references
- signed manifest references
- recipient, role, or function key wrapping records
- key epoch and device-key references
- key-fetch/access audit events
- external recipient token state
- expiry and withdrawal state separate from deletion
- retention state that can operate without decrypting content
## E2EE decisions still to settle before implementation
The product direction above is selected, but the first trusted profile still
needs bounded decisions on:
- whether a new incumbent receives all retained history, history from a
policy-defined date, or only content delivered during the assignment;
- organizational recovery/escrow and the authority required when every holder
loses all registered device keys;
- whether ordinary rotation only rewraps per-content keys or also re-encrypts
ciphertext, and which events require the stronger path;
- assurance and quorum requirements for delegation, hand-over, emergency
access, export, and destructive retention; and
- how attention/escalation works during a vacancy without granting plaintext
access to an unrelated personal account.