mirror of
https://github.com/lllin000/PaperForge.git
synced 2026-07-22 17:00:23 +00:00
- Replace W4-S3 (old lifecycle stepper) with new paper mode specs: status strip, overview card, discussion card, workflow toggles, files row, technical details - Add W4-S4: workspace path detection keeps paper mode for fulltext.md - Add W4-S5: global mode as system homepage - Add W4-S6: workflow toggle checkboxes sync to Base via processFrontMatter (no extra sync needed)
7.7 KiB
7.7 KiB
UX Contract — Verifiable Workflow Specifications
This document defines concrete, single-measurement step sequences for every PaperForge user workflow. Every step has a Trigger (what the user does), a Measurable Outcome (what we verify), and an Error Contract (how failure presents). Journey tests validate against this contract.
Workflow 1: First-Time Installation
| Step ID | Trigger | Action | Measurable Outcome | Error Contract |
|---|---|---|---|---|
| W1-S1 | Run paperforge setup --headless --vault /tmp/pf-test |
Vault selection / directory creation | {vault}/paperforge.json exists with valid JSON containing system_dir, resources_dir, literature_dir |
Exit code != 0; stderr: "Failed to create vault directory" |
| W1-S2 | Setup writes config file | Config file generated | {vault}/paperforge.json keys: version (string), system_dir (string), resources_dir (string), literature_dir (string), base_dir (string) |
Exit code != 0; stderr: "Failed to write paperforge.json" |
| W1-S3 | Setup writes .env with API token | Environment file created | {vault}\System\PaperForge\.env exists and contains line PADDLEOCR_API_TOKEN=<non-empty> |
Exit code != 0; stderr: "Failed to create .env" |
| W1-S4 | Setup creates directory structure | Directory tree generated | Directories exist: System/PaperForge/exports/, System/PaperForge/ocr/, System/PaperForge/indexes/, Resources/Literature/, Bases/, .opencode/skills/ |
Exit code != 0; stderr: "Failed to create directory: {path}" |
| W1-S5 | User runs paperforge sync |
First sync from BBT JSON | paperforge sync exits code 0; stdout contains "Created" or "Found" to indicate new items |
Exit code != 0; stderr: "Error reading exports directory" |
| W1-S6 | Verify formal note created | First paper appears | {vault}/Resources/Literature/{domain}/{key} - {title}.md exists with frontmatter containing zotero_key, domain, has_pdf, pdf_path |
No note created; stderr: "Failed to create formal note for {key}" |
Workflow 2: Daily Sync
| Step ID | Trigger | Action | Measurable Outcome | Error Contract |
|---|---|---|---|---|
| W2-S1 | User adds paper in Zotero | Zotero entry created | Better BibTeX auto-exports updated JSON to {vault}/System/PaperForge/exports/{collection}.json with new item entry |
N/A — outside PaperForge scope |
| W2-S2 | Better BibTeX auto-exports | JSON appears in exports/ | File {vault}/System/PaperForge/exports/{collection}.json is valid JSON with items array containing the new paper's object |
N/A — Zotero/BBT handles export |
| W2-S3 | User runs paperforge sync |
Sync processes new export | Exit code 0; stdout contains the new paper's title or key; log shows "Formal note created" or "1 new items" | Exit code != 0; stderr: "Sync failed" |
| W2-S4 | Verify new formal note | Formal note exists with correct state | New .md file found at {vault}/Resources/Literature/{domain}/{key} - {title}.md; frontmatter has has_pdf: true, do_ocr: false, ocr_status: "pending", analyze: false |
File not created; stderr shows error about missing key or title |
Workflow 3: OCR Pipeline
| Step ID | Trigger | Action | Measurable Outcome | Error Contract |
|---|---|---|---|---|
| W3-S1 | User sets do_ocr: true in formal note frontmatter |
OCR trigger flag | Formal note frontmatter contains do_ocr: true, ocr_status: "pending" |
N/A — manual file edit |
| W3-S2 | User runs paperforge ocr |
OCR job submitted | Exit code 0; stdout contains "Submitting" or "Processing" or job reference; meta.json created at {vault}/System/PaperForge/ocr/{key}/meta.json with ocr_status: "processing" |
Exit code != 0; stderr: "OCR API authentication failed" or "Network error" |
| W3-S3 | Wait for OCR job to complete | Polling OCR status | meta.json shows ocr_status: "done"; fulltext.md exists in OCR output directory with text content |
ocr_status: "failed"; stderr: "OCR job {id} did not complete" |
| W3-S4 | OCR artifacts extracted | Full text and figures available | {vault}/System/PaperForge/ocr/{key}/fulltext.md exists with >= 1 page; {vault}/System/PaperForge/ocr/{key}/images/ exists with at least 1 image or empty |
Missing artifacts; ocr_status: "failed" with error detail |
| W3-S5 | Formal note updated with OCR status | Frontmatter reflects OCR done | Formal note frontmatter ocr_status updated to "done"; fulltext_md_path references OCR fulltext file |
ocr_status remains "pending" or "processing"; no error logged |
Workflow 4: Dashboard View (Obsidian Plugin)
| Step ID | Trigger | Action | Measurable Outcome | Error Contract |
|---|---|---|---|---|
| W4-S1 | User opens Obsidian vault | Plugin loads and registers dashboard view | Plugin view registered; sidebar icon visible; clicking opens PaperForge dashboard panel | Plugin not loaded; console shows "Failed to register PaperForge view" |
| W4-S2 | User opens a .base file |
Collection mode activates | Dashboard switches to collection mode; shows: workflow funnel (Total → PDF Ready → OCR Done → Deep Read), OCR pipeline progress bar scoped to current base, issue summary (compact, only when issues exist), action buttons (Sync Library, Run OCR) |
Falls to global mode; missing stats |
| W4-S3 | User opens a formal note (.md with zotero_key) |
Paper mode activates | Dashboard switches to paper mode; shows: status strip (PDF/OCR/DeepRead pills), paper overview card (Pass 1 summary from ## 🔍 精读), workflow toggle checkboxes (do_ocr/analyze — sync to Base), next-step card, files row (Open PDF / Open Fulltext), collapsible technical details |
Falls to global mode; components empty or erroring |
| W4-S4 | User opens fulltext.md or other workspace file |
Paper mode activates via workspace detection | Dashboard stays in paper mode for any file inside a paper workspace directory ({key} - {title}/). zotero_key resolved from dirname pattern |
Falls to global mode |
| W4-S5 | User opens no file or non-workspace .md |
Global mode activates | Dashboard shows: library snapshot (papers / PDFs / OCR done / deep-read done), system status grid (runtime / index / Zotero export / OCR token), issues panel (only when anomalies exist with Run Doctor / Repair Issues), action buttons (Open Literature Hub / Sync Library) | Shows loading/empty state; console errors |
| W4-S6 | User toggles do_ocr or analyze checkbox |
Workflow toggle writes to frontmatter | Checkbox state writes to formal note YAML frontmatter via processFrontMatter; Base view reflects change immediately (reads from file); dashboard auto-refreshes via modify event |
Frontmatter not written; notice shows "Note file not found" |
Assertion Library
Use these shell commands in journey tests to verify each step:
# W1-S1: Config file exists
test -f "{vault}/paperforge.json" && python -c "import json; json.load(open('{vault}/paperforge.json'))"
# W1-S3: .env exists with token
grep -q "PADDLEOCR_API_TOKEN" "{vault}/System/PaperForge/.env"
# W1-S4: Directory structure complete
test -d "{vault}/System/PaperForge/exports" && test -d "{vault}/Resources/Literature"
# W1-S6: Formal note created
test -f "{vault}/Resources/Literature/"{domain}/*.md
# W2-S4: Frontmatter fields present
python -c "
import yaml; m=open('{note_path}').read()
fm=yaml.safe_load(m.split('---')[1])
assert fm.get('has_pdf')==True
assert fm.get('ocr_status') in ('pending','done')
"
# W3-S5: OCR status updated in note frontmatter
python -c "
import yaml; m=open('{note_path}').read()
fm=yaml.safe_load(m.split('---')[1])
assert fm.get('ocr_status')=='done'
assert fm.get('fulltext_md_path','')!=''
"