Add governed contact point snapshots

This commit is contained in:
2026-08-02 06:20:24 +02:00
parent 67392f620f
commit 2e78b9ae50
10 changed files with 1620 additions and 16 deletions
+32 -1
View File
@@ -12,6 +12,7 @@ from govoplan_addresses.backend.capabilities import (
)
from govoplan_addresses.backend.db import models as addresses_models # noqa: F401 - populate address ORM metadata
from govoplan_core.core.access import CAPABILITY_AUTH_PERMISSION_EVALUATOR, CAPABILITY_AUTH_PRINCIPAL_RESOLVER
from govoplan_core.core.contact_points import CAPABILITY_ADDRESSES_CONTACT_POINT_RESOLUTION
from govoplan_core.core.module_guards import drop_table_retirement_provider, persistent_table_uninstall_guard
from govoplan_core.core.people import CAPABILITY_ADDRESSES_PEOPLE_SEARCH
from govoplan_core.core.distribution_lists import CAPABILITY_RECIPIENT_CHANNEL_FACTS
@@ -42,6 +43,7 @@ from govoplan_addresses.backend.provider_state import (
_addresses_table_retirement_provider = drop_table_retirement_provider(
addresses_models.ContactPointSnapshot,
addresses_models.AddressSyncDiagnostic,
addresses_models.AddressSyncConflict,
addresses_models.AddressSyncTombstone,
@@ -147,12 +149,19 @@ ROLE_TEMPLATES = (
def _tenant_summary(session, tenant_id: str) -> dict[str, int]:
from govoplan_addresses.backend.db.models import AddressBook, AddressList, AddressSyncSource, Contact
from govoplan_addresses.backend.db.models import (
AddressBook,
AddressList,
AddressSyncSource,
Contact,
ContactPointSnapshot,
)
return {
"address_books": session.query(AddressBook).filter(AddressBook.tenant_id == tenant_id, AddressBook.deleted_at.is_(None)).count(),
"address_lists": session.query(AddressList).filter(AddressList.tenant_id == tenant_id, AddressList.deleted_at.is_(None)).count(),
"contacts": session.query(Contact).filter(Contact.tenant_id == tenant_id, Contact.deleted_at.is_(None)).count(),
"contact_point_snapshots": session.query(ContactPointSnapshot).filter(ContactPointSnapshot.tenant_id == tenant_id).count(),
"sync_sources": session.query(AddressSyncSource).filter(AddressSyncSource.tenant_id == tenant_id, AddressSyncSource.enabled.is_(True)).count(),
}
@@ -226,6 +235,7 @@ manifest = ModuleManifest(
ModuleInterfaceProvider(name=CAPABILITY_ADDRESSES_LOOKUP, version="0.1.8"),
ModuleInterfaceProvider(name=CAPABILITY_ADDRESSES_PEOPLE_SEARCH, version="0.1.0"),
ModuleInterfaceProvider(name=CAPABILITY_ADDRESSES_RECIPIENT_SOURCE, version="0.1.9"),
ModuleInterfaceProvider(name=CAPABILITY_ADDRESSES_CONTACT_POINT_RESOLUTION, version="1.0.0"),
ModuleInterfaceProvider(name=CAPABILITY_ADDRESSES_CONTACT_WRITER, version="0.1.8"),
ModuleInterfaceProvider(name=CAPABILITY_RECIPIENT_CHANNEL_FACTS, version="0.1.0"),
),
@@ -263,6 +273,10 @@ manifest = ModuleManifest(
"govoplan_addresses.backend.capabilities",
fromlist=["channel_facts_capability"],
).channel_facts_capability(context),
CAPABILITY_ADDRESSES_CONTACT_POINT_RESOLUTION: lambda context: __import__(
"govoplan_addresses.backend.capabilities",
fromlist=["contact_point_resolution_capability"],
).contact_point_resolution_capability(context),
},
uninstall_guard_providers=(
persistent_table_uninstall_guard(
@@ -272,6 +286,7 @@ manifest = ModuleManifest(
addresses_models.AddressSyncSource,
addresses_models.AddressListEntry,
addresses_models.AddressList,
addresses_models.ContactPointSnapshot,
addresses_models.AddressBook,
addresses_models.Contact,
addresses_models.ContactEmail,
@@ -297,6 +312,22 @@ manifest = ModuleManifest(
related_modules=("campaigns", "mail", "forms", "reporting", "portal", "postbox"),
order=30,
),
DocumentationTopic(
id="addresses.contact-point-resolution",
title="Contact-point resolution and snapshots",
summary="Resolve purpose-aware channel targets and freeze immutable recipient evidence.",
body=(
"Addresses exposes a versioned contact-point capability for email, postal, internal-mail, and portal targets. "
"Callers can request an effective date, communication purpose, address purpose, fallback rule, locale, and "
"postal format. Bounded previews remain live; frozen snapshots retain the resolved values, exclusions, "
"source and governance revisions, provenance, and a deterministic evidence hash even after contacts change."
),
layer="configured",
documentation_types=("admin", "user"),
audience=("tenant_admin", "operator", "module_admin"),
related_modules=("dist_lists", "campaigns", "policy", "templates"),
order=31,
),
),
external_providers=(CARDDAV_PROVIDER,),
external_provider_state_providers=(