CCS PDF Editor — Architecture
| Field | Value |
|---|---|
| Version | 1.5.40 |
| Owner | CCS Information Technology |
| Approved by | CCS Information Technology |
| Last updated | 2026-08-15 |
| Review frequency | Annual (or after significant architectural change) |
| Next review | 2027-08-05 |
High-level design of the CCS PDF Editor as an offline-first, client-side application. For ownership and residual risk see SYSTEM-PROFILE.md and GOVERNANCE.md. For deploy overview see README.md.
1. Purpose of the system
CCS PDF Editor is a static web application (optional Windows WebView2 shell) that:
- Renders PDF pages (PDF.js canvas + text layer + interactive AnnotationLayer for widgets).
- Lets staff annotate with DOM overlays in Editor workspace.
- Lets staff fill form fields in Editor with Pointer (native widgets and/or designer fill surfaces).
- Lets staff design fillable AcroForm fields in Form workspace; supported native widgets are auto-imported as designer overlays (no prompt).
- Optionally runs local OCR (Tesseract.js + English data under
lib/;file://uses base64 embeds). - Exports either:
- Project (
.ccspdf) — PDF bytes + appended compressed edit state (overlays + form layout), or - Final PDF — source pages + rasterized annotation layer (html2canvas) + live form widgets (pdf-lib AcroForm), optional QPDF (WASM) password protect.
- Opens many password-protected PDFs via PDF.js
onPasswordUI. - Prints via the browser/print pipeline (full-opacity annotations; form designer chrome omitted).
It is not multi-tenant SaaS, not a document management system, and not a certified electronic signature platform.
2. Context diagram
┌─────────────────────────────────────┐
│ Optional: intranet reverse proxy │
│ TLS · optional SSO / IP allowlist │
└──────────────────┬──────────────────┘
│ HTTPS (static only)
▼
┌─────────────────────────────────────┐
│ Static web host │
│ index.html, js/, lib/, assets/ │
│ NO document database / upload API │
└──────────────────┬──────────────────┘
│ download assets once
▼
Local PDF / .ccspdf ──────►┌──────────────────────┐──────► Saved PDF / .ccspdf
(user disk / share) │ Browser tab memory │ (user disk / share)
│ PDF.js · overlays │
│ pdf-lib · Tesseract │
└──────────────────────┘
│
▼
Printer / PDF printer
(OS / org print path)
Optional alternate runtimes:
· Windows WebView2 shell (deploy_windows / build-windows.ps1)
· Browser offline zip pack (build-release.ps1) — file:// capable
· Tauri-style shell if adopted later (same static UI)
3. Application layering
┌──────────────────────────────────────────────────────────┐
│ Browser / WebView2 DOM │
│ index.html · style.css · fonts.css · modals │
└────────────────────────────┬─────────────────────────────┘
│
┌────────────────────────────▼─────────────────────────────┐
│ js/ui/* Toolbars, modals, hotkeys, header density│
│ js/interaction/* Mouse, keyboard, drag, file import │
│ js/overlays/* Text, shapes, images, tables, snip, │
│ form-fields (design + Editor fill UI) │
│ js/features/* OCR, print, signature + form attestation │
│ js/engine/* PDF render, AnnotationLayer, native-forms│
│ js/core/* State, history, import/export (io.js) │
│ host-bridge (WebView2 open-with) │
└────────────────────────────┬─────────────────────────────┘
│
┌────────────────────────────▼─────────────────────────────┐
│ lib/* PDF.js · pdf-lib · qpdf.wasm · html2canvas · │
│ Tesseract (+ offline embeds for file://) · fonts │
└──────────────────────────────────────────────────────────┘
| Layer | Responsibility |
|---|---|
| UI | Workspace switch, tools, dialogs, responsive header |
| Interaction | Pointer tools, multi-select, zoom/scroll; workspace isolation |
| Overlays | Annotation objects + form designer + Editor fill surfaces |
| Engine | PDF.js canvases, text layer, interactive form widgets, auto-import |
| Core I/O | Load PDF/project; save project; flatten + AcroForm + optional QPDF encrypt |
| lib/ | Third-party engines (see NOTICE) |
There is no required JS build pipeline for the static web UI. Scripts load with defer from index.html. Windows EXE is produced separately via scripts/build-windows.ps1.
4. Core runtime flows
4.1 Open PDF
- User selects file(s), drops onto the viewer, or (Windows shell) uses Open with / argv path.
- Bytes enter memory (
ArrayBuffer). - If encrypted, PDF.js
onPassworddrives the password modal; user password unlocks the document. - PDF.js renders each page to canvas (annotationMode DISABLE so widgets are not double-painted).
- Text layer + AnnotationLayer (
renderForms: true) for interactive native widgets. - Source bytes retained in
window.sourcePdfBuffers[fingerprint]for later export. - If file is
.ccspdf, trailer schema reapplied as overlays. - Otherwise, supported native widgets are auto-imported as Form designer overlays (silent); matching native AnnotationLayer sections are hidden so Editor fill uses the designer fill surface without doubles.
4.2 Edit / fill
- Annotation overlays are DOM elements inside
.pageContainer. - Form filling in Editor + Pointer: native AnnotationLayer widgets and/or
.form-field-fillcontrols on designer overlays. - Undo/redo records DOM operations via
historyEngine. - No server round-trip.
4.3 Workspaces (Editor vs Form)
APP.workspaceMode is "editor" or "form". Body classes workspace-editor / workspace-form (and tool-select) control hit-testing:
| Mode | Annotations | Form widgets | Native AnnotationLayer |
|---|---|---|---|
| Editor + Pointer | Full, interactive | Fill surfaces active | Interactive (unless hidden after import) |
| Editor + other tool | Interactive | Fill PE off | PE off (don’t steal annotate clicks) |
| Form | Dimmed, PE none | Design chrome + handles | Dimmed, PE none |
Switching into Form always selects Pointer. Save PDF and Print temporarily apply full-opacity annotation styling so Form-mode dimming is not included in output.
4.4 Save Project (.ccspdf)
- Acquire save destination first (native picker / modal) while user gesture is valid.
- For each page: copy original PDF page via pdf-lib; serialize overlay + form-field JSON.
- Gzip + hash edit state; append after PDF bytes with markers.
- Write blob to destination.
4.5 Save PDF (annotations flattened + fillable fields)
- Acquire save destination first (critical for Chromium File System Access API).
- If the UI is in Form mode, temporarily restore full-opacity annotations for capture.
- For each page: copy the source page; if decorative overlays exist, hide form designer widgets and the base canvas, rasterize overlays, and embed the PNG.
- After all pages exist: create AcroForm widgets (text, checkbox, radio group, dropdown; signature field where supported).
- Optionally encrypt the finished bytes with a user password via QPDF (WASM) (content-preserving; AcroForm fields remain fillable).
- Write the final PDF.
4.6 OCR
- Tesseract worker initialized with local
workerPath,corePath,langPathunder./lib/. - On
file://, worker/core/lang assets load via base64 embeds + IndexedDB language seed (CORS-safe). - Canvas pixels recognized in-browser; text layer spans injected for selection/stamp tools.
- No remote OCR endpoint in this release.
4.7 Print
Temporarily uses full-opacity annotation styling, clones page canvases and annotation overlays (not form designer chrome), then opens the browser print dialog.
5. Data flow & trust boundaries
| Boundary | Trust assumption |
|---|---|
| Static host → browser | Assets are authentic CCS release (HTTPS + host controls) |
| User disk → browser | User chose a file they are allowed to open |
| Browser → user disk | User chooses save location; OS permissions apply |
| Browser → network | Should not upload document content; only loads same-origin assets (SW is network-only pass-through) |
5.1 In-memory data
While a document is open, memory may hold: full PDF bytes, high-resolution canvases, overlay HTML (including text that may be PHI), form-field designer state, OCR results, and signature/image bitmaps.
5.2 Persistence
| Store | Content | Controlled by |
|---|---|---|
| User filesystem | Saved PDF / .ccspdf |
User + OS ACLs + org DLP |
| Browser download folder | Fallback saves | User profile |
| Cache Storage (if SW improved) | App assets only (intended) | Service worker design |
| Server disk | Static app files only | CCS IT |
6. Offline-first model
| Asset | Offline strategy |
|---|---|
| Application JS/CSS/HTML | Deployed on host; intended for local cache / PWA |
| PDF.js worker / cmaps | Vendored under lib/ |
OCR engine + eng.traineddata |
Vendored under lib/; embeds for file:// |
| QPDF WASM | Vendored qpdf.js + qpdf.wasm (+ embed for file:// encrypt) |
| Fonts | Self-hosted assets/*.woff2 via fonts.css |
| User PDFs | Always local to the user |
Service worker (sw.js): network-only pass-through (PWA installability); no Cache API precache or fallback. Offline intent = no CDN hard-dependency + vendored lib/ / assets on the origin; script/CSS freshness via config.js ?v=.
Deploy modes:
| Mode | Notes |
|---|---|
| HTTPS intranet (primary) | Preferred production; PWA manifest / SW work |
| Browser zip pack | scripts/build-release.ps1 → app/ + launchers; file:// supported with embeds |
| Windows WebView2 | scripts/build-windows.ps1 → CcsPdfEditor.exe + app/ + tools\ |
7. Security design notes
| Topic | Approach |
|---|---|
| AuthN/Z | Outside the app (network edge) |
| XSS | Prefer textContent / sanitizer for restored HTML (sanitizeHTML); keep third-party libs updated |
| Supply chain | Vendor libs in-repo; no runtime npm install on host |
| Save gesture | Destination acquired before long export work (File System Access activation) |
| Secrets | None in client application code; no third-party API keys required |
| CSP | Optional host header; validate wasm requirements for Tesseract/PDF.js before enabling a restrictive policy |
8. Deployment topologies
8.1 Internal OWA (primary)
- Static files on intranet web server.
- Path example:
/pdf-edit/matchingmanifest.jsonstart_url. - Access: VPN / campus network / reverse-proxy auth as CCS prefers.
8.2 Windows WebView2 shell (supported optional)
- Same static UI under
app/, hosted in a small WinForms + WebView2 EXE. - Open with / file associations via
tools\Register File Types.bat(HKCU). - Desktop icon via
tools\Create Desktop Shortcut.bat. - Single-instance named pipe for second-launch file handoff.
- Inventory separately on SYSTEM-PROFILE if production.
8.3 Browser offline pack (supported optional)
scripts/build-release.ps1stagesapp/+ launchers + docs.- Edge/Chrome
--app=launchers; works offline including OCR/encrypt embeds.
8.4 What not to do
- Do not put an unauthenticated public internet copy if staff will open PHI without compensating controls.
- Do not add a “upload PDF to server for processing” feature without a full architecture and governance revision (data store, access control, audit, retention).
- Do not load OCR models from public CDNs in production CCS builds.
9. File format: .ccspdf / embedded project state
CCS project files are valid PDFs that also carry an editable schema + optional audit.
9.0 Primary: Catalog dictionary /CCSProject (schema 4.0+)
Stored on the document catalog (private key ignored by most readers):
| Key | Meaning |
|---|---|
/Type |
/CCSProject |
/Ver |
(4.0) |
/Fmt |
/GZipHex — JSON → gzip → hex in /Data |
/Hash |
Integrity string (same salt recipe as legacy trailer) |
/Data |
<hex…> of the gzip payload |
Implemented in js/core/project-state.js. Load tries legacy trailer first (if present), then catalog.
Save Project (.ccspdf) and Export PDF (.pdf) both embed /CCSProject (no trailer by default).
.ccspdf: re-editable package — open in CCS to restore overlays; other apps only show base PDF + AcroForm.- Export PDF: stamps baked into pixels for any reader; form fields remain fillable; schema is audit/restore of forms.
Trailer dual-write is opt-in only (dualWriteTrailer: true).
Resilience note: Other editors may strip unknown catalog keys on “Save as”. Hex-in-catalog is the standard private-data pattern; full legal non-repudiation still needs signed metadata / external e-sign when required.
9.1 Legacy trailer (still written + read)
- Valid PDF body (with or without
/CCSProject). - Trailing ASCII marker:
\n---CCS-SAVE-STATE---. - Integrity hash + delimiter + gzip-compressed JSON schema of overlays and optional rolling audit.
| Field | Purpose |
|---|---|
version |
Schema version string (3.1 trailer-only, 4.0 embedded) |
pdfName |
Suggested file name |
pages[] |
Per-page overlay / form-field layout |
audit[] |
Optional rolling change log (see §9.2) |
storage |
Optional: catalog-CCSProject / catalog+trailer |
Ordinary PDF readers open the PDF portion; edit restore requires this application (or a compatible tool that understands trailer and/or /CCSProject).
9.2 Rolling project audit (insight log)
High-signal changes while a document is open are recorded in memory (js/core/project-audit.js) and written into the trailer on Save Project.
| Cap | Value |
|---|---|
| Rolling entry count | 200 (oldest dropped) |
| Compressed audit size safety | ~128 KB gzip of audit[] (oldest dropped until under) |
| Schema field | audit[] (schema version 3.1+) |
Entry shape (approx.): { id, t (ISO-8601), action, detail? }
Typical action codes: FIELD_CREATED, FIELD_FILLED, FIELD_SIGNED, FIELD_IMPORTED, TEXT_ADDED, IMAGE_ADDED, SHAPE_ADDED, OVERLAY_DELETED, OVERLAY_TRANSFORM, PAGE_CHANGE, SAVE_PROJECT, plus coarse EDIT fallbacks from history.
Guarantees / non-goals
- Insight for support and contested-project review — not a keystroke log, not multi-user collaboration history.
- Not identity-bound to Windows/Entra user; the app has no login.
- Strings truncated; passwords and bulk PHI values are not retained for their own sake.
- Export PDF also embeds
/CCSProject(schema includes overlays/forms for re-edit; decorative layers are still flattened into page pixels). - File-level who/when remains OneDrive / network share versioning where staff save files.
9.3 Layered seal + form-signature attestation
Project schema may include a .seal object built so hashes do not loop on themselves (js/core/project-state.js, js/core/project-crypto.js):
| Field | Meaning |
|---|---|
originHash |
SHA-256 of bytes when the document was first opened this session |
contentHash |
SHA-256 of PDF bytes before /CCSProject is attached |
schemaHash |
SHA-256 of schema JSON without .seal |
| Optional ECDSA | Device-local WebCrypto signature over seal material (not a TSA) |
Form signature fields (Editor fill): fixed attestation wording, signed name, ISO time, basic browser/device meta, and digests are stored on the field and included in schema → schemaHash. UI shows a compact caption with mid-length hashes; a body-level hover popover exposes full hex with Copy (js/features/signature.js).
This is device-local attestation, not certified legal e-sign / identity proofing.
9.4 Incident extraction (IT)
To extract project state / audit without opening the editor (supports catalog /CCSProject and legacy trailer):
| Context | How |
|---|---|
| Windows install package | Drag .ccspdf or Export PDF onto tools\Extract Project Audit.bat |
| Windows install package | powershell -File tools\scripts\extract-ccspdf-audit.ps1 -Path "…\file.ccspdf" -FullSchema -ExtractPdf |
| Source / offline pack | powershell -File scripts\extract-ccspdf-audit.ps1 -Path "…\file.pdf" -FullSchema -ExtractPdf |
| Source / offline pack | Drag onto scripts\Extract-Ccspdf-Audit.bat |
Prefer trailer when both exist (same as app open path); use -PreferCatalog to force catalog.
Outputs (folder *_extract next to the source file):
| File | Content |
|---|---|
*_summary.txt |
Storage source, integrity, seal hashes, form signatures, chronological audit |
_audit.json / _audit.csv |
Machine-readable log |
*_seal.json |
Layered seal when present |
*_signatures.json |
Form signature attestations when present |
*_schema.json |
Full schema JSON (-FullSchema) |
*_body.pdf |
Trailer stripped, or source copy for catalog-only (-ExtractPdf) |
Verifies the integrity hash using the same algorithm as the app (Uint8Array comma-join + salt CCS-SAVE-HASH-CHECK-S4lT!!). This is decode/gunzip, not QPDF password removal. Exit code 0 = integrity OK; 2 = hash mismatch (artifacts still written for investigation).
Training lab: USER-TRAINING.md Track D · SOP: WINDOWS-INSTALL-SOP.md §8.
(§9.4 continues the extract workflow formerly numbered §9.3 in older docs.)
10. Related documentation
| Document | Purpose |
|---|---|
| SYSTEM-PROFILE.md | Owners, host fields |
| GOVERNANCE.md | Process, residual risk |
| DEVELOPMENT-STANDARDS.md | How to change code safely |
| HOW-TO.md | Staff landing how-to (docs/index.html) |
| USER-GUIDE.md | Operator how-to |
| NOTICE | Third-party stack |
Rendered for the browser from repository markdown. Edit the .md sources, then re-run powershell -File docs/marketing/render-docs.ps1 from the repo root.