Seed postbox workflow and concept docs

This commit is contained in:
2026-07-07 20:43:20 +02:00
commit 3e4d945b70
12 changed files with 768 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
---
name: "Bug"
about: "Report a reproducible defect, regression, or incorrect behavior"
title: "[Bug] "
labels:
- type/bug
- status/triage
- module/postbox
---
## Scope
- Repository:
- Area/module:
- Affected version or commit:
## Behavior
Expected:
Actual:
## Reproduction
1.
2.
3.
## Evidence
Logs, screenshots, traces, or failing test output:
## Verification Target
Command or workflow that should pass when fixed:

View File

@@ -0,0 +1 @@
blank_issues_enabled: false

View File

@@ -0,0 +1,27 @@
---
name: "Docs / workflow"
about: "Request documentation, process, or developer workflow changes"
title: "[Docs] "
labels:
- type/docs
- status/triage
- module/postbox
- area/docs
---
## Scope
- Repository:
- Document or workflow:
## Current State
What is missing, unclear, duplicated, or stale?
## Desired State
What should the docs or workflow make clear?
## Verification Target
How should this be checked?

View File

@@ -0,0 +1,32 @@
---
name: "Feature"
about: "Propose new user-visible behavior or platform capability"
title: "[Feature] "
labels:
- type/feature
- status/triage
- module/postbox
---
## Problem
What user, operator, or developer problem should this solve?
## Proposed Capability
What should exist when this is done?
## Ownership
- Owning repository:
- Related module repositories:
- Extension point or integration boundary:
## Acceptance Criteria
- [ ]
- [ ]
## Verification Target
Command, scenario, or UI flow that should prove completion:

View File

@@ -0,0 +1,28 @@
---
name: "Task"
about: "Track implementation, maintenance, or migration work"
title: "[Task] "
labels:
- type/task
- status/triage
- module/postbox
---
## Objective
What needs to be completed?
## Scope
- Owning repository:
- In-scope:
- Out-of-scope:
## Checklist
- [ ]
- [ ]
## Verification Target
Command or manual check:

View File

@@ -0,0 +1,25 @@
---
name: "Tech debt"
about: "Track cleanup, refactoring, risk reduction, or deferred engineering work"
title: "[Debt] "
labels:
- type/debt
- status/triage
- module/postbox
---
## Current Cost
What does this make harder, riskier, slower, or more fragile?
## Desired Shape
What should the code, tests, or architecture look like afterwards?
## Constraints
What behavior, compatibility, or module boundary must be preserved?
## Verification Target
Focused checks that should pass:

View File

@@ -0,0 +1,15 @@
## Issue
Closes #
## Summary
-
## Verification
-
## Notes
Follow-up issues:

31
AGENTS.md Normal file
View File

@@ -0,0 +1,31 @@
# GovOPlaN Postbox Codex Guide
## Scope
This repository owns the `postbox` module: in-platform postboxes, role-organization-bound access, postbox messages, postbox directory APIs, internal and portal postbox surfaces, campaign postbox integration, postbox-owned migrations, and future `@govoplan/postbox-webui`.
Postboxes are not login-bound mailboxes. They are platform-owned communication and access containers whose visibility is derived from organizational role assignments, explicit postbox bindings, and capability contracts.
## Local Commands
Install and run through core:
```bash
cd /mnt/DATA/git/govoplan-core
./.venv/bin/python -m pip install -r requirements-dev.txt
```
For combined checks once implementation starts, run:
```bash
cd /mnt/DATA/git/govoplan-core
./scripts/check-focused.sh
```
## Working Rules
- Keep postbox behavior in this module, not core.
- Derive role-organization access through core/access contracts; do not duplicate RBAC membership logic locally.
- Do not import mail, files, campaign, or portal internals. Use manifests, capabilities, events, API routes, and typed DTOs.
- Treat postbox access changes as auditable security events, especially when access changes because a role assignment changes.
- Keep campaign delivery, file evidence, and portal usage optional behind capability boundaries.

40
README.md Normal file
View File

@@ -0,0 +1,40 @@
# govoplan-postbox
GovOPlaN Postbox provides platform-owned postboxes for internal work, portals, campaign flows, and role-bound organizational communication.
## Ownership
This repository owns:
- backend module manifest `postbox`
- postbox permissions and policy checks
- postbox, binding, message, participant, attachment-reference, and audit-facing data models
- role-organization-bound access resolution for postboxes
- API routes for postbox directory, messages, access checks, and administration
- optional integration capabilities for campaign, files, portal, notification, and mail-facing workflows
- future WebUI package `@govoplan/postbox-webui`
Core owns auth, tenants, RBAC evaluation, database/session primitives, module discovery, migrations, CSRF/API helpers, and shell layout. Access owns identities, users, groups, roles, memberships, and administrative RBAC surfaces.
## Role-bound postboxes
A role-bound postbox is linked to an organizational unit and one or more roles. A person can access that postbox while their identity has an effective matching role in that organizational unit. Access is not tied to a login mailbox, personal email address, or static user assignment.
When the role assignment changes, postbox access changes with it. The postbox keeps durable message and evidence history, while authorization remains derived from current platform role state.
## Module integration
Backend entry point:
```toml
[project.entry-points."govoplan.modules"]
postbox = "govoplan_postbox.backend.manifest:get_manifest"
```
Frontend package:
```text
@govoplan/postbox-webui
```
Platform RBAC, module capability contracts, and governance rules are documented in `govoplan-core/docs/`.

27
docs/POSTBOX_BACKLOG.md Normal file
View File

@@ -0,0 +1,27 @@
# Postbox Backlog
## P1 Immediate
- [ ] Define the `postbox` backend manifest, permissions, module metadata, and capability names.
- [ ] Design the postbox, binding, message, participant, attachment-reference, and audit-event data model.
- [ ] Implement role-organization-bound access checks through core/access contracts.
- [ ] Add API DTOs and routes for postbox directory, access checks, message listing, message creation, and binding administration.
- [ ] Create focused tests for access changes when role assignments are granted, revoked, or expire.
## P2 Module Integration
- [ ] Define optional campaign integration for sender context, response intake, and artifact handoff.
- [ ] Define optional files integration for postbox-visible file and evidence references.
- [ ] Define optional portal integration for portal-facing role-bound postboxes.
- [ ] Define optional mail bridge semantics without making postboxes login-bound mailboxes.
## P2 WebUI
- [ ] Build the postbox administration route contribution and navigation metadata.
- [ ] Build an inbox view for visible postboxes, messages, and role-bound access explanation.
- [ ] Build a binding editor for organization and role links with audit-visible changes.
## P3 Governance
- [ ] Document retention, audit, and privacy rules for postbox messages and evidence references.
- [ ] Document migration ownership and compatibility imports while postbox code is extracted from core if needed.

103
docs/POSTBOX_CONCEPT.md Normal file
View File

@@ -0,0 +1,103 @@
# 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 bound to platform context: organization, role, process, portal, campaign, or service responsibility.
## Role-Organization-Bound Access
The special access pattern is a postbox linked to an organizational unit and one or more roles. A person can access that postbox while their identity has an effective matching role in that organizational unit.
Example:
- Organizational unit: `District Office North`
- Required role: `Case Clerk`
- Postbox: `District Office North / Case Clerk Intake`
Any identity currently holding the `Case Clerk` role for `District Office North` can see the postbox. When the role is removed or expires, access disappears without moving messages or reassigning a mailbox.
This makes postboxes useful for responsibilities that outlive individuals:
- intake desks
- role-based service queues
- campaign sender or response desks
- portal message inboxes for organizational responsibilities
- file or evidence drops linked to a role in an organization
## Authorization Model
Postbox authorization should be derived from access-owned identity and role data through core/access contracts. The postbox module stores postbox bindings and postbox-specific permissions, but it should not duplicate membership, group, or role resolution.
The minimum authorization inputs are:
- postbox id
- tenant id
- organizational unit id
- required role id or role key
- actor identity id
- current effective role assignments from the access module
- 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 role assignment changes rather than direct postbox membership edits.
## Domain Objects
The initial domain model should stay small:
- `Postbox`: the addressable container.
- `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.
- `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 campaign sender context, reply intake, review queues, and role-bound access to campaign artifacts.
- Files can expose file references to a postbox when the actor's role grants 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 role state controls current access.
- Historical message records remain durable even when no current person holds the role.
- 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.
## 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
- role-bound access explanation
- message list and message detail
- binding editor for organization and role links
- audit-visible administrative actions
Campaign, files, portal, and mail behavior should arrive as optional integrations after the core postbox model is stable.

404
docs/gitea-labels.json Normal file
View File

@@ -0,0 +1,404 @@
[
{
"name": "type/bug",
"color": "d73a4a",
"description": "A reproducible defect, regression, or incorrect behavior.",
"exclusive": true
},
{
"name": "type/feature",
"color": "0e8a16",
"description": "New user-visible behavior or platform capability.",
"exclusive": true
},
{
"name": "type/task",
"color": "1d76db",
"description": "Implementation, maintenance, migration, or operational work.",
"exclusive": true
},
{
"name": "type/debt",
"color": "fbca04",
"description": "Cleanup, refactoring, risk reduction, or deferred engineering work.",
"exclusive": true
},
{
"name": "type/docs",
"color": "5319e7",
"description": "Documentation, process, or developer workflow work.",
"exclusive": true
},
{
"name": "priority/p0",
"color": "b60205",
"description": "Immediate stop-the-line priority.",
"exclusive": true
},
{
"name": "priority/p1",
"color": "d93f0b",
"description": "High priority for the next focused work window.",
"exclusive": true
},
{
"name": "priority/p2",
"color": "fbca04",
"description": "Normal planned priority.",
"exclusive": true
},
{
"name": "priority/p3",
"color": "c2e0c6",
"description": "Low priority or opportunistic cleanup.",
"exclusive": true
},
{
"name": "status/triage",
"color": "d4c5f9",
"description": "Needs review, ownership, priority, or acceptance criteria.",
"exclusive": true
},
{
"name": "status/ready",
"color": "0e8a16",
"description": "Ready for implementation.",
"exclusive": true
},
{
"name": "status/in-progress",
"color": "0052cc",
"description": "Currently being worked.",
"exclusive": true
},
{
"name": "status/blocked",
"color": "b60205",
"description": "Cannot progress without a decision, dependency, credential, or external change.",
"exclusive": true
},
{
"name": "status/needs-info",
"color": "f9d0c4",
"description": "Needs clarifying input before implementation can proceed safely.",
"exclusive": true
},
{
"name": "module/access",
"color": "0e8a16",
"description": "GovOPlaN access, identity, authentication, RBAC, and administration behavior.",
"exclusive": false
},
{
"name": "module/addresses",
"color": "5319e7",
"description": "GovOPlaN Addresses module behavior or integration.",
"exclusive": false
},
{
"name": "module/admin",
"color": "006b75",
"description": "GovOPlaN Admin module behavior or integration.",
"exclusive": false
},
{
"name": "module/appointments",
"color": "d876e3",
"description": "GovOPlaN Appointments module behavior or integration.",
"exclusive": false
},
{
"name": "module/audit",
"color": "0e8a16",
"description": "GovOPlaN Audit module behavior or integration.",
"exclusive": false
},
{
"name": "module/calendar",
"color": "bfd4f2",
"description": "GovOPlaN Calendar module behavior or integration.",
"exclusive": false
},
{
"name": "module/campaign",
"color": "d876e3",
"description": "GovOPlaN campaign module behavior or integration.",
"exclusive": false
},
{
"name": "module/cases",
"color": "1d76db",
"description": "GovOPlaN Cases module behavior or integration.",
"exclusive": false
},
{
"name": "module/connectors",
"color": "c2e0c6",
"description": "GovOPlaN Connectors module behavior or integration.",
"exclusive": false
},
{
"name": "module/core",
"color": "0052cc",
"description": "GovOPlaN core runner, shared primitives, shell, or extension points.",
"exclusive": false
},
{
"name": "module/dms",
"color": "c5def5",
"description": "GovOPlaN Dms module behavior or integration.",
"exclusive": false
},
{
"name": "module/erp",
"color": "fef2c0",
"description": "GovOPlaN Erp module behavior or integration.",
"exclusive": false
},
{
"name": "module/files",
"color": "006b75",
"description": "GovOPlaN files module behavior or integration.",
"exclusive": false
},
{
"name": "module/fit-connect",
"color": "fbca04",
"description": "GovOPlaN Fit Connect module behavior or integration.",
"exclusive": false
},
{
"name": "module/forms",
"color": "f9d0c4",
"description": "GovOPlaN Forms module behavior or integration.",
"exclusive": false
},
{
"name": "module/identity-trust",
"color": "d4c5f9",
"description": "GovOPlaN Identity Trust module behavior or integration.",
"exclusive": false
},
{
"name": "module/idm",
"color": "0052cc",
"description": "GovOPlaN Idm module behavior or integration.",
"exclusive": false
},
{
"name": "module/ledger",
"color": "5319e7",
"description": "GovOPlaN Ledger module behavior or integration.",
"exclusive": false
},
{
"name": "module/mail",
"color": "5319e7",
"description": "GovOPlaN mail module behavior or integration.",
"exclusive": false
},
{
"name": "module/notifications",
"color": "d876e3",
"description": "GovOPlaN Notifications module behavior or integration.",
"exclusive": false
},
{
"name": "module/ops",
"color": "0e8a16",
"description": "GovOPlaN Ops module behavior or integration.",
"exclusive": false
},
{
"name": "module/payments",
"color": "bfd4f2",
"description": "GovOPlaN Payments module behavior or integration.",
"exclusive": false
},
{
"name": "module/policy",
"color": "d93f0b",
"description": "GovOPlaN Policy module behavior or integration.",
"exclusive": false
},
{
"name": "module/postbox",
"color": "006b75",
"description": "GovOPlaN postbox module behavior or integration.",
"exclusive": false
},
{
"name": "module/portal",
"color": "1d76db",
"description": "GovOPlaN Portal module behavior or integration.",
"exclusive": false
},
{
"name": "module/reporting",
"color": "c2e0c6",
"description": "GovOPlaN Reporting module behavior or integration.",
"exclusive": false
},
{
"name": "module/search",
"color": "bfdadc",
"description": "GovOPlaN Search module behavior or integration.",
"exclusive": false
},
{
"name": "module/scheduling",
"color": "d93f0b",
"description": "GovOPlaN Scheduling module behavior or integration.",
"exclusive": false
},
{
"name": "module/tasks",
"color": "c5def5",
"description": "GovOPlaN Tasks module behavior or integration.",
"exclusive": false
},
{
"name": "module/templates",
"color": "fef2c0",
"description": "GovOPlaN Templates module behavior or integration.",
"exclusive": false
},
{
"name": "module/tenancy",
"color": "e4e669",
"description": "GovOPlaN Tenancy module behavior or integration.",
"exclusive": false
},
{
"name": "module/web",
"color": "bfd4f2",
"description": "GovOPlaN public website, product page, or publication content.",
"exclusive": false
},
{
"name": "module/workflow",
"color": "f9d0c4",
"description": "GovOPlaN Workflow module behavior or integration.",
"exclusive": false
},
{
"name": "module/xoev",
"color": "d4c5f9",
"description": "GovOPlaN Xoev module behavior or integration.",
"exclusive": false
},
{
"name": "module/xrechnung",
"color": "0052cc",
"description": "GovOPlaN Xrechnung module behavior or integration.",
"exclusive": false
},
{
"name": "module/xta-osci",
"color": "5319e7",
"description": "GovOPlaN Xta Osci module behavior or integration.",
"exclusive": false
},
{
"name": "area/auth",
"color": "bfd4f2",
"description": "Authentication, sessions, access bootstrap, or login behavior.",
"exclusive": false
},
{
"name": "area/tenancy",
"color": "bfdadc",
"description": "Tenant boundaries, provisioning, or tenant-scoped data behavior.",
"exclusive": false
},
{
"name": "area/rbac",
"color": "c5def5",
"description": "Permissions, roles, delegation, or authorization policy.",
"exclusive": false
},
{
"name": "area/governance",
"color": "fef2c0",
"description": "Governance policy, audit, privacy, retention, or compliance behavior.",
"exclusive": false
},
{
"name": "area/module-system",
"color": "bfe5bf",
"description": "Module discovery, manifests, capabilities, routing, or optional integrations.",
"exclusive": false
},
{
"name": "area/migrations",
"color": "e4e669",
"description": "Alembic migrations, schema bootstrap, or persistence evolution.",
"exclusive": false
},
{
"name": "area/webui",
"color": "1d76db",
"description": "Shared WebUI shell, frontend components, routing, or frontend tests.",
"exclusive": false
},
{
"name": "area/api",
"color": "5319e7",
"description": "HTTP API contracts, routers, schemas, or API smoke behavior.",
"exclusive": false
},
{
"name": "area/db",
"color": "0e8a16",
"description": "Database sessions, models, transactions, or persistence primitives.",
"exclusive": false
},
{
"name": "area/devex",
"color": "bfd4f2",
"description": "Local developer workflow, scripts, tests, tooling, or release helpers.",
"exclusive": false
},
{
"name": "area/release",
"color": "c2e0c6",
"description": "Versioning, release locks, tags, packaging, or dependency pins.",
"exclusive": false
},
{
"name": "area/docs",
"color": "5319e7",
"description": "Durable documentation and project guidance.",
"exclusive": false
},
{
"name": "area/marketing",
"color": "f9d0c4",
"description": "Public website, product messaging, publication copy, or legal page content.",
"exclusive": false
},
{
"name": "source/todo-scan",
"color": "cccccc",
"description": "Imported from inline TODO/FIXME/HACK markers by the Gitea TODO importer.",
"exclusive": false
},
{
"name": "source/backlog-import",
"color": "bfdadc",
"description": "Imported from markdown backlog, roadmap, plan, or TODO files.",
"exclusive": false
},
{
"name": "codex/ready",
"color": "0e8a16",
"description": "Suitable for Codex to pick up with the existing issue context.",
"exclusive": false
},
{
"name": "codex/needs-human",
"color": "f9d0c4",
"description": "Needs an explicit human decision before Codex should implement.",
"exclusive": false
}
]