1
Repo docs ADDRESS MODULE ARCHITECTURE
Albrecht Degering edited this page 2026-07-13 18:09:26 +02:00

Mirrored from /mnt/DATA/git/govoplan-addresses/docs/ADDRESS_MODULE_ARCHITECTURE.md. Origin: repository. Active tasks and changing state belong in Gitea issues; this wiki page is durable project context.


GovOPlaN Addresses Module Architecture

Decision

govoplan-addresses owns reusable contact and recipient-source data. Campaigns, mail, scheduling, portal, postbox, forms, reporting, and other modules consume address data through core-mediated capabilities and APIs, not by importing address-module internals.

The implementation reference for contact data is vCard. CardDAV is the primary address-book sync protocol. LDAP/Active Directory, Exchange/Microsoft 365, Google Contacts, CSV/XLSX, LDIF, and batch vCard import/export are connector targets layered on top of the same local model and sync contracts.

Ownership

govoplan-addresses owns:

  • scoped address books
  • contacts, organizations, households, and postal/email/phone address data
  • vCard import/export and vCard-compatible field mapping
  • reusable recipient sources and classical address lists
  • contact tags, categories, communication preferences, consent, and legal basis
  • deduplication, merge, address quality checks, and suppression lists
  • contact provenance, audit history, soft delete, and restore
  • external-source bindings, sync state, conflicts, and read-only source markers

It does not own:

  • campaign-local recipient snapshots and evidence
  • mail transport, mailbox access, or delivery queues
  • calendar events or iCalendar event storage
  • global identity authentication or authorization decisions
  • organization structure or internal function assignments
  • operational distribution lists/Verteiler with mixed users, identities, groups, functions, roles, raw recipients, and nested lists

Scopes

Address books can live in these scopes:

  • user: personal address books and remembered contacts
  • group: team/shared address books
  • tenant: tenant-wide directories and approved shared lists
  • system: platform-wide public/shared directories where policy allows it

The scope determines visibility, default permissions, sync credentials, and whether downstream modules may reuse or mutate entries.

Data Model Principles

The canonical model should preserve enough vCard semantics to round-trip common fields:

  • name components and formatted names
  • nicknames and display names
  • email addresses, phone numbers, postal addresses, URLs, notes, categories
  • organizations, titles, roles, departments, and relationships
  • birthday/anniversary where allowed by policy
  • photos/avatars where storage and privacy policy allow them
  • calendar or scheduling addresses where present
  • source IDs, revisions, ETags, sync tokens, and provenance

The model should support both normalized query fields and a preserved original representation for import/export and conflict handling.

The local baseline implements scoped address books, contacts, normalized email/phone/postal-address tables, tags, source kind/reference fields, first-class source payload/revision fields, and provenance JSON. Imported vCards preserve raw source payload and revision metadata for audit/debugging and later conflict workflows. External sync conflict tables and resolution UI remain part of the sync milestones.

Capabilities

The first stable capabilities are:

  • addresses.recipient_source: return immutable recipient snapshots for campaigns, forms, reporting, and other send/build workflows.
  • addresses.lookup: provide read-only lookup and autocomplete for mail, campaign, scheduling, postbox, portal, and case workflows.
  • addresses.contact_writer: provide address-book-scoped write target decisions and contact creation for local or otherwise writable sources.

Capabilities use DTOs and source IDs. Consumers must not receive ORM objects or write address tables directly. Consumers that need historical evidence must store their own immutable snapshot with source ID, source revision, and provenance; they must not treat live address records as historical evidence.

addresses.recipient_source exposes both complete address books and classical address lists. Address-book sources use addresses:address_book:<id>. Address-list sources use addresses:address_list:<id> and include the address-list entry ID in each recipient's provenance. The current snapshot DTO is email-recipient oriented; postal-only list entries are valid address-list members but are skipped by the email recipient-source path until postal recipient DTOs are added.

The writer capability is intentionally address-book specific. It answers whether the current principal may perform an operation such as create_contact, update_contact, or delete_contact against a concrete address book. The decision payload includes:

  • allowed
  • stable reason
  • user-facing message
  • required scopes
  • source kind
  • read-only state
  • scope and tenant provenance

Policy modules or connector sync state may later add inputs to this decision, but consumers must continue to call the address capability/API instead of importing policy logic or address services directly. Disabled or read-only UI actions should surface the returned message on hover.

Sync Model

Every synced address book should track:

  • connector type and external account/source
  • external address-book ID and display name
  • local address-book scope
  • sync direction: read-only, one-way import, one-way export, two-way
  • sync token, ETag/revision, last successful sync, last attempted sync
  • deleted markers/tombstones
  • conflict status and resolution decision
  • connector diagnostics and rate-limit/backoff state

Sync conflict UX must show the local value, remote value, source, timestamp, and available action. Silent overwrite is not acceptable.

Connector Direction

Implement connectors in this order:

  1. vCard import/export and batch import.
  2. CardDAV address books.
  3. LDAP/Active Directory read-only directories.
  4. Exchange/Microsoft 365 and Google Contacts.
  5. CSV/XLSX/LDIF import mapping profiles.

Connector runtime behavior should reuse shared connector concepts where useful: configured endpoints, credentials, dry-run, diagnostics, rate limits, and audit events.

Cross-Module Integration

Campaigns should consume addresses.recipient_source through the platform registry and freeze snapshots into campaign versions. Mail should consume addresses.lookup for autocomplete and addresses.contact_writer for "add contact" workflows. Scheduling should use lookup for attendees and organizers. Portal, postbox, cases, forms, and reporting should link to contact records by stable IDs while keeping their own domain evidence. Cross-module UI must hide write actions when no writable target exists, or show the writer decision message when a disabled action remains visible for context.

Operational distribution lists belong in govoplan-dist-lists. They may later consume address lists as one entry type, but they own mixed recipient expansion for users, identities, organization units, groups, functions, roles, raw recipients, and nested lists. Workflow and Tasks own Umlauf execution state; distribution lists define who is included, not how work circulates.

Deferred Work

The following are valuable but not required for the first functional milestone:

  • automatic deduplication and merge suggestions
  • two-way sync conflict UI
  • Microsoft/Google connectors
  • household and relationship editing
  • advanced consent-policy automation
  • contact activity timeline across all modules