CCS PDF Editor · Docs

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:

  1. Renders PDF pages (PDF.js canvas + text layer + interactive AnnotationLayer for widgets).
  2. Lets staff annotate with DOM overlays in Editor workspace.
  3. Lets staff fill form fields in Editor with Pointer (native widgets and/or designer fill surfaces).
  4. Lets staff design fillable AcroForm fields in Form workspace; supported native widgets are auto-imported as designer overlays (no prompt).
  5. Optionally runs local OCR (Tesseract.js + English data under lib/; file:// uses base64 embeds).
  6. Exports either:
  7. Opens many password-protected PDFs via PDF.js onPassword UI.
  8. 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

  1. User selects file(s), drops onto the viewer, or (Windows shell) uses Open with / argv path.
  2. Bytes enter memory (ArrayBuffer).
  3. If encrypted, PDF.js onPassword drives the password modal; user password unlocks the document.
  4. PDF.js renders each page to canvas (annotationMode DISABLE so widgets are not double-painted).
  5. Text layer + AnnotationLayer (renderForms: true) for interactive native widgets.
  6. Source bytes retained in window.sourcePdfBuffers[fingerprint] for later export.
  7. If file is .ccspdf, trailer schema reapplied as overlays.
  8. 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

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)

  1. Acquire save destination first (native picker / modal) while user gesture is valid.
  2. For each page: copy original PDF page via pdf-lib; serialize overlay + form-field JSON.
  3. Gzip + hash edit state; append after PDF bytes with markers.
  4. Write blob to destination.

4.5 Save PDF (annotations flattened + fillable fields)

  1. Acquire save destination first (critical for Chromium File System Access API).
  2. If the UI is in Form mode, temporarily restore full-opacity annotations for capture.
  3. 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.
  4. After all pages exist: create AcroForm widgets (text, checkbox, radio group, dropdown; signature field where supported).
  5. Optionally encrypt the finished bytes with a user password via QPDF (WASM) (content-preserving; AcroForm fields remain fillable).
  6. Write the final PDF.

4.6 OCR

  1. Tesseract worker initialized with local workerPath, corePath, langPath under ./lib/.
  2. On file://, worker/core/lang assets load via base64 embeds + IndexedDB language seed (CORS-safe).
  3. Canvas pixels recognized in-browser; text layer spans injected for selection/stamp tools.
  4. 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.ps1app/ + launchers; file:// supported with embeds
Windows WebView2 scripts/build-windows.ps1CcsPdfEditor.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)

8.2 Windows WebView2 shell (supported optional)

8.3 Browser offline pack (supported optional)

8.4 What not to do


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).

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)

  1. Valid PDF body (with or without /CCSProject).
  2. Trailing ASCII marker: \n---CCS-SAVE-STATE---.
  3. 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

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.