# Drawing release register

A local PDF revision register with separate author, reviewer and reader roles. It stores revision-specific approval, a current release pointer, and the original file bytes. The browser interface uses local assets and a dark palette.

## Run

Node.js 24 or newer is required. No npm installation is needed.

```sh
node --experimental-strip-types app.ts --seed --port 8012
```

Open http://127.0.0.1:8012. The default data directory is `data`. Pass `--data /path/to/register` to choose another directory. Only localhost Host and Origin values are accepted. Stop with Ctrl+C.

| Account | Password | Role |
| --- | --- | --- |
| author | author-demo | Create drawings and upload revisions; shop and research access |
| reviewer | review-demo | Review, release, reconcile and export; shop and research access |
| reader | read-demo | Read released and superseded shop revisions only |

These fixed accounts demonstrate permissions. They are not production authentication. Sessions expire after one hour and on process restart. Do not expose this server to the internet.

## Exercise the workflow

1. Sign in as author. Select DRW-100. The seed data contains an initial released revision.
2. Choose `fixtures/sample-document.pdf`, enter a change note and upload it as a new revision. The browser hashes the file, creates a pending revision, stores its bytes and finalizes it.
3. Sign out and sign in as reviewer. Read the latest file, enter a review note and approve that exact revision.
4. Release the approved revision. The previous release becomes superseded, while its file and review remain available.
5. Sign in as reader. The shop release is visible; LAB-200 in the research group is not. The reader cannot upload, approve or release.
6. As reviewer, run reconciliation and download the export. A missing, mismatched, pending or orphan object is reported separately. Reconciliation does not delete files.

The fixture PDF is a portfolio design brief used to exercise upload, not an approved manufacturing drawing. Both demonstrated revision records use the same PDF bytes intentionally; they retain separate revision, change-note and approval identities.

## Verify and reproduce evidence

```sh
node run-tests.mjs
node --experimental-strip-types evidence.ts
```

Tests use temporary directories and HTTP servers. `verification.json` and `results/test-output.txt` record 26 executed tests. Coverage includes two competing HTTP release requests, repeated finalization, stale/latest revision checks, mismatched uploads, immutable verified files, author/reviewer separation, reader/group permissions, Host/Origin/CSRF checks, missing and orphan objects, export checksum rejection and restore.

The evidence script creates two released revisions, injects a finalization failure, confirms that pending bytes cannot be downloaded, then retries finalization. It exports and restores the revision history and checks both file hashes. A separate damaged store contains one missing object, one orphan and one stored pending object; these are detected by reconciliation.

`report.html` opens directly without the server. Optional report regeneration uses Python 3's standard library:

```sh
python build_report.py
```

## Restore an export

Download an export as reviewer, or use `results/sample-export.json` to try the example. The destination must not already exist.

```sh
node --experimental-strip-types app.ts restore results/sample-export.json --data restored-register
node --experimental-strip-types app.ts --data restored-register --port 8012
```

Restore verifies the manifest digest, object keys, PDF byte hashes, release pointers and matching approvals. It then writes metadata and files to the new location. Keep the original store. An ordinary failure removes its own new destination. An abrupt process loss can leave a RESTORE_INCOMPLETE marker, which prevents serving the partial store. Preserve it for diagnosis and restore into a different new directory. This is a local export/restore path, not a live backup scheduler.

To back up a stopped service, copy the complete data directory, including its `objects` directory and SQLite files. Do not copy only the database while it is being written. Use a new `--data` path to start another synthetic example without deleting the old one.

## Rules and limits

- Each uploaded PDF is at most 10 MiB. Validation checks `%PDF-`, `%%EOF`, byte length and SHA-256; it does not parse engineering content or scan for malware.
- Upload writes and fsyncs a temporary file, then links it under a new object key without replacement. The revision remains pending until a transaction verifies the bytes. Directory metadata is not explicitly fsynced; sudden power loss has not been qualified.
- A verified revision's file cannot be changed through the application. A reviewer must approve the latest revision and the matching hash. The author cannot approve their own file.
- Release uses `BEGIN IMMEDIATE` and an expected release version. It supersedes the old release and advances the pointer atomically. Repeating a successful release returns its earlier result.
- Exports contain accessible groups, metadata, audit history and base64 PDF bytes. The export limit is 48 MiB of PDF content and the JSON is assembled in memory.
- SQLite and a local object directory replace the earlier hosted database/object-storage plan. There is no public multi-user deployment, malware scanning, CAD format support, electronic-signature certificate or physical manufacturing approval.

## Files

`app.ts` contains storage rules and HTTP routes. `schema.sql` defines version 1. `static/` contains the interface. `tests.test.ts` and `run-tests.mjs` execute tests. `evidence.ts` rebuilds the synthetic outputs under `results/`. `delivery.json` describes this package for the portfolio; `verification.json` records the most recent test run.

The package contains no runtime database or session. `results/sample-export.json` contains only synthetic records and the supplied fixture document.

## Extended verification

Run `node complete.mjs` for client-source upload/export, real process-crash recovery and the theoretical deployment model. Read [completion-report.html](completion-report.html) and [OPERATIONS.md](OPERATIONS.md). The client rehearsal uses a modeled DOM with real WebCrypto, HTTP, SQLite and exact export bytes; it is the executed substitute for the secure-context/file-download limitations in the HTTP browser preview. It does not claim browser-native upload or save completion.
