Repository navigation
Documents module: policies, versions, review cycle and acknowledgement campaigns - #183
Merged
Merged
Conversation
…ledgement) Proposed for v0.37.0: a register of the ISMS's documented information (ISO 27001 clause 5.2, 7.5, A.5.1) in a new documents app. - Policy: the document identity (type, owner, classification, review cycle, scopes, requirement links, parent / child structure) running a draft / active / retired lifecycle. - PolicyVersion: frozen-once-submitted content (rich text and / or a PDF with its SHA-256), change summary, approval stamped by the transition, at most one version in force with automatic, recorded supersession (backed by a partial unique constraint). - AcknowledgementCampaign and PolicyAcknowledgement: an audience of users, groups and roles resolved once at launch into write-once rows only the addressee can acknowledge, reminders, completion rate. - Review cycle derived from the version in force, "reviewed, no change" as a recorded act, reminders, calendar, dashboard, kanban. - IsmsChange.affected_documents and a Trust Center document source that always serves the version in force. The related specs (Trust Center document, ISMS change, contract, the specs index) are updated to point at it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FaEkJnhS3VNDeb6jrdn6MC
A new documents app (module 7) with its four models, three lifecycles, permissions and notifications, implementing the RG-DOC rules of docs/specs/m7-documents/: - Policy (PLCY): identity, type, classification, owner / approver, parent document, requirement and role links, a derived next review date, record_review() and new_version(); draft / active / retired. - PolicyVersion (PLVR): rich text sanitized while draft and a PDF with its SHA-256, frozen from submission; putting a version in force stamps the approval and supersedes the previous one in the same transaction through its own recorded transition, backed by a partial unique constraint (one version in force per document). - AcknowledgementCampaign (ACKC): audience of users, groups and roles resolved once at launch into write-once PolicyAcknowledgement rows that only the addressee can acknowledge; closing or superseding expires the pending rows; excusing needs a reason. Gates and side effects live in each model's transition_to() and raise DomainRefusalError, so the generic stepper endpoint, REST and MCP all apply them. Each lifecycle declares its archived exit explicitly (no unguarded archive / restore edge) and no restore transition. The documents permission features (10 codenames) are attached to the six system groups by migration; five notification types are added. The web views are placeholders until the interface lands. The spec is aligned with these choices. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FaEkJnhS3VNDeb6jrdn6MC
/api/v1/documents/ with policies, policy-versions, acknowledgement-campaigns and acknowledgements, on the house pattern (ModulePermission, scope filter, /transition/, history, batch create): - record-review and new-version (minor / major) on a document, add-newcomers on a campaign, mine / acknowledge / excuse on the acknowledgement rows; acknowledging is the addressee's own act (channel "api"), refused to anyone else, administrators included; - a submitted version refuses changes to its frozen fields with a 400 naming the field, a launched campaign its version, statement and audience; file_content is never serialized (has_pdf, pdf_sha256, document_url instead); DomainRefusalError becomes a 400 with its reason. Three domain gaps surfaced by the API are closed in the models: acknowledgement rows are created with their history (bulk_create_with_history), a retired document refuses a new version, and an approved version's effective date is frozen. generate_docs now includes the documents app in models.md and an MCP module title for it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FaEkJnhS3VNDeb6jrdn6MC
AdvancedFilterMixin listed up to 200 rows of every related model as the
options of its relation pickers, unscoped, and rendered them into the
list page: a user restricted to one scope read the names of the risk
assessments, documents, suppliers... of every other scope. The options
of a model with a scope lookup are now filtered through the reader's
allowed scopes (superusers and unrestricted users unchanged; people and
tags, which have no scope, are listed as before). Found while building
the documents lists; test on the risk register's assessment picker.
Also: lifecycle_name_for() given an "app_label.Model" string resolved
nothing and fell back to the default lifecycle, so
reportable_states("documents.Policy") answered {"validated"}; it now
resolves the label to its model. The Trust Center certification gate
passed such a label and only worked because frameworks run the default
lifecycle.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FaEkJnhS3VNDeb6jrdn6MC
Every route of documents/urls.py, on the framework anatomies: - the document register and the campaign list (rail tiles, facets including "review overdue", scoped relation filters); - document, version and campaign detail pages with the lifecycle stepper, the version in force rendered with its approval line, PDF and SHA-256, the versions table, structure, requirements, campaigns, "Reviewed, no change" and "New version" actions, the audience table with "Add newcomers" and "Excuse"; - drawer create / edit forms with one-line page fallbacks (creating a document drafts its version 1.0), delete confirmations on the shared shells; a submitted version, a launched campaign and a retired document open read-only; - "To acknowledge", every user's own pending rows, reachable from the user menu with a count: a row is only ever the current user's own (anyone else's is a 404, superusers included); - the PDF download (attached PDF or the rich text rendered by WeasyPrint), permission and scope checked, also open to the addressee of a campaign on that version. Wiring: the Documents sidebar section, NAV_TREE entries, the "documents" module accent in both themes, an acknowledgement_status badge scale, the five help banners, the French catalogue for the whole module, and docs/user-guide/documents.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FaEkJnhS3VNDeb6jrdn6MC
…nd the seed - Management review: IsmsChange.affected_documents (M2M -> Policy, linkable_or_linked picker, the legacy free-text field kept), exposed in the API; the review page lists each change's documents and a "Documents due for review" card (due in the period or overdue at the review date, within the review's and the reader's scopes). - Trust Center: TrustCenterDocument.policy as a third exclusive source (public classification, active document); the published() gate drops an entry whose policy is retired, reclassified or has no version in force; the download serves the version in force through render_pdf(). - Global search (documents and versions), a "documents" calendar category (review dates, campaign due dates), a Documents dashboard widget with its context and cache invalidation, the current user's pending acknowledgements in the kanban To do column, and the policies_overdue_review / acknowledgement_rate predefined indicators. - documents_sweep: review due / overdue and acknowledgement reminders, each sent once, with --dry-run; scheduled as a host cron line like the other sweeps (operations and installation guides). - The Voltara seed gains a documents phase: seven documents, ten versions (superseded ones included, one with a PDF), a draft, an overdue review, a running and a closed campaign, an ISMS change and a Trust Center publication, all through the recorded transitions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FaEkJnhS3VNDeb6jrdn6MC
_register_documents_tools() exposes the module to MCP clients: - CRUD, transition, allowed transitions and history for documents, versions and campaigns, with scope checks and the frozen-field rule on version and campaign updates; - new_policy_version, record_policy_review, get_policy_in_force, get_campaign_progress, add_campaign_newcomers, list_policy_acknowledgements, excuse_policy_acknowledgement; - list_my_pending_acknowledgements and acknowledge_policy_version, the caller's own act (channel "mcp"), which need no permission by design; - the PLCY / PLVR / ACKC reference prefixes and a documents help topic. The management review and Trust Center tools accept and return the new affected_document_ids / policy fields, and the assistant catalogue gains three read-only documents tools. The generated reference is regenerated for the module (models, permissions, lifecycles, REST routes, MCP tools, dashboard widget). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FaEkJnhS3VNDeb6jrdn6MC
The README feature table gains the Documents module; the user guide page shows the register, a document, the campaigns and the "To acknowledge" page, captured at 2560x1440 by capture_screenshots.py (which now includes them); the module spec is marked implemented with its wiring checklist ticked, and the related specs drop their "proposed" notes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FaEkJnhS3VNDeb6jrdn6MC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A new Documents module (module 7) : the register of the ISMS's documented information (ISO/IEC 27001:2022 clause 5.2, 7.5, A.5.1). Policies, procedures, standards, charters and plans with frozen, approved versions (one in force at a time), a review cycle with reminders, and acknowledgement campaigns whose confirmations are kept as write-once evidence. Integrated with the management review, the Trust Center, the calendar, the dashboard, the kanban, search and the indicators, and exposed on the web, the REST API and MCP. Specified first in
docs/specs/m7-documents/.Related issue
None.
Type of change
Changes
6efb48bSpec:docs/specs/m7-documents/(README + four entity files) and the related specs (Trust Center document, ISMS change, contract, index).342d414Domain:Policy(PLCY),PolicyVersion(PLVR),AcknowledgementCampaign(ACKC),PolicyAcknowledgement; three lifecycles with an explicit, guardedarchivedexit and no restore edge; gates and side effects intransition_to()(supersession in the same transaction, approval stamps, frozen content, PDF with SHA-256, audience resolved once at launch, write-once acknowledgements only the addressee can give); a partial unique constraint for "one version in force"; 10 permission codenames on the six system groups; five notification types.2483610REST API under/api/v1/documents/, plus three domain gaps it surfaced (row creation history, no new version of a retired document, frozen effective date).62e4b0cSecurity: the advanced filter of every list rendered its relation picker options unscoped (names of records outside the reader's scopes in the page);lifecycle_name_for("app.Model")silently fell back to the default lifecycle.4c374a6Web interface: registers, detail pages, drawer forms, delete shells, "To acknowledge" (own rows only), PDF download, sidebar, module accent, help banners, user guide, French catalogue.b84e8b3Integrations:IsmsChange.affected_documentsand a "Documents due for review" card on the review;TrustCenterDocument.policyserving the version in force behind the publication gate; search, calendar, dashboard widget, kanban, two predefined indicators; thedocuments_sweepreminders command; the Voltara seed.bb9b8deMCP: CRUD / transitions / history for the three entities, plusnew_policy_version,record_policy_review,get_policy_in_force,get_campaign_progress,list_my_pending_acknowledgements,acknowledge_policy_versionand the campaign row tools; assistant catalogue entries; regenerated reference.58b9cc9Docs: README, screenshots, spec marked implemented.Screenshots
docs/screenshots/documents.png,document-detail.png,acknowledgement-campaigns.png,to-acknowledge.png(2560x1440). Every documents page was captured in light / dark at 1600 px and 390 px during development: HTTP 200, no horizontal overflow, no console error.Checklist
pytestpassesruff checkpassesmcp/tools.py(accurate docstrings and parameter descriptions)api/(serializers, viewsets, routes under/api/v1/)_()/{% trans %}with French translations inlocale/fr/LC_MESSAGES/django.po(no duplicatemsgid;compilemessagespasses)README.mdupdated (features, MCP tools, tech stack, install) when behaviour changedCHANGELOG.mdupdated under## [Unreleased]docs/brand/brand-guidelines.md); no em dash charactersdocs/specs/updated in the same PRVerification: full suite 3,457 passed,
ruffclean,generate_docs --checkandbuild_wiki.py --checkclean,compilemessagesclean.Known limits (spec §11): no rendered diff between versions, no exceptions register, no electronic signature, no future-dated entry into force. PDF rendering of rich text needs WeasyPrint's system libraries (present in the Docker image); without them the download falls back to a message instead of a 500.
🤖 Generated with Claude Code
https://claude.ai/code/session_01FaEkJnhS3VNDeb6jrdn6MC