docs(portal): declare DSAR ownership boundary
This commit is contained in:
@@ -38,4 +38,11 @@ The public `/portal/status/:trackingId` surface presents the bounded
|
||||
configured authenticated, short-lived email-link, and permanent-link modes,
|
||||
while Portal owns only the accessible presentation and reload/request actions.
|
||||
|
||||
Portal deliberately does not publish a DSAR provider because it persists no
|
||||
service-directory, launch, Postbox, application-status, applicant, or session
|
||||
records. Services owns definitions, each launch target owns its effects,
|
||||
Postbox owns mailbox data, and Forms Runtime owns status grants and submission
|
||||
data. Core and the deployment operator remain responsible for request/security
|
||||
logs. This reviewed boundary avoids duplicate or contradictory privacy exports.
|
||||
|
||||
See [docs/SERVICE_DIRECTORY_CONCEPT.md](docs/SERVICE_DIRECTORY_CONCEPT.md).
|
||||
|
||||
@@ -149,3 +149,26 @@ must not infer missing milestones or expose values, people, evidence, internal
|
||||
notes, or handoff details. A reload action re-fetches the authoritative
|
||||
projection. Missing, disabled, revoked, expired, or unauthorized grants share
|
||||
a non-enumerating unavailable state.
|
||||
|
||||
## Data-subject request ownership
|
||||
|
||||
Portal has no module-owned persistence and therefore does not contribute a
|
||||
`privacy.dsar.portal` provider. Its routes resolve and render bounded
|
||||
provider-owned projections during each request; they do not copy service
|
||||
definitions, launch parameters or results, Postbox entries, status grants,
|
||||
submission values, email addresses, or applicant identities into Portal.
|
||||
|
||||
Data-subject request coverage follows the authoritative owner:
|
||||
|
||||
- Services covers configuration-author attribution for versioned service
|
||||
definitions;
|
||||
- Cases, Forms Runtime, and Workflow Engine cover launch effects and domain
|
||||
instances;
|
||||
- Postbox covers mailbox records; and
|
||||
- Forms Runtime covers status-access grants, token lifecycle, confirmations,
|
||||
acknowledgements, and submitted Form data.
|
||||
|
||||
Authentication state, request/security logs, and infrastructure telemetry are
|
||||
Core or deployment-operator concerns, not Portal records. If Portal later gains
|
||||
durable personalization, analytics, saved searches, contact data, or session
|
||||
persistence, that change must add a tenant-scoped DSAR provider before release.
|
||||
|
||||
@@ -231,6 +231,39 @@ manifest = ModuleManifest(
|
||||
),
|
||||
},
|
||||
documentation=(
|
||||
DocumentationTopic(
|
||||
id="portal.data-subject-requests",
|
||||
title="Portal data-subject request boundary",
|
||||
summary="Understand why Portal has no separate privacy export and which authoritative modules own the projected data.",
|
||||
body=(
|
||||
"Portal persists no service-directory, service-launch, Postbox, application-status, applicant, or session records, so it deliberately publishes no duplicate data-subject request provider. Services owns definition attribution; Cases, Forms Runtime, and Workflow Engine own launch effects; Postbox owns mailbox records; and Forms Runtime owns submission and status-access data. Core and the deployment operator own authentication state, request/security logs, and infrastructure telemetry. "
|
||||
"If durable personalization, analytics, saved searches, contact data, or sessions are added to Portal, a tenant-scoped privacy provider is required before release."
|
||||
),
|
||||
layer="available",
|
||||
documentation_types=("admin", "user"),
|
||||
audience=("user", "operator", "module_admin", "auditor"),
|
||||
links=(
|
||||
DocumentationLink(
|
||||
label="Portal ownership boundary",
|
||||
href="govoplan-portal/docs/SERVICE_DIRECTORY_CONCEPT.md",
|
||||
kind="repository",
|
||||
),
|
||||
),
|
||||
related_modules=(
|
||||
"core",
|
||||
"services",
|
||||
"cases",
|
||||
"forms_runtime",
|
||||
"workflow_engine",
|
||||
"postbox",
|
||||
),
|
||||
metadata={
|
||||
"kind": "reference",
|
||||
"help_contexts": ["portal.data-subject-requests"],
|
||||
"dsar_coverage": "not_applicable_no_persistence",
|
||||
},
|
||||
order=10,
|
||||
),
|
||||
DocumentationTopic(
|
||||
id="portal.function-postboxes",
|
||||
title="Portal-facing function Postboxes",
|
||||
@@ -337,6 +370,7 @@ manifest = ModuleManifest(
|
||||
"Portal does not persist service definitions; the Services provider remains authoritative.",
|
||||
"Case, Forms Runtime, and Workflow Engine own launch effects. Portal keeps entries unavailable whenever the selected owner capability is absent.",
|
||||
"Forms Runtime owns applicant-status access, redaction, and timeline semantics; Portal only presents that projection. Payment and decision-document actions are not yet included in the first status surface.",
|
||||
"Portal owns no durable subject records and therefore has no DSAR provider; adding persistence requires introducing one before release.",
|
||||
),
|
||||
owned_concepts=("service discovery", "service presentation", "channel entry", "applicant status presentation"),
|
||||
non_owned_concepts=("institutional service definition", "case lifecycle", "applicant status access decision"),
|
||||
|
||||
@@ -440,6 +440,22 @@ class PortalServiceDirectoryTests(unittest.TestCase):
|
||||
"application_status.projection",
|
||||
{item.name for item in manifest.requires_interfaces},
|
||||
)
|
||||
self.assertFalse(
|
||||
any(
|
||||
name.startswith("privacy.dsar.")
|
||||
for name in manifest.capability_factories
|
||||
)
|
||||
)
|
||||
dsar_topic = next(
|
||||
item
|
||||
for item in manifest.documentation
|
||||
if item.id == "portal.data-subject-requests"
|
||||
)
|
||||
self.assertEqual(
|
||||
"not_applicable_no_persistence",
|
||||
dsar_topic.metadata["dsar_coverage"],
|
||||
)
|
||||
self.assertTrue({"admin", "user"}.issubset(dsar_topic.documentation_types))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user