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,
|
configured authenticated, short-lived email-link, and permanent-link modes,
|
||||||
while Portal owns only the accessible presentation and reload/request actions.
|
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).
|
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
|
notes, or handoff details. A reload action re-fetches the authoritative
|
||||||
projection. Missing, disabled, revoked, expired, or unauthorized grants share
|
projection. Missing, disabled, revoked, expired, or unauthorized grants share
|
||||||
a non-enumerating unavailable state.
|
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=(
|
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(
|
DocumentationTopic(
|
||||||
id="portal.function-postboxes",
|
id="portal.function-postboxes",
|
||||||
title="Portal-facing function Postboxes",
|
title="Portal-facing function Postboxes",
|
||||||
@@ -337,6 +370,7 @@ manifest = ModuleManifest(
|
|||||||
"Portal does not persist service definitions; the Services provider remains authoritative.",
|
"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.",
|
"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.",
|
"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"),
|
owned_concepts=("service discovery", "service presentation", "channel entry", "applicant status presentation"),
|
||||||
non_owned_concepts=("institutional service definition", "case lifecycle", "applicant status access decision"),
|
non_owned_concepts=("institutional service definition", "case lifecycle", "applicant status access decision"),
|
||||||
|
|||||||
@@ -440,6 +440,22 @@ class PortalServiceDirectoryTests(unittest.TestCase):
|
|||||||
"application_status.projection",
|
"application_status.projection",
|
||||||
{item.name for item in manifest.requires_interfaces},
|
{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__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Reference in New Issue
Block a user