# Documents Module — Production Baseline

**Status:** ✅ Production-ready — FROZEN
**Baseline date:** 2026-07-12
**Owner routes:** `/documents/*`, `/_authenticated/documents/dashboard`, `/_authenticated/manage/documents`

> Do not modify functionality in this module without opening a verified defect
> or security ticket. Refer to the regression checklist (§10) for any change.

---

## 1. Technical documentation

### 1.1 Feature map

| Feature                | Route                                 | Primary storage bucket | Primary tables                                               |
| ---------------------- | ------------------------------------- | ---------------------- | ------------------------------------------------------------ |
| AI Scanner + OCR       | `/documents/scanner`                  | `scans`                | `ocr_jobs`, `ocr_extractions`, `document_processing_history` |
| PDF Toolkit            | `/documents/pdf-toolkit`              | `scans` (outputs)      | `document_processing_history`                                |
| AI Signature           | `/documents/signature`                | `signatures`           | `user_signatures`, `document_processing_history`             |
| AI Translator          | `/documents/translate`                | `translated`           | `translation_jobs`, `document_processing_history`            |
| Document Verification  | `/documents/verify`                   | `verified`             | `doc_authenticity_checks`, `document_processing_history`     |
| CV Builder             | existing career routes                | `cvs`                  | existing `generated_documents`                               |
| Cover Letter Generator | existing career routes                | `cover-letters`        | existing `generated_documents`                               |
| User Dashboard         | `/_authenticated/documents/dashboard` | — (aggregates)         | `document_processing_history` + all above                    |
| Admin Dashboard        | `/_authenticated/manage/documents`    | — (aggregates)         | all above + `storage.objects`                                |

### 1.2 Shared infrastructure

- `src/lib/documents/storage.ts` — canonical helpers:
  - `uploadOwnerFile()` — writes to `<bucket>/<userId>/…` with content-type detection.
  - `signedUrl()` / `downloadOwnerFile()` / `deleteOwnerFile()`.
  - `logActivity()` — writes to `document_processing_history`.
  - `sha256Hex()` — file/data hashing for verification and dedup.
- Client library: `@/integrations/supabase/client` (publishable key, user session, RLS as user).
- Server AI calls: `createServerFn` + Lovable AI Gateway (`google/gemini-3-flash-preview` for OCR/translate).
- PDF ops: `pdf-lib` (write) + `pdfjs-dist` (render/preview) — fully client-side.
- Barcode/QR: `jsqr` + `@zxing/browser` — client-side.

### 1.3 Route architecture

All feature routes are public TanStack Start routes; individual actions require a Supabase session and RLS enforces per-user data scoping. Dashboards and admin live under the integration-managed `_authenticated/` layout.

---

## 2. Database schema

All tables live in `public`, own an `id UUID PK`, `created_at TIMESTAMPTZ DEFAULT now()`, and `user_id UUID` referencing `auth.users(id)`.

### 2.1 `ocr_jobs`

16 columns — tracks a single scan/upload submitted to OCR.
Key columns: `user_id`, `source_bucket`, `source_path`, `mime_type`, `size_bytes`, `file_hash`, `status`, `provider`, `error`, `metadata`.
Indexes: `ocr_jobs_user_id_idx`, `ocr_jobs_hash_idx` (dedup lookup).

### 2.2 `ocr_extractions`

12 columns — extracted text + block-level results linked to a job.
Key columns: `job_id → ocr_jobs.id`, `user_id`, `text`, `language`, `confidence`, `blocks JSONB`, `page`.
Indexes: `ocr_extractions_user_idx`, `ocr_extractions_job_idx`.

### 2.3 `user_signatures`

10 columns — persistent signature library.
Key columns: `user_id`, `label`, `kind` (`draw`/`type`/`upload`), `storage_bucket='signatures'`, `storage_path`, `width_px`, `height_px`, `metadata`.

### 2.4 `translation_jobs`

13 columns — one row per translation request.
Key columns: `user_id`, `source_lang`, `target_lang`, `source_text`, `translated_text`, `source_bucket`, `source_path`, `output_bucket`, `output_path`, `provider`, `metadata`.
Index: `idx_tj_user_created`.

### 2.5 `doc_authenticity_checks`

15 columns — verification runs and report references.
Key columns: `user_id`, `file_name`, `file_hash`, `mime_type`, `authenticity_score` (0–100), `qr_payloads JSONB`, `barcode_payloads JSONB`, `pdf_metadata JSONB`, `tamper_findings JSONB`, `report_bucket='verified'`, `report_path`.
Index: `idx_dac_user_created`.

### 2.6 `document_processing_history`

11 columns — unified audit/timeline used by dashboards.
Key columns: `user_id`, `tool` (`scanner`|`pdf-toolkit`|`signature`|`translate`|`verify`|`cv`|`cover-letter`), `action`, `document_id`, `file_name`, `storage_bucket`, `storage_path`, `size_bytes`, `metadata`.
Indexes: `idx_dph_user_created`, `idx_dph_tool`.

---

## 3. Storage buckets

All buckets **private**. Path convention: `<userId>/<subdir?>/<timestamp>-<rand>.<ext>`.

| Bucket          | Contents                                               | Retention        |
| --------------- | ------------------------------------------------------ | ---------------- |
| `scans`         | Original OCR uploads + PDF Toolkit outputs             | User-managed     |
| `signatures`    | Signature image assets referenced by `user_signatures` | Deleted with row |
| `translated`    | Translated document outputs (txt/pdf/docx)             | User-managed     |
| `verified`      | Verification PDF reports                               | User-managed     |
| `cvs`           | Generated CV PDFs                                      | User-managed     |
| `cover-letters` | Generated cover letter PDFs                            | User-managed     |

RLS on `storage.objects`: 27 policies, one INSERT / SELECT / UPDATE / DELETE per bucket, all scoped to `(storage.foldername(name))[1] = auth.uid()::text`. Admins can read across buckets via `has_role(auth.uid(),'admin')`.

---

## 4. API reference

All server logic uses `createServerFn` from `@tanstack/react-start`. No Supabase Edge Functions are used by this module.

### 4.1 Client-callable server functions

| Function            | File                                       | Auth | Purpose                                                    |
| ------------------- | ------------------------------------------ | ---- | ---------------------------------------------------------- |
| `runOcr`            | `src/lib/documents.scanner.functions.ts`   | user | Calls Gemini via AI Gateway, returns OCR text + confidence |
| `translateDocument` | `src/lib/documents.translate.functions.ts` | user | Structured translation with quality scoring                |
| `verifyDocument`    | `src/lib/documents.verify.functions.ts`    | user | Server-side companion to client tamper checks              |

### 4.2 Client-only libraries (no network)

| Concern               | Library                       |
| --------------------- | ----------------------------- |
| PDF read/write        | `pdf-lib`, `pdfjs-dist`       |
| Image OCR pre-process | canvas / `<img>` transforms   |
| QR decode             | `jsqr`                        |
| Barcode decode        | `@zxing/browser`              |
| Hashing               | `crypto.subtle` (`sha256Hex`) |

### 4.3 Direct Supabase Data API operations

Owner-scoped `select`/`insert`/`update`/`delete` against the tables in §2 using the browser client. All calls rely on RLS — no filter-by-user-id is trusted on the server without an RLS check.

---

## 5. User guide

### Scanner

1. `/documents/scanner` → drop or select an image/PDF, or tap the camera on mobile.
2. The file uploads to your private `scans/` folder and OCR runs automatically.
3. Edit the extracted text; use **Save** to persist. History appears on the right.

### PDF Toolkit

1. `/documents/pdf-toolkit` → choose an action tab (Merge, Split, Rotate, Reorder, Delete pages, Extract pages, Compress).
2. Drop PDF files, configure the action, run. Result downloads locally and is also stored in `scans/`.

### Signature

1. `/documents/signature` → create a signature (Draw / Type / Upload) and save it to your library.
2. Load any PDF, drag the signature onto a page, resize/rotate, then **Apply & Download**.

### Translator

1. `/documents/translate` → paste text or upload a file; choose one of 58 target languages.
2. Result is downloadable and appears in history.

### Verify

1. `/documents/verify` → drop the document.
2. See QR/barcode contents, PDF metadata, tamper findings and the 0–100 authenticity score.
3. **Download report** produces a PDF stored under `verified/`.

### Dashboard

`/documents/dashboard` — live metrics: tool usage, recent activity, total storage used.

---

## 6. Administrator guide

Route: `/manage/documents` — requires the `admin` role in `user_roles`.

Capabilities:

- Aggregate metrics (docs processed per tool, storage per bucket, active users).
- Recent verifications feed with authenticity scores.
- Moderation: delete a stored file (removes from bucket **and** owning row).

### Granting admin

```sql
insert into public.user_roles(user_id, role) values ('<uuid>', 'admin');
```

### Handling abuse reports

1. Locate the file in the Admin Dashboard.
2. Verify against `document_processing_history` for context.
3. Delete — this cascades to storage via the moderation action.

---

## 7. Maintenance guide

### Routine checks

- **Monthly:** review Supabase → Storage usage per bucket; alert if any bucket >80% of quota.
- **Monthly:** `select tool, count(*) from document_processing_history where created_at > now()-interval '30 days' group by tool;` — usage sanity.
- **Quarterly:** re-run linter: `bunx tsgo --noEmit` and `bunx eslint .`.
- **Quarterly:** verify RLS regression suite (`.github/workflows/rls-regression.yml`) still green.

### Dependency upgrades

Keep `pdf-lib`, `pdfjs-dist`, `@zxing/browser`, `jsqr` current at minor versions only. Major upgrades require running the full regression checklist in §10.

### AI provider rotation

OCR/translation use `LOVABLE_API_KEY`. If a translation returns the fallback stub (visible as `[<lang>]\n\n<source>` with a critical issue), the key is missing or the Gateway is degraded — check Cloud settings.

---

## 8. Backup and recovery

### Backups

- **Database:** Supabase automated daily backups (managed).
- **Storage buckets:** rely on Supabase object durability. For extra safety, schedule a monthly export of `scans`, `signatures`, `verified` to cold storage via Cloud → Advanced settings → Export data.

### Recovery procedures

| Scenario                 | Steps                                                                                                                                |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
| Accidental table drop    | Restore from the most recent Supabase daily backup. Re-run migrations only if the missing table post-dates the backup.               |
| Corrupted history row    | `document_processing_history` is a log — safe to delete a bad row; source-of-truth remains in the tool-specific table.               |
| Storage object lost      | Recreate from user's local copy (originals live client-side too); OCR/translation results can be re-run from the source in `scans/`. |
| Verification report lost | Re-run verify against the same source file — the algorithm is deterministic given identical input.                                   |
| Compromised bucket       | Rotate the publishable key via Supabase settings, then audit `document_processing_history` for anomalous writes.                     |

---

## 9. Security architecture

- **AuthN:** Supabase Auth; browser holds publishable key + user JWT.
- **AuthZ:** RLS on every table (owner-scoped via `auth.uid()`); `has_role()` SECURITY DEFINER for admin overrides.
- **Storage:** all 6 buckets private; owner-scoped policies on `storage.objects`; access only via signed URLs (`signedUrl()` helper).
- **Path isolation:** every write goes to `<userId>/…`; the path prefix policy makes cross-user reads impossible even if signed URLs leaked their pattern.
- **Server functions:** privileged calls use `requireSupabaseAuth`; service role is never touched from the client.
- **AI Gateway:** `LOVABLE_API_KEY` is server-only, read inside handlers.
- **Content trust:** OCR/translation text is treated as untrusted user input everywhere it renders.
- **PII:** the module stores whatever the user uploads. Retention is user-managed; deletion of a row triggers bucket cleanup only via admin moderation — end-users delete via the dashboard which removes both.

---

## 10. Regression test checklist

Run before shipping ANY change that touches Documents code, storage, or the six tables in §2.

### Build & types

- [ ] `bunx tsgo --noEmit` — 0 errors.
- [ ] `bun run build` succeeds.
- [ ] No new `TODO`/`FIXME`/mock refs introduced.

### Route smoke

- [ ] `/documents` renders hub with links to all tools.
- [ ] Each of the 8 module routes loads without console errors.
- [ ] `/manage/documents` blocks non-admin users.

### Scanner

- [ ] Upload PNG → OCR text appears → row in `ocr_jobs` + `ocr_extractions`.
- [ ] Upload PDF → same.
- [ ] Mobile camera capture returns to an editable OCR result.
- [ ] History panel shows the new scan.

### PDF Toolkit

- [ ] Merge 2 PDFs downloads a combined file.
- [ ] Split by page range produces N files.
- [ ] Rotate/Reorder/Delete/Extract each round-trip successfully.
- [ ] Compress reports a reduced size in `document_processing_history.metadata`.

### Signature

- [ ] Draw + save → row in `user_signatures` + object in `signatures/`.
- [ ] Load PDF, drag signature, apply → output PDF downloads with signature at the placed position.

### Translator

- [ ] Translate to 3 different target languages → 3 rows in `translation_jobs`.
- [ ] Empty/invalid input returns a graceful validation error, not a crash.

### Verify

- [ ] Upload a QR-bearing image → payload decoded and shown.
- [ ] Upload a PDF → metadata + score rendered; **Download report** yields a PDF stored in `verified/`.
- [ ] Hash of identical file is stable across runs.

### Dashboards

- [ ] User dashboard counts match `document_processing_history` aggregates.
- [ ] Admin dashboard delete removes both DB row and storage object.

### Security

- [ ] Sign in as user B, attempt to `select` from user A's rows in each of the 6 tables → 0 rows.
- [ ] Attempt `download` on another user's storage object → 403.
- [ ] Admin read policy on OCR tables verified with a role-assigned test user.

### Performance

- [ ] Initial `/documents/verify` bundle < 400 KB gzipped.
- [ ] Dashboard query returns in < 500 ms for a user with 1,000 history rows.

---

**Sign-off:** any PR that closes a Documents defect must attach a filled copy of §10 in its description.
