Mariano/cs 437#2992
Conversation
Placement (framework-grouped Documents page, ISO 27001 (ISMS) tab), IsmsDocument substrate following the SOA pattern, clause-requirement linkage, per-document data models, PDF reuse + net-new DOCX export, feature-flagged all-or-nothing release, and slice-first build sequence. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
IsmsDocument + IsmsDocumentVersion (versioned narrative, source snapshot for drift, pdf/docx urls, sign-off) and IsmsContextIssue (clause 4.1 register), mirroring the SOADocument pattern. Links the global FrameworkEditorFramework + org + ISO clause requirement. Back-relations on Organization, FrameworkEditorFramework, FrameworkEditorRequirement, and Member. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
NestJS isms module (@controller path:'isms' v1) mirroring SOA: ensure-setup, get document, deterministic Context-of-Organization (4.1) generation from platform data, context-issue CRUD with derived->manual override, sign-off (submit/approve/decline), drift detection vs approved snapshot, and branded PDF + net-new DOCX export (docx@9.7.1). All endpoints gated @RequirePermission('audit', ...) to match SOA. 63 Jest tests. openapi regen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ion (4.1) (CS-437) Add framework-grouped Documents tabs with a flag-gated, ISO-27001-conditional "ISO 27001 (ISMS)" tab (IsmsOverview: 6 foundational-doc cards + the moved SOA card). Full Context of the Organization (4.1) detail page: useIsmsDocument hook, generate-from-platform-data, editable internal/external issues register with derived->manual override, drift banner, submit/approve/decline sign-off, and PDF/DOCX export. Mutations gated on audit:update; readers can view + export. isIsmsEnabled defaults off (PostHog) until the full pack ships. Vitest tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Permissions: switch ISMS endpoints from `audit` to the `evidence` resource (reads incl. ensure-setup -> evidence:read; mutations -> evidence:update). `evidence` matches the Documents route gate and is the correct semantic fit: owner/admin author + sign off, auditor read-only (review + export), others excluded. Frontend mutation gating moved to evidence:update. - Drop the isIsmsEnabled runtime flag. The ISO 27001 (ISMS) tab is now purely framework-conditional (visible when ISO 27001 is active); the unmerged branch is the release gate. SOA card now lives solely in the ISMS tab. - Spec updated to match (permissions + merge-gated release). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… Objectives (CS-437) Add IsmsInterestedParty (4.2a), IsmsInterestedPartyRequirement (4.2b/c, linked to a party), and IsmsObjective (6.2) register tables + IsmsObjectiveStatus enum, all reusing the shared IsmsContextSource derived/manual flag. Scope (4.3) and Leadership (5.1) are singletons stored in IsmsDocumentVersion.narrative. Additive migration only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…tch (CS-437)
Refactor generate/drift/export to dispatch by IsmsDocumentType to per-document
handler modules (documents/registry.ts). Add deterministic derivation, register
CRUD, and branded PDF/DOCX export for: Interested Parties (4.2a), Requirements &
Treatment (4.2b/c, linked to parties), Objectives (6.2), plus singleton narrative
docs Scope (4.3) and Leadership (5.1) stored zod-validated in version.narrative.
Single platform-data source; per-type drift snapshots; manual rows preserved on
regenerate. All endpoints @RequirePermission('evidence', ...). 138 Jest tests.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…CS-437) Generalize useIsmsDocument (generic createRow/updateRow/deleteRow + saveNarrative) and the [type] route dispatch, enable all six overview cards, and add functional detail pages on the proven Context pattern: - Interested Parties Register (4.2a), Requirements & ISMS Treatment (4.2b/c), Information Security Objectives Plan (6.2) - editable registers - ISMS Scope Statement (4.3, certificate sentence first-class) and Leadership Commitment (5.1, clause 5.1 a-h) - narrative forms via saveNarrative Each reuses DriftBanner + IsmsApprovalSection, gates mutations on evidence:update, and offers PDF/DOCX export. Vitest tests per document (admin vs read-only). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
One profile per org+framework holding the ~12 un-derivable wizard answers as a Zod-validated JSON blob that feeds document generation. Additive migration. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
API: IsmsProfile get-or-init/save/complete + generate-all, a shared Zod WizardAnswers schema, computed defaults for pre-population (capabilities from Types of Services, certificate sentence, default objectives/outcomes, cloud split), and threading wizard answers through derivation (insurance/regulators/ contractors/EU-rep -> Interested Parties & Requirements; certificate sentence + cloud split + capabilities -> Scope; deputy SPO -> Leadership; confirmed objectives -> 6.2). Frontend: 6-step wizard (12 questions, confirm-or-edit, pre-filled from defaults) with partial saves per step and complete -> generate-all on finish; "Run setup wizard" entry point on the ISMS overview. RHF+Zod, design-system only. 189 API jest tests; wizard Vitest tests; all ISMS checks green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…S-438) Adds the evidence:update-gated wizard launch button to IsmsOverview (missed by the prior wizard commit's add path). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add FrameworkEditorIsmsDocumentTemplate (one per doc type, with default clause) and FrameworkEditorIsmsDocumentRequirementLink (framework-scoped template->clause mapping, editable in the Framework Editor), plus IsmsDocument.templateId provenance. Additive migration. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…, Paul A) Seed the 6 ISMS doc templates; add a framework-editor CRUD/mapping API (framework-editor/isms-document-template: list, update, link/unlink a clause requirement per framework, PlatformAdminGuard); rework ensure-setup to be template-driven (requirement = framework-scoped link ?? clause-match ?? seeded defs fallback) with IsmsDocument.templateId provenance; and a Framework Editor "ISMS Documents" tab/page to author the template->requirement mappings. 238 api jest tests; framework-editor + api typecheck clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
FrameworkEditorControlIsmsDocumentLink (template: control template <-> ISMS doc template, framework-scoped) and IsmsDocumentControlLink (org: document <-> control), mirroring how policies/document-types link to controls. Back-relations on FrameworkEditorFramework/ControlTemplate/IsmsDocumentTemplate, Control, IsmsDocument. Additive migration. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Template level (Framework Editor): link/unlink control templates to ISMS doc templates + a "Controls" mapping cell on the ISMS Documents page. Org level: POST/DELETE /v1/isms/documents/:id/controls (like policies), getDocument returns controlLinks, ensure-setup auto-derives a doc's org control links from its template's control mapping. A "Linked controls" section (IsmsControlMappings) on all 6 document detail pages, mirroring PolicyControlMappings. 257 api jest tests; api/framework-editor/app typecheck clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-grade (CS-437) Establish a shared ISMS presentation kit (IsmsStatusBadge, IsmsDocumentCard, IsmsPageHeader, IsmsSummaryRow, IsmsEmptyState, IsmsRegisterShell, IsmsSourceBadge, IsmsRowActions) and restyle the whole area with it: overview (summary stats + Section/Grid of document cards + SOA section + Empty state), the 6 detail pages (consistent header + Section composition), register tables (DS Table + Empty states), drift (Alert), control mappings, approval, and the wizard (Progress + Field steps). One status language, no hand-rolled badges. Strictly design-system components only. Tests + typecheck green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wizard: Select shows the human label via items prop (#8) + controlled-from-first- render value, no console warning (#9); Finish validation jumps to the first invalid step (#6); form re-seeds when the profile loads post-mount (#7). Shared: source badge reads "Manual" not "Edited" (#1); approval section is status-aware — approved/declined/pending states instead of a bare submit (#2); compact empty state (#4); delete confirmation dialog on register rows (#5). Detail pages: content-first ordering across all 6 (#3). API: certificate-sentence whitespace normalized (#11); cloud-split/capabilities feed scope correctly (#10). Plus QA findings doc + openapi regen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rview (CS-437) Replace the dense always-on-textarea tables (Context internal/external issues, Interested Parties, Requirements, Objectives) with calm read-first cards: source chip + provenance leading, the primary field prominent, secondary fields as muted labelled values, count-badged sections, compact empty states, and an explicit Edit affordance (Save/Cancel) with the delete-confirm preserved. New shared kit: IsmsRegisterCard, IsmsCardActions, IsmsAddCard. Design-system only; register component props/behaviour unchanged. 42 ISMS tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Read mode is now a compact two-line row — issue prominent, effect muted beneath, source chip + provenance on the right, hover-reveal actions, tighter padding — instead of an airy card with a labelled effect field. Roomy labelled form kept for editing. Tighter row spacing. Cuts ~half the vertical space per item for long lists. DS-only; behaviour unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the loud uppercase AUTO-DERIVED pill + raw "framework:GDPR" key with a
quiet muted line + small icon and a humanized source ("GDPR framework", "Vendor
register", "Workforce", "Setup wizard"). Manual rows keep a small badge so human
overrides still stand out. Shared component, so all four registers benefit.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drop the misleading auto/ML icon and the disconnected right-floating label; render the humanized source as a plain pill beneath each entry's description (GDPR framework / Vendor register / Workforce / Manual). Reads like a tag on the entry rather than floating metadata. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
framework:GDPR -> "GDPR" (not "GDPR framework"); the name alone is clearer. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The submit-for-approval / approved banner now renders directly under the header, above drift/content/linked-controls, so the sign-off state and action are the first thing you see on a document rather than buried at the bottom. Applied identically across all six detail pages. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…(CS-437) The auto-derive provenance pill (WORKFORCE / GDPR / HIPAA) just restated the party name sitting next to it. Removed it; the category badge (CUSTOMER / SUPPLIER / REGULATOR) stays since that's real classification, not a restatement. Made IsmsRegisterCard.header optional so edit mode renders without it (actions stay right-aligned via ml-auto). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nt (CS-439) Redesign the ISO 27001 Context of the Organization PDF/DOCX export to match the hand-authored reference document, and capture the data it needs. - db: add `category` to IsmsContextIssue (4.1 grouping) + migration - derivation: assign each derived issue an ISO 4.1 category; export the external/internal category taxonomies - export: pull org overview (onboarding Q&A), mission (company description) and intended outcomes (wizard answers / defaults) at export time; build rich metadata (document code, clause, classification, owner, next review, issue date) - builder: buildContextSections now emits the full 7-section structure — purpose, organization overview, mission + intended outcomes, categorised external and internal issue tables (Category / Issue / Effect), linkage, review - renderers: rebuild PDF (jspdf + jspdf-autotable) and DOCX with a cover block, metadata table, numbered sections, real bordered tables, bullet lists and a footer with classification + page numbers; split PDF into its own module - ui: add an ISO 4.1 category picker to the issue add form + edit row, show the category as a pill in read mode - tests: API builder/derivation/service + app picker coverage Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…s (CS-437) Wrap the ISO 27001 (ISMS) tab in the `is-isms-enabled` PostHog flag so it can be privately tested per-org (matching the is-*-enabled convention). The tab now shows only when ISO 27001 is active AND the flag is on; local development falls through so it stays visible without PostHog configured. Move the Statement of Applicability card out of the ISMS tab and back to the top of the general Documents list (gated on ISO 27001 presence), while we privately test the ISMS area. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
@cubic-dev-ai ultrareview this |
|
@cubic-dev-ai review this |
@Marfuen I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
cubic analysis
10 issues found across 203 files
Confidence score: 2/5
- There is a concrete user-impacting regression risk in
apps/app/src/app/(app)/[orgId]/documents/isms/components/ContextOfOrganizationClient.tsx:handleUpdateIssueswallows API errors, soIssueRowcan exit edit mode and lose unsaved edits when save fails. - Several high-confidence behavior issues (7/10) increase merge risk, including stale local state in
apps/framework-editor/app/(pages)/isms-documents/useIsmsDocumentRows.tsafter template re-fetches and hardcoded admin-only access inapps/api/src/framework-editor/isms-document-template/isms-document-template.controller.tsthat can block RBAC-based delegation. - Data-intent consistency is also at risk in
apps/api/src/isms/documents/objectives.tsandapps/api/src/isms/documents/org-profile.ts, where explicitly saved empty values can be overwritten by regenerated defaults. - Pay close attention to
apps/app/src/app/(app)/[orgId]/documents/isms/components/ContextOfOrganizationClient.tsx,apps/framework-editor/app/(pages)/isms-documents/useIsmsDocumentRows.ts,apps/api/src/framework-editor/isms-document-template/isms-document-template.controller.ts,apps/api/src/isms/documents/objectives.ts, andapps/api/src/isms/documents/org-profile.ts- these carry the highest chance of user-visible regressions and authorization/data-intent mismatches.
Linked issue analysis
Linked issue: CS-437: [Feature] A. Foundational documents
| Status | Acceptance criteria | Notes |
|---|---|---|
| ✅ | Add an ISMS area in Documents (ISO 27001 / ISMS tab) and an ISMS overview with document cards | Front-end tab wiring and overview components added; DocumentsPageTabs updated and IsmsOverview plus many UI cards/components added. |
| ✅ | Provide the six foundational document types (4.1 Context, 4.2a Interested Parties, 4.2b/c Requirements, 4.3 Scope, 5.1 Leadership Commitment, 6.2 Objectives) | Schema, type definitions and handler modules for each document type are present; ISMS_TYPE_DEFINITIONS and IsmsDocumentType defined; per-document derivation modules added. |
| ✅ | Deterministic generation from platform data (collectPlatformData + per-document derivations) and generate-all flow | Platform-data collection, generate/runDerivation and replace-derived-rows logic implemented; generate-all DTO and service paths exist. |
| ✅ | Customer-editable registers where manual overrides are preserved (derived → manual on edit) and regenerate preserves manual edits | Services flip derived rows to 'manual' on edit and replaceDerivedRows preserves manual rows; register services and controllers added for CRUD. |
| ✅ | Versioning, submit/approve/decline workflow and approval invalidation when content changes | IsmsDocument and IsmsDocumentVersion model work is supported by services and DTOs; approval invalidation helper and narrative save that resets approvals implemented; submit/approval DTO and UI present. |
| ✅ | Export to DOCX and PDF (branded, cover metadata, structured sections) | Both docx and PDF renderers implemented, export generator dispatch, DTO and client export helper present; deps added to package.json. |
| ✅ | Short setup wizard (~12 questions) that persists profile answers and can generate all documents in a single session | Full wizard client + server-side profile schema, services and generate-all plumbing implemented, including defaults and merge logic. |
| ✅ | Drift detection and one-click regenerate UI (flagging when underlying platform data changed) | Snapshot diffing and snapshot upsert implemented; drift API/hooks and UI components exist (useIsmsDrift, DriftBanner, snapshot logic). |
| ✅ | Consolidated register CRUD endpoints (create / update / delete) routed by register segment | A generic register-registry routes requests to per-register services; controller exists exposing create/update/delete for registers. |
| Definition-of-done: Pressmaster and Kidan packs reproducible and match/exceed hand-authored quality | Renderers and metadata exist to create DOCX/PDF outputs and a QA file was added, but there is no example output or explicit automated regression comparing generated packs to existing hand-authored artifacts in the diff to verify parity/quality. | |
| Definition-of-done: Pressmaster/Kidan Stage-1 findings (4.1,4.2,4.3,6.2) closable using platform output alone | Generation targets the specified clauses and derivation logic maps platform data to clause content, but auditor acceptance is outcome-level and there are no audit-run artifacts or acceptance tests proving those engagements' findings are closable solely with generated docs. |
Tip: instead of fixing issues one by one fix them all with cubic
Partial review: This PR has more than 100 files, so cubic reviewed the highest-priority files first.
For a deeper review of large PRs, comment @cubic-dev-ai ultrareview. Learn more.
Re-trigger cubic
- clients: every create/update/delete handler re-throws after toast so a failed save keeps the row/form open with the user's input (regression from the shell refactor) - route gating: new server layout gates the whole /documents/isms/* segment on the is-isms-enabled flag (+ ISO 27001 active), so wizard/detail pages aren't reachable by direct URL during private testing - wizard: stable row keys in WizardObjectivesEditor (was array index); breadcrumb href matches its link - single-source the objective zod schema (ObjectivesForm imported the shared one) - framework-editor: useIsmsDocumentRows re-syncs local state when templates prop changes - @ApiBody on the isms-profile @Req endpoint - respect an explicitly-emptied wizard objectives / intended-outcomes array instead of reseeding defaults (only fall back when never set) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@cubic-dev-ai review this |
@Marfuen I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
cubic analysis
11 issues found across 207 files
Confidence score: 3/5
- There is concrete regression risk in persistence logic:
packages/db/prisma/migrations/20260529172752_add_isms_foundational_documents/migration.sqlallows multipleisLatest=truerows, which can make “latest version” reads nondeterministic. apps/api/src/isms/isms-narrative.service.tsandapps/api/src/isms/isms-context-issue.service.tsperform key reads/calculations outside transactions, creating race windows under concurrency (wrong-version narrative writes, unique-constraint crashes, and duplicate ordering positions).- Workflow integrity is also at risk:
apps/api/src/isms/isms-document-control.service.tscan modify approved documents without triggering approval invalidation, and several frontend schema/linking issues increase validation and data-consistency drift risk. - Pay close attention to
packages/db/prisma/migrations/20260529172752_add_isms_foundational_documents/migration.sql,apps/api/src/isms/isms-narrative.service.ts,apps/api/src/isms/isms-context-issue.service.ts,apps/api/src/isms/isms-document-control.service.ts- they carry the highest likelihood of user-visible data integrity and process-state regressions.
Linked issue analysis
Linked issue: CS-437: [Feature] A. Foundational documents
| Status | Acceptance criteria | Notes |
|---|---|---|
| ✅ | Add new ISO 27001 (ISMS) Documents area and navigation tab (feature-flagged / framework-gated) | Frontend adds ISMS overview/route, DocumentsPageTabs was updated to surface an ISMS tab and layout enforces feature-flag + framework gating. |
| ✅ | Implement the six foundational document types server-side (types, DB schema, migrations, templates) | Prisma schema, multiple migrations and template seed entries add the IsmsDocument types and related tables. |
| ✅ | Deterministic generation of document content from platform data (collect + per-document derivations) | There is a centralized data collector and per-document derivation modules with unit tests; runDerivation wires them into generation logic. |
| ✅ | Documents are editable and manual overrides are preserved (editing flips source to manual) | Register services explicitly flip derived rows to 'manual' on edit; narrative save and register CRUD exist; UI provides inline edit forms. |
| ✅ | Versioning and approval workflow (submit / approve / decline) with approval invalidation on edits | Document version snapshot upsert, approval DTOs and narrative/version services exist; invalidateApprovalIfNeeded used when edits occur. |
| ✅ | DOCX and PDF export (branded) implemented | Export generator + separate DOCX and PDF renderers exist, with metadata handling including primary colour; docx/jspdf deps added. |
| ✅ | Setup wizard to collect non-derivable inputs and ability to generate all six documents | Wizard schema, controller/service, client components, generate-all DTO and generate flow are implemented and tested; defaults and merging logic present. |
| ✅ | Frontend: overview, per-document detail pages and register UIs (add/update/delete) | Many client components implement overview cards, per-document shells, register tables, add/edit rows, control mapping, and tests are included. |
| ✅ | Drift detection and one-click regenerate flow (snapshot, diff, UI banner) | Snapshot capture, diff logic and UI drift banner plus useIsmsDrift hook and regenerate flows are implemented. |
| ✅ | Control ↔ ISMS document mapping (link/unlink controls) | Backend control-link service and frontend control-mapping UI and APIs are implemented. |
| Exports & generation in a single session (wizard → generate → export all six documents) | All pieces exist (wizard, generateAll, export endpoints and client hooks), showing an end-to-end path. However, end-to-end integration tests or an explicit e2e flow demonstrating export-of-all-six-in-single-session are not present in the diff to fully validate this behavior in CI. | |
| ❌ | Pressmaster and Kidan packs are reproducible and platform output alone closes Stage-1 findings | The issue's DoD requires reproducing specific vendor packs and closing real audit findings; the PR implements the generation pipeline and export tooling, but I see no explicit seeded content, acceptance tests, or sample outputs demonstrating Pressmaster/Kidan comparability or any audit-closing validation artifacts in this diff. |
Tip: instead of fixing issues one by one fix them all with cubic
Partial review: This PR has more than 100 files, so cubic reviewed the highest-priority files first.
For a deeper review of large PRs, comment @cubic-dev-ai ultrareview. Learn more.
Re-trigger cubic
# Conflicts: # apps/app/src/app/(app)/[orgId]/documents/components/SOAOverviewCard.tsx
…(CS-437) - atomic read+write: narrative latest-version read and register nextPosition now run inside their transactions (no stale-version write / position TOCTOU) - control-link add/remove invalidate approval (revert approved doc to draft), consistent with register/narrative edits - DB: partial unique index enforces at most one isLatest=true version per document - shared zod schemas trim before min(1) (whitespace-only no longer passes); the last three forms (interested-parties, requirements, add-issue) import the shared schema instead of duplicating it - wizard page derives org from the [orgId] route param, not session active org - ScopeClient keys the narrative form on the stable version id (no remount on save) - framework-editor link handlers guard against double-linking Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
4 issues found across 23 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Fix all with cubic | Re-trigger cubic
…approval (CS-437) - register creates take a per-document Postgres advisory xact lock before allocating position, so concurrent creates can't read the same max(position) and persist duplicate ordering keys (a moved-read-into-tx alone doesn't serialize under READ COMMITTED). Shared lockDocumentForPositions helper. - control-link add/remove now invalidate approval only when a row actually changes (createMany/deleteMany count > 0), so an idempotent re-link / no-op unlink no longer downgrades an approved document. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
What does this PR do?
Visual Demo (For contributors especially)
A visual demonstration is strongly recommended, for both the original and new change (video / image - any one).
Video Demo (if applicable):
Image Demo (if applicable):
Mandatory Tasks (DO NOT REMOVE)
How should this be tested?
Checklist
Summary by cubic
Adds the ISO 27001 ISMS area with six auto-derived, editable, versioned documents (4.1, 4.2a, 4.2b/c, 4.3, 5.1, 6.2) plus DOCX/PDF export, approvals, drift detection, and a short setup wizard. Delivers CS-437 by letting customers generate auditor-ready foundational documents from existing platform data.
New Features
is-isms-enabledis on) with cards for Context (4.1), Interested Parties (4.2a), Requirements & Treatment (4.2b/c), Scope (4.3), Leadership (5.1), Objectives (6.2); full detail pages with registers or narrative forms.docxandjspdf-autotable.Bug Fixes
@ApiBody; narrative save is atomic and preserves user content unless empty; single isLatest version enforced; register creates serialize position allocation with a per-document advisory lock; stable forms and export usesapiClient.Written for commit e92d083. Summary will update on new commits.