# Document workbench

A browser-local document editor for Free4AllHub. The standalone source in this
package supplies the hosted /tools/documents/ workbench. It adds no account, backend, upload,
telemetry, storage, autosave, external fonts or runtime CDN.

## Build and use

Node 24 was used for validation. Install the exact lockfile with `npm ci`, then
`npm run build`. Serve `dist/` with a static web server, such as
`python3 -m http.server 8057 --directory dist --bind 127.0.0.1`. Open the server
URL in a modern browser. Direct `file://` launch is not promised for ES modules.
Run `npm test` and `npm run browser-test` (requires local Chromium).

Editing uses pinned MIT ProseMirror packages; DOCX export uses pinned MIT docx.
The build emits local ES modules. Export and import use separate workers loaded only when requested. Import uses pinned fflate (MIT) and sax (Blue Oak Model License 1.0.0). The export worker's packer runs off the UI thread and stops on cancellation or after 30 seconds. There is no main-thread fallback. Source,
lockfile, complete third-party notices and provenance belong in the downloadable
source. `evidence/build.json` records exact emitted modules, size, gzip size,
SHA-256 hashes and bundled input files.

## Supported workflow

1. Try the fictional example or start blank. Both stage a review before replacing.
2. Edit paragraphs, semantic headings 1–3, lists, bold, italic and HTTP(S) links.
3. Download an editable JSON project. Export DOCX or readable semantic HTML.
4. Open a fresh editor, choose the JSON, review, explicitly replace, and revise.
5. Download and reopen the revised JSON. Keep prior versions until checked.

JSON is the complete reimportable source. Simple DOCX text and structure can also import with explicit conversion review; see DOCX_IMPORT.md for losses and limits. HTML is an export only. Current work remains during file reads,
validation and review. Invalid files, cancelled reviews and stale reads do not
replace it. Editing current content, title or language cancels a pending read or
replacement review. Repeated Open has no effect after the first replacement.
Editing or starting another open cancels in-progress Word export, so an obsolete
snapshot cannot trigger a later download. No merge is attempted. Downloads have neutral names and do not prove
filesystem save. Closing or refreshing loses tab-only work. Browser unload
warnings are best effort; they are not backups.

## Data and safety bounds

Schema `free4allhub-document`, version 1, with exact top-level fields: schema,
version, title, language and document. The document is a strictly validated
ProseMirror tree. Allowed content is paragraphs, headings, bullet/numbered lists,
list items, text and line breaks. Allowed marks are bold, italic and HTTP(S)
links without embedded credentials. Unknown fields, versions, nodes, marks and
invalid nesting fail closed. Structural normalization is not used to silently
repair imported documents. UTF-8 decoding is fatal before JSON parsing.

Maximum 1 MiB UTF-8 JSON in both the incoming file and the canonical
formatted download (including all link attributes and indentation), 2,500 nodes, 100,000 text characters (UTF-16 units), 120 title
characters, 12 structural depth and 4 list levels. Numbered lists may begin at
1–1000. Empty paragraphs are allowed. Blank titles pause export. Limits reduce
accidental overload, not a promise of performance on every device.

No HTML import or full-fidelity Word import. Paste is handled by the narrow ProseMirror schema, which
drops unsupported markup; it is not a rich Word import. Imported strings are
rendered as text or schema-controlled nodes, not raw HTML. Local file content
is never used as code, CSS, a remote image or a fetch destination. Links do not
navigate inside the editor. The exported HTML has a restrictive policy and
contains no script; its links may navigate on reader activation. All downloaded
files are plain, unencrypted and unredacted.

## Accessibility and document fidelity

The app uses native labeled controls, visible focus, a first-focus Skip link,
`main` focus target, a labeled multiline textbox and live operation status. Tab
leaves the editor rather than indenting a list. Native semantic output preserves
heading elements, `ul`/`ol`/`li`, anchors, emphasis and line breaks. DOCX creates
Word heading paragraph styles, actual numbering properties and external
hyperlink relationships rather than styled text imitations.

This is not a full word processor, accessibility certification or pixel-perfect
Word round-trip. The author still determines heading order, meaningful links,
language and content quality. No images, tables, pagination, footnotes, comments,
tracked changes, collaboration, full Word compatibility or ODT/PDF export. Browser automation
and an automated accessibility scan do not replace screen-reader/real-phone or
keyboard-user testing. Check semantic output in the recipient's document app.

## Hosting and source scope

The hosted route is `/tools/documents/`. This ZIP rebuilds a standalone editor;
the shared Hub navigation wrapper is maintained separately. Both use the same
editor, validation and export modules. The shared Keep & reopen tool accepts
this version 1 editable document JSON through the pinned v33 native parser.
It preserves the file bytes and does not install state in this editor.

To keep a project across tools: export a harmless Learn brief manually, write
the matching handout here, then save the editable document JSON. In Keep &
reopen, choose each native format and add those JSON files. Download the bundle.
In a fresh session, reopen it and download the unchanged document file. Return
here, review the file and explicitly open it; revise, save and reopen the new
JSON. Keep earlier versions until checked. This is manual file transport, not
automatic cross-tool conversion or evidence of learning. DOCX and HTML remain
separate exports and cannot be added as editable document inputs.

The complete document text, title and links remain in the plain, unencrypted
JSON and bundle. No automatic redaction, synchronization, publication or
permanent backup is provided. Keep private files in a location you control.

See TESTING.md for completed checks and remaining device/application limits.

Keep `connect-src 'none'`, `script-src 'self'`, `style-src 'self'`,
`worker-src 'self'`, no blob/remote workers, no external
assets, no inline script and no service worker. The small shared model chunk is
loaded with the editor; the larger DOCX worker module loads only on export. It receives a structured-cloned
plain project and transfers the resulting ArrayBuffer back; it has no storage or
network API calls. Status uses actual preparation/packaging stages, not invented
percentages. Cancellation terminates the worker, and each retry creates a new one. Local source
serving still sends ordinary asset requests to the same origin; it does not send
document contents. Original code is MIT within this package only.

## Simple DOCX text import

This workbench supports local, reviewed conversion of simple DOCX text and structure, plus a fictional downloadable practice file. See DOCX_IMPORT.md for supported features, deliberate losses and security limits. Editable JSON remains the complete editor backup. Full-fidelity Word import is not claimed. See TESTING.md for the dated technical acceptance and remaining device limits.
