UI slog grinds on

This commit is contained in:
Jim Lancaster
2026-08-02 23:44:53 -05:00
parent c098013a68
commit 47aef0e26e
13 changed files with 192 additions and 162 deletions
@@ -37,11 +37,13 @@ This checklist does not cover:
### RD-4 Sources section empty state
1. The page shows a Sources action for the current Document
2. The action routes to a document-scoped Sources view
2. The page shows a primary + Add Source action that opens job-create flow for this Document
3. The action routes to a document-scoped Sources view
### RD-5 Jobs section empty state
1. The page shows a Jobs action for the current Document
2. The action routes to a document-scoped Jobs view
2. The page shows a primary + Add Job action for the current Document
3. The action routes to a document-scoped Jobs view
### RD-6 Filtered navigation readiness
1. The detail page provides links or actions that can route to document-scoped Sources and Jobs views
@@ -57,6 +59,8 @@ This checklist does not cover:
1. Given a loaded Document detail page
2. When the user chooses Edit document
3. Then editable controls are shown for allowed fields only, including the author relationship selector
4. The author selector includes No author, existing Person options, and a Create new item option
5. Selecting Create new item routes to Person create
### UP-2 Editable fields
1. Editable: name, document_type, document_date, document_date_raw, location_created, notes, archive_identifier
+9 -10
View File
@@ -105,7 +105,7 @@ On the Document detail page, the user should be able to see:
2. linked people
3. a Sources section with empty-state behavior when no sources exist
4. a Jobs section with empty-state behavior when no jobs exist
5. future links to filtered Jobs and Sources views for the current document
5. filtered Jobs and Sources views for the current document
### 5.2 Current Implementation
@@ -156,13 +156,13 @@ Intended system-managed fields:
| Field | Updatable via UI | Updatable via Service | Notes |
|---|---|---|---|
| id | No | Practically no | Primary key should be treated as immutable |
| name | No | Yes | `DocumentService.update_document()` |
| document_type | No | Yes | `DocumentService.update_document()` |
| document_date | No | Yes | `DocumentService.update_document()` |
| document_date_raw | No | Yes | `DocumentService.update_document()` |
| location_created | No | Yes | `DocumentService.update_document()` |
| notes | No | Yes | `DocumentService.update_document()` |
| archive_identifier | No | Yes | `DocumentService.update_document()` |
| name | Yes | Yes | Editable from dedicated document edit page via `DocumentService.update_document()` |
| document_type | Yes | Yes | Editable from dedicated document edit page via `DocumentService.update_document()` |
| document_date | Yes | Yes | Editable from dedicated document edit page via `DocumentService.update_document()` |
| document_date_raw | Yes | Yes | Editable from dedicated document edit page via `DocumentService.update_document()` |
| location_created | Yes | Yes | Editable from dedicated document edit page via `DocumentService.update_document()` |
| notes | Yes | Yes | Editable from dedicated document edit page via `DocumentService.update_document()` |
| archive_identifier | Yes | Yes | Editable from dedicated document edit page via `DocumentService.update_document()` |
| created_at | No | Technically yes | Should remain system-managed |
| updated_at | No | Technically yes | Should remain system-managed |
@@ -213,11 +213,10 @@ Schema and models:
- `src/transcription/db/models.py`
Current implementation:
- `src/transcription/ui/pages/documents_page.py`
- `src/transcription/services/documents.py`
- `src/transcription/services/store.py`
- `src/transcription/ui/pages/upload_page.py`
- `src/transcription/ui/pages/jobs_page.py`
- `src/transcription/ui/components/table/jobs.py`
- `src/transcription/ui/components/transcript.py`
Companion UX spec:
+11 -14
View File
@@ -49,10 +49,7 @@ It should show:
3. a linked-author summary when available
4. document-scoped navigation links for Sources and Jobs
5. filtered views for sources and jobs linked to the current document
It should later support links to filtered views for:
1. jobs associated with the current document only
2. sources associated with the current document only
6. primary actions + Add Source and + Add Job
## 4. Entry Point
@@ -167,10 +164,12 @@ Minimum acceptable first implementation:
1. Dropdown of existing Person records.
2. Clear display of the selected related person before submit.
3. Ability to change or clear the selected person in the Document edit flow.
4. A Create new item option in the author selector that routes to Person create.
5. A visible Create new person link near the selector.
If the person does not exist:
1. The user should create the Person first from the Person page.
2. The Document create flow only links existing Person records in first release.
1. The user can use Create new item from the author selector and continue from Person create.
2. The Document create flow links existing Person records after selection.
## 7. Validation Rules
@@ -205,18 +204,16 @@ If a related person is selected or created:
When the user submits the form, the system should perform these logical steps:
1. validate form inputs
2. create the Document record
3. create a Person record only if the user chose to add a new related person
4. create one DocumentPerson record only if a related person was selected or created
5. persist all intended records successfully before reporting success to the user
3. create one DocumentPerson record only if an existing related person was selected
4. persist intended records successfully before reporting success to the user
Expected write sequence:
1. insert Document
2. insert Person only if needed
3. insert DocumentPerson link only if a person is linked
2. insert DocumentPerson link only if a person is linked
Recommended transactional behavior:
1. all related writes should succeed or fail together
2. the user should not end up with a partial create state where the Document exists but an intended person link does not
1. Document and optional DocumentPerson writes should succeed or fail together
2. Person creation is a separate workflow reached from the author selector and is not part of the same transaction
## 9. Expected Result After Success
@@ -281,7 +278,7 @@ The Document detail page should include:
The Document detail page should support:
1. empty-state messaging when no related records exist
2. clear next actions from each empty state
3. future links to filtered Sources and Jobs views scoped to the current document
3. filtered Sources and Jobs views scoped to the current document
### 11.4 Read Empty States
+20 -10
View File
@@ -81,7 +81,7 @@ This checklist does not cover:
### RD-4 Detail execution context visibility
1. provider, model, and prompt_name are displayed when known
2. status lifecycle value is visible
3. source-level transcription and revision context remains deferred in the current UI
3. source-level transcription and revision context is available through Source detail navigation from Job detail
### RD-5 Missing and invalid id states
1. Given an invalid job id format
@@ -94,16 +94,17 @@ This checklist does not cover:
### UP-1 Revision edit entry
1. Given a job detail page
2. When the user opens the page
3. Then document-scoped navigation links are available
3. Then navigation links to job-scoped Sources are available
4. Then source rows can open Source detail revision workflow
### UP-2 Revision validation
1. source revision editing remains deferred in the current UI
1. revision save blocks empty trimmed text and shows warning feedback
### UP-3 Successful revision save
1. deferred until the source revision UI is restored
1. Source detail save persists revised text and shows success feedback
### UP-4 Revision save failure
1. deferred until the source revision UI is restored
1. Source detail save failure shows clear error feedback with retry path
### UP-5 Job lifecycle state update visibility
1. status changes from queued to processing to terminal states are reflected in UI
@@ -113,19 +114,28 @@ This checklist does not cover:
## Delete Acceptance Criteria
### DL-1 Delete entry and confirmation
1. job deletion is deferred in the current UI
1. Given a job detail context
2. When the user opens job delete page
3. Then a permanent-action confirmation is shown for non-processing jobs
### DL-2 Dependency guardrails
1. deferred until a job delete flow is reintroduced
1. Delete is blocked while job status is processing
2. Related JobSource links are removed as part of allowed delete flow
### DL-3 Blocked delete behavior
1. deferred until a job delete flow is reintroduced
1. When blocked, the UI shows clear processing-state guidance
2. The user is offered navigation back to job or jobs list
### DL-4 Successful delete
1. deferred until a job delete flow is reintroduced
1. Given an allowed delete
2. When the user confirms delete
3. Then the job is removed and success feedback is shown
4. Then the user is returned to Jobs list
### DL-5 Delete failure
1. deferred until a job delete flow is reintroduced
1. Given backend failure during delete
2. Then clear error feedback is shown
3. Then the user remains in delete context with retry path
## Cross-Criteria Quality Gates
+19 -18
View File
@@ -36,7 +36,7 @@ This document uses three lenses:
| prompt_name | str | Yes | None | Visible when known; editable if create-time options are available | Prompt metadata |
Related execution fields rendered in Job detail via relationships:
- none in the current simplified detail view beyond job metadata and document navigation links
- Job detail renders metadata and document links; source-level review/editing is reached through job-scoped Sources routes.
## 4. CREATE Mapping
@@ -72,7 +72,7 @@ Current backend path: job create submit -> create_job_for_document()
| Field | Current Value at Create | Source | Visible to User | Evidence |
|---|---|---|---|---|
| id | Generated UUID | System | Yes on jobs list/detail | src/transcription/ui/pages/jobs_page.py |
| document_id | Newly created Document id | Service | Indirectly | src/transcription/services/store.py |
| document_id | Selected existing Document id | User selection + service write | Indirectly | src/transcription/ui/pages/jobs_page.py, src/transcription/services/store.py |
| status | queued | Service/model default | Yes | src/transcription/services/store.py, src/transcription/db/models.py |
| retry_count | 0 | Model default | Yes | src/transcription/db/models.py, src/transcription/ui/pages/jobs_page.py |
| date_created | current UTC timestamp | System | Yes | src/transcription/db/models.py, src/transcription/ui/pages/jobs_page.py |
@@ -118,27 +118,27 @@ Current read behavior exists in jobs list and jobs detail routes.
| date_created | Jobs list table | Yes | Included in row model | src/transcription/ui/components/table/jobs.py |
| date_updated | Jobs list table | Yes | Included in row model | src/transcription/ui/components/table/jobs.py |
| document_id | Not rendered directly as labeled field | Partial | Document context exists by relationship but limited direct display | src/transcription/ui/pages/jobs_page.py |
| provider/model/prompt_name | Not rendered as first-class labels | Partial | Stored in job records after processing updates | src/transcription/services/workflows.py |
| provider/model/prompt_name | Rendered as labeled fields in Job detail | Yes | Shows pending fallback when unset | src/transcription/ui/pages/jobs_page.py |
Source-related read behavior:
1. one primary source preview is shown in detail.
2. original transcription and revision editor are rendered for source context.
1. Job detail exposes Sources navigation for current job context.
2. Source preview, transcription context, and revision editor are rendered in Source detail.
3. invalid or missing job ids show explicit UI states.
### 5.3 Gap to Target
To satisfy intended Read flow, implementation must add:
1. richer per-source detail navigation if a later revision restores transcription review in Job detail.
1. optional in-page source summaries in Job detail if future UX requires fewer navigation steps.
2. richer filtering/search UX if needed.
## 6. UPDATE Mapping
### 6.1 Intended Update Behavior
Primary user updates in first release are source revision edits in job detail source context in the product plan, but the current UI no longer exposes that surface.
Primary user updates in first release are source revision edits in Source detail reached from Job detail.
Intended editable scope (first release):
- Source.revised_text through Job detail review
- Source.revised_text through Source detail review
Intended read-only Job fields in first release:
- id
@@ -156,7 +156,7 @@ Job metadata visibility policy:
| Field/Area | Updatable via UI | Updatable via Service | Notes |
|---|---|---|---|
| Source.revised_text from job detail | No | Yes | Saved via transcription service revision path, but the current UI does not expose the editor |
| Source.revised_text from Source detail | Yes | Yes | Saved via transcription service revision path from Sources page detail route |
| status | No | Yes | Updated by workflow lifecycle services |
| retry_count | No | Yes | Incremented by workflow retry logic |
| provider/model/prompt_name | No | Yes | Set during transcription result finalization |
@@ -167,13 +167,14 @@ Job metadata visibility policy:
Implementation now includes:
1. create-mode handling for provider/model/prompt visibility and optional selection.
2. detail display for provider/model/prompt and document-scoped navigation links.
3. manual controls for retry and state transitions remain deferred.
3. source revision workflow through job-scoped Sources and Source detail pages.
4. manual controls for retry and state transitions remain deferred.
## 7. DELETE Mapping
### 7.1 Intended Delete Behavior
Job deletion is deferred in the current UI.
Job deletion is implemented as a dedicated delete route with processing-state guardrails.
Rules:
1. deletion is allowed only when policy allows cleanup or retention handling for related JobSource records.
@@ -184,14 +185,13 @@ Rules:
| Action | UI Exposed | Backend Capability | Notes |
|---|---|---|---|
| Delete Job | No | Yes | JobService.delete_job() exists; no dedicated UI delete flow |
| Delete Job | Yes | Yes | Job delete page confirms permanent action and blocks when processing |
### 7.3 Gap to Target
Implementation should add in a future revision:
1. delete control in Job detail.
2. dependency checks and blocked-delete messaging.
3. success navigation and confirmation UX.
Implementation may add in a future revision:
1. inline delete entry in Job detail header.
2. richer dependency messaging beyond processing-state guardrail.
## 8. Hidden and System-Managed Fields
@@ -211,10 +211,11 @@ Schema and models:
Current implementation:
- src/transcription/ui/pages/jobs_page.py
- src/transcription/ui/components/table/jobs.py
- src/transcription/ui/components/transcript.py
- src/transcription/ui/pages/sources_page.py
- src/transcription/services/jobs.py
- src/transcription/services/workflows.py
- src/transcription/services/store.py
- src/transcription/services/transcription.py
Companion UX spec:
- docs/ui/entities/job/user-journey.md
@@ -226,7 +227,7 @@ Acceptance checklist:
- Every Job schema field appears in the field inventory.
- Intended Create behavior matches the companion user journey.
- Current behavior reflects existing upload-first creation and jobs read surfaces.
- Current behavior reflects explicit jobs creation plus source review/editing through dedicated Sources routes.
- Provider/model/prompt visibility intent is explicit for create and detail views.
- Gaps between intended and current behavior are explicit.
- Read, Update, and Delete sections distinguish target behavior from current code.
+14 -10
View File
@@ -65,9 +65,9 @@ Primary entry points:
2. from Jobs page row selection, open existing Job detail
Current implementation note:
1. current code path is upload-first and auto-creates Job records
1. current code path uses explicit /jobs/new creation
2. intended UX is explicit Create job from the Jobs page
3. current detail view is link-oriented and does not show per-source transcription or revision editing controls
3. current detail view is link-oriented and routes source review/editing through dedicated Source detail
## 5. Create Job Flow
@@ -167,9 +167,13 @@ Optional first-release columns if available:
The Job detail should show:
1. job status and summary metadata
2. selected Document context
3. per-source status (pending, transcribed, failed)
4. original transcription output per source
5. revision editor and latest revised content
3. document-scoped and job-scoped navigation links
4. source review entry through job-scoped Sources list
Source detail should show:
1. source metadata and preview
2. original transcription output per source
3. revision editor and latest revised content
### 6.4 Read Empty and Missing States
@@ -228,7 +232,7 @@ The user primarily updates job-related review outcomes by editing revised transc
### 8.2 First-Release Editable Scope
Editable in first release:
1. source-level revised_text through job detail review
1. source-level revised_text through Source detail reached from job-scoped Sources navigation
Read-only in first release:
1. Job.document_id after create
@@ -256,10 +260,10 @@ The user may need to remove invalid or duplicate jobs safely.
### 9.2 First-Release Policy
Delete behavior is policy-controlled:
1. deletion may be blocked when related JobSource or source history must be retained
2. blocked delete must explain constraints and cleanup path
3. if allowed, delete requires explicit confirmation
Delete behavior uses explicit guardrails:
1. deletion is blocked while status is processing
2. blocked delete explains constraints and offers back navigation
3. allowed delete requires explicit confirmation and then returns to Jobs list with success feedback
## 10. Relationship to Other Workflows
@@ -35,6 +35,7 @@ This checklist does not cover:
1. Optional fields may be blank without blocking create
2. Date raw and exact fields can coexist
3. Exact date remains canonical when both exact and raw are provided
4. Portrait uploads persist under uploads/portraits/person and store a relative portrait_path
### CR-4 Successful create outcome
1. Given valid input
@@ -60,6 +61,7 @@ This checklist does not cover:
1. The page shows full_name and available optional person fields
2. created_at and updated_at are shown as system-managed, read-only values
3. portrait_path is rendered when available, including an image preview when possible
4. relative portrait_path values resolve through /uploads for image rendering
### RD-3 Linked documents section
1. Given no linked DocumentPerson rows
+43 -42
View File
@@ -72,31 +72,31 @@ Related records during intended create:
### 4.2 Current Implementation
Current entry point: no dedicated Person UI page yet
Current user action: none in UI
Current backend path: service calls via DocumentService.create_person()
Current entry point: dedicated People page and Person create/edit flows
Current user action: open Person create page, fill form fields, optionally upload portrait
Current backend path: People page submit callbacks -> DocumentService.create_person() / update_person()
| Field | Current Value at Create | Source | Visible to User | Evidence |
|---|---|---|---|---|
| id | Generated UUID | System | No | Person model default factory in src/transcription/db/models.py |
| full_name | Caller-provided | Service/API caller | No | create_person() in src/transcription/services/documents.py |
| display_name | Caller-provided or None | Service/API caller | No | create_person() in src/transcription/services/documents.py |
| maiden_name | Caller-provided or None | Service/API caller | No | create_person() in src/transcription/services/documents.py |
| birth_date | Caller-provided or None | Service/API caller | No | create_person() in src/transcription/services/documents.py |
| birth_date_raw | Caller-provided or None | Service/API caller | No | create_person() in src/transcription/services/documents.py |
| birth_place | Caller-provided or None | Service/API caller | No | create_person() in src/transcription/services/documents.py |
| death_date | Caller-provided or None | Service/API caller | No | create_person() in src/transcription/services/documents.py |
| death_date_raw | Caller-provided or None | Service/API caller | No | create_person() in src/transcription/services/documents.py |
| death_place | Caller-provided or None | Service/API caller | No | create_person() in src/transcription/services/documents.py |
| biography | Caller-provided or None | Service/API caller | No | create_person() in src/transcription/services/documents.py |
| portrait_path | Caller-provided or None | Service/API caller | No | create_person() in src/transcription/services/documents.py |
| full_name | Form input | User input | Yes | src/transcription/ui/pages/people_page.py |
| display_name | Form input or None | User input | Yes | src/transcription/ui/pages/people_page.py |
| maiden_name | Form input or None | User input | Yes | src/transcription/ui/pages/people_page.py |
| birth_date | Form input or None | User input | Yes | src/transcription/ui/pages/people_page.py |
| birth_date_raw | Form input or None | User input | Yes | src/transcription/ui/pages/people_page.py |
| birth_place | Form input or None | User input | Yes | src/transcription/ui/pages/people_page.py |
| death_date | Form input or None | User input | Yes | src/transcription/ui/pages/people_page.py |
| death_date_raw | Form input or None | User input | Yes | src/transcription/ui/pages/people_page.py |
| death_place | Form input or None | User input | Yes | src/transcription/ui/pages/people_page.py |
| biography | Form input or None | User input | Yes | src/transcription/ui/pages/people_page.py |
| portrait_path | Relative upload path or manual path | Upload helper + user input | Yes | src/transcription/ui/pages/people_page.py, src/transcription/services/store.py |
| metadata_ | Caller-provided or None | Service/API caller | No | Person model in src/transcription/db/models.py |
| created_at | Current UTC timestamp | System | No | Person model default in src/transcription/db/models.py |
| updated_at | Current UTC timestamp | System | No | Person model default in src/transcription/db/models.py |
### 4.3 Gap to Target
To satisfy the intended Create flow, implementation must add:
To satisfy the intended Create flow, implementation now includes:
1. a Person page and dedicated create form
2. user-entered controls for Person fields
3. create validation and success/failure UX states
@@ -113,24 +113,24 @@ On the Person detail page, the user should be able to see:
### 5.2 Current Implementation
Current Person visibility in the UI is not implemented as a dedicated page.
Current Person visibility is implemented in dedicated list/detail/edit/delete pages.
| Field | Current Rendering | Visible to User | Notes | Evidence |
|---|---|---|---|---|
| full_name | Rendered in header and summary | Yes | Dedicated Person page exists | `src/transcription/ui/pages/people_page.py` |
| display_name | Not rendered | No | No current Person page | no Person page in src/transcription/ui |
| maiden_name | Not rendered | No | No current Person page | no Person page in src/transcription/ui |
| birth_date | Not rendered | No | No current Person page | no Person page in src/transcription/ui |
| birth_date_raw | Not rendered | No | No current Person page | no Person page in src/transcription/ui |
| birth_place | Not rendered | No | No current Person page | no Person page in src/transcription/ui |
| death_date | Not rendered | No | No current Person page | no Person page in src/transcription/ui |
| death_date_raw | Not rendered | No | No current Person page | no Person page in src/transcription/ui |
| death_place | Not rendered | No | No current Person page | no Person page in src/transcription/ui |
| biography | Not rendered | No | No current Person page | no Person page in src/transcription/ui |
| display_name | Rendered | Yes | Visible in detail and list contexts | src/transcription/ui/pages/people_page.py |
| maiden_name | Rendered | Yes | Visible in detail context | src/transcription/ui/pages/people_page.py |
| birth_date | Rendered | Yes | Visible in detail context | src/transcription/ui/pages/people_page.py |
| birth_date_raw | Rendered | Yes | Visible in detail context | src/transcription/ui/pages/people_page.py |
| birth_place | Rendered | Yes | Visible in detail context | src/transcription/ui/pages/people_page.py |
| death_date | Rendered | Yes | Visible in detail context | src/transcription/ui/pages/people_page.py |
| death_date_raw | Rendered | Yes | Visible in detail context | src/transcription/ui/pages/people_page.py |
| death_place | Rendered | Yes | Visible in detail context | src/transcription/ui/pages/people_page.py |
| biography | Rendered | Yes | Visible in detail context | src/transcription/ui/pages/people_page.py |
| portrait_path | Rendered as text and image when available | Yes | Dedicated Person page exists | `src/transcription/ui/pages/people_page.py` |
| metadata_ | Not rendered | No | Hidden advanced field | no current UI field |
| created_at | Not rendered | No | No current Person page | no Person page in src/transcription/ui |
| updated_at | Not rendered | No | No current Person page | no Person page in src/transcription/ui |
| created_at | Rendered read-only | Yes | Visible in detail context | src/transcription/ui/pages/people_page.py |
| updated_at | Rendered read-only | Yes | Visible in detail context | src/transcription/ui/pages/people_page.py |
### 5.3 Gap to Target
@@ -171,17 +171,17 @@ Hidden in first release:
| Field | Updatable via UI | Updatable via Service | Notes |
|---|---|---|---|
| id | No | Practically no | Primary key should be treated as immutable |
| full_name | No | Yes | DocumentService.update_person() |
| display_name | No | Yes | DocumentService.update_person() |
| maiden_name | No | Yes | DocumentService.update_person() |
| birth_date | No | Yes | DocumentService.update_person() |
| birth_date_raw | No | Yes | DocumentService.update_person() |
| birth_place | No | Yes | DocumentService.update_person() |
| death_date | No | Yes | DocumentService.update_person() |
| death_date_raw | No | Yes | DocumentService.update_person() |
| death_place | No | Yes | DocumentService.update_person() |
| biography | No | Yes | DocumentService.update_person() |
| portrait_path | No | Yes | DocumentService.update_person() |
| full_name | Yes | Yes | Editable from Person edit page via DocumentService.update_person() |
| display_name | Yes | Yes | Editable from Person edit page via DocumentService.update_person() |
| maiden_name | Yes | Yes | Editable from Person edit page via DocumentService.update_person() |
| birth_date | Yes | Yes | Editable from Person edit page via DocumentService.update_person() |
| birth_date_raw | Yes | Yes | Editable from Person edit page via DocumentService.update_person() |
| birth_place | Yes | Yes | Editable from Person edit page via DocumentService.update_person() |
| death_date | Yes | Yes | Editable from Person edit page via DocumentService.update_person() |
| death_date_raw | Yes | Yes | Editable from Person edit page via DocumentService.update_person() |
| death_place | Yes | Yes | Editable from Person edit page via DocumentService.update_person() |
| biography | Yes | Yes | Editable from Person edit page via DocumentService.update_person() |
| portrait_path | Yes | Yes | Editable manually and via portrait upload helper |
| metadata_ | No | Yes | Technically updatable, hidden in first release |
| created_at | No | Technically yes | Should remain system-managed |
| updated_at | No | Technically yes | Should remain system-managed |
@@ -208,11 +208,11 @@ Rules:
| Action | UI Exposed | Backend Capability | Notes |
|---|---|---|---|
| Delete Person | No | Yes | DocumentService.delete_person() exists, but no dedicated UI guard flow exists |
| Delete Person | Yes | Yes | Dedicated delete page enforces linked-document guardrails before service delete |
### 7.3 Gap to Target
Implementation must add:
Implementation includes:
1. a Person delete control in the UI
2. relationship-aware pre-delete checks
3. user-facing blocked-delete messaging
@@ -247,7 +247,8 @@ Schema and models:
Current implementation:
- src/transcription/services/documents.py
- src/transcription/ui (no dedicated Person pages yet)
- src/transcription/ui/pages/people_page.py
- src/transcription/services/store.py
Companion UX spec:
- docs/ui/entities/person/user-journey.md
@@ -259,6 +260,6 @@ Acceptance checklist:
- Every Person schema field appears in the field inventory.
- Intended Create behavior matches the companion user journey.
- Current Create behavior reflects service-level implementation.
- Current Create behavior reflects dedicated UI form implementation with optional portrait upload handling.
- Gaps between intended and current behavior are explicit.
- Read, Update, and Delete sections distinguish target behavior from current code.
+2
View File
@@ -136,6 +136,7 @@ On submit:
2. The system creates the Person record
3. The system returns the user to the Person detail page
4. The system shows a success message
5. If portrait upload is used, the file is stored under uploads/portraits/person and portrait_path is set to that relative file path
Recommended transactional behavior:
1. Person writes are atomic
@@ -173,6 +174,7 @@ The Person detail page should show:
2. birth and death fields
3. biography summary
4. related documents list or empty state
5. portrait preview resolved from /uploads when portrait_path is a relative path
### 10.3 Read Empty State
+14 -14
View File
@@ -59,14 +59,14 @@ This checklist does not cover:
## Read Acceptance Criteria
### RD-1 Source detail retrieval
1. Given a valid Source id in source context, typically via a document-scoped source list in first release
2. When the user opens source detail or equivalent panel
3. Then source metadata and preview are displayed for that source only if the detail UI exists in a later revision
1. Given a valid Source id in source context
2. When the user opens source detail
3. Then source metadata and preview are displayed for that source only
### RD-2 Transcription and revision visibility
1. Original transcription context is visible read-only when the revision UI exists
2. Revision state is visible when the revision UI exists
3. If revised_text is absent, no revision yet messaging is shown when the revision UI exists
1. Original transcription context is visible read-only in Source detail
2. Revision state is visible in Source detail
3. If revised_text is absent, revision input opens as empty and can be edited
### RD-3 Missing source state
1. Given a missing source
@@ -77,29 +77,29 @@ This checklist does not cover:
### UP-1 Revision editing entry
1. Given a source context
2. When the user enters revision edit flow
3. Then revised_text input is available in a later revision of the UI
3. Then revised_text input is available in Source detail
### UP-2 Revision validation
1. revised_text cannot be saved as empty after trimming when the revision UI exists
2. Warning feedback is shown for invalid empty input when the revision UI exists
1. revised_text cannot be saved as empty after trimming
2. Warning feedback is shown for invalid empty input
### UP-3 Successful revision save
1. Given valid revision text
2. When the user saves in a later revision of the UI
2. When the user saves
3. Then revised_text persists
4. Then date_revised is updated
5. Then success feedback is shown
6. Then refreshed revision content is visible
### UP-4 Revision save failure
1. Given backend failure during save in a later revision of the UI
1. Given backend failure during save
2. Then clear error feedback is shown
3. Then the user-entered text remains available for retry where possible
## Delete Acceptance Criteria
### DL-1 Delete entry and confirmation
1. Given a source in source context, typically via a later source detail view
1. Given a source in source context
2. When the user selects delete source
3. Then a permanent-action confirmation dialog appears
@@ -135,7 +135,7 @@ This checklist does not cover:
2. No acceptance criterion contradicts first-release deferred items
### QG-3 First-release constraints
1. Source interaction may remain job-detail-centric initially
1. Source creation remains job-create-centric
2. revised_text is the primary editable source field in first release
3. source creation requires both Document linkage and Job linkage at create time
4. richer source management surfaces are phased in later
4. source delete management surfaces are phased in later
+25 -25
View File
@@ -32,7 +32,7 @@ This document uses three lenses:
| filename | str | No | None | Shown read-only | Stored filename |
| file_path | str | No | None | Usually hidden; preview uses path internally | Filesystem path |
| raw_transcription | str | Yes | None | Shown indirectly or hidden | Immutable machine output context |
| revised_text | str | Yes | None | Hidden in current simplified UI | Human-authored correction |
| revised_text | str | Yes | None | Editable in Source detail | Human-authored correction |
| date_uploaded | datetime | No | datetime.now(UTC) | Shown read-only | System-managed timestamp |
| date_revised | datetime | Yes | None | Shown read-only | Set when revision is saved |
@@ -66,8 +66,8 @@ Current backend path: job create submit -> create_job_for_document()
| Field | Current Value at Create | Source | Visible to User | Evidence |
|---|---|---|---|---|
| id | Generated UUID | System | No | Source model default in src/transcription/db/models.py |
| document_id | Created Document id | Service | Indirectly | src/transcription/services/store.py |
| page_number | 1 | Service default in upload flow | No | src/transcription/services/store.py |
| document_id | Selected existing Document id | Job create selection + service write | Indirectly | src/transcription/ui/pages/jobs_page.py, src/transcription/services/store.py |
| page_number | Sequential assignment based on existing max and alphabetical upload order | Service | No | src/transcription/services/store.py |
| upload_name | original filename basename | User file name transformed by service | Indirectly | src/transcription/services/store.py |
| filename | stored generated filename | Service | Indirectly | src/transcription/services/store.py |
| file_path | stored path | Service | Indirectly | src/transcription/services/store.py |
@@ -78,11 +78,11 @@ Current backend path: job create submit -> create_job_for_document()
### 4.3 Gap to Target
To satisfy intended Create flow, implementation must add:
To satisfy intended Create flow, implementation now includes:
1. multi-source and folder upload support in job create/configure flows
2. deterministic page_number assignment from alphabetical original filename ordering
3. enforced create-time Source-to-Document and Source-to-Job linkage invariants
4. complete filename storage policy migration to UUID.extension only
4. filename storage policy using UUID.extension
## 5. READ Mapping
@@ -96,33 +96,33 @@ On Source detail/list surfaces, users should be able to see:
### 5.2 Current Implementation
Current Source reading is primarily embedded in a document-scoped source list and job create/navigation flow.
Current Source reading is centered on dedicated Sources list/detail routes with optional document/job filtering.
| Field | Current Rendering | Visible to User | Notes | Evidence |
|---|---|---|---|---|
| upload_name | Shown in document-scoped source list | Yes | Displayed in source list context | src/transcription/ui/pages/documents_page.py |
| filename | Shown in document-scoped source list | Yes | Source metadata shown in list | src/transcription/ui/pages/documents_page.py |
| file_path | Hidden from current simplified UI | No | Operational path remains internal | current UI pages |
| page_number | Shown in document-scoped source list | Yes | Ordering visible in document source list | src/transcription/ui/pages/documents_page.py |
| raw_transcription | Not shown in current simplified UI | No | Source preview/revision UI deferred | current UI pages |
| revised_text | Not shown in current simplified UI | No | Source revision UI deferred | current UI pages |
| date_uploaded | Not shown in current simplified UI | No | Operational metadata only | current UI pages |
| date_revised | Not shown in current simplified UI | No | Operational metadata only | current UI pages |
| upload_name | Shown in Sources list and Source detail | Yes | Displayed in source context | src/transcription/ui/pages/sources_page.py |
| filename | Shown in Sources list and Source detail | Yes | Source metadata shown in list/detail | src/transcription/ui/pages/sources_page.py |
| file_path | Hidden from direct text rendering | No | Used internally for preview rendering | src/transcription/ui/components/document_panzoom.py |
| page_number | Shown in Sources list and Source detail | Yes | Ordering visible in filtered/global list | src/transcription/ui/pages/sources_page.py |
| raw_transcription | Shown read-only in Source detail | Yes | Read from latest linked JobSource context | src/transcription/ui/pages/sources_page.py |
| revised_text | Shown and editable in Source detail | Yes | Saved through revision action | src/transcription/ui/pages/sources_page.py |
| date_uploaded | Shown in Source detail | Yes | Read-only metadata | src/transcription/ui/pages/sources_page.py |
| date_revised | Shown in Source detail | Yes | Read-only metadata after revision save | src/transcription/ui/pages/sources_page.py |
### 5.3 Gap to Target
To satisfy intended Read flow, implementation must add:
1. richer source detail and revision surfaces if the review workflow returns later
2. optional page-specific navigation if needed beyond the document-scoped list
1. optional list filtering controls in-page (current filtering is URL/context based)
2. optional page-specific navigation enhancements beyond current list/detail pattern
## 6. UPDATE Mapping
### 6.1 Intended Update Behavior
Primary user update for Source is revised_text maintenance in the service layer; the current UI does not expose this flow.
Primary user update for Source is revised_text maintenance in Source detail.
Intended editable fields (first release):
- revised_text, if the revision UI is restored later
- revised_text
Intended read-only fields (first release):
- document_id
@@ -138,16 +138,15 @@ Intended read-only fields (first release):
| Field | Updatable via UI | Updatable via Service | Notes |
|---|---|---|---|
| revised_text | No | Yes | Saved via TranscriptionService.upsert_revision_for_source(), but not exposed in current UI |
| revised_text | Yes | Yes | Saved via TranscriptionService.upsert_revision_for_source() from Source detail |
| date_revised | No | Yes | Set automatically on revision save |
| other fields | No | Technically yes in service layer | No first-class UI editing flow |
### 6.3 Gap to Target
Implementation should add in a later revision:
1. explicit Source edit boundaries in dedicated Source UI
2. validation and save UX for revisions in document-scoped source views
3. optional future controls for page ordering and metadata corrections
1. optional future controls for page ordering and metadata corrections
2. revision history and conflict-resolution UX beyond single revised_text updates
## 7. DELETE Mapping
@@ -192,9 +191,10 @@ Schema and models:
Current implementation:
- src/transcription/services/store.py
- src/transcription/services/transcription.py
- src/transcription/ui/pages/sources_page.py
- src/transcription/ui/pages/jobs_page.py
- src/transcription/ui/components/transcript.py
- src/transcription/ui/components/job_detail.py
- src/transcription/ui/pages/documents_page.py
- src/transcription/ui/components/document_panzoom.py
Companion UX spec:
- docs/ui/entities/source/user-journey.md
@@ -207,6 +207,6 @@ Acceptance checklist:
- Every Source schema field appears in the field inventory.
- Intended Create behavior matches the companion user journey.
- Source create invariant requires both Document linkage and Job linkage at create time.
- Current behavior reflects upload-centric and job-detail-centric implementation.
- Current behavior reflects upload-centric create flow and dedicated Sources list/detail review flow.
- Gaps between intended and current behavior are explicit.
- Read, Update, and Delete sections distinguish target behavior from current code.
+22 -12
View File
@@ -15,7 +15,8 @@ Managing Source records is page-first:
1. The user starts from a transcription job flow.
2. The user adds one or more source files.
3. The system creates Source records linked to the Document and linked to the Job through JobSource.
4. The user reviews source lists by document and can navigate to the owning Document or Job.
4. The user reviews source lists from a dedicated Sources page.
5. The user opens Source detail to review preview, metadata, transcription text, and revision text.
## 2. User Goal
@@ -32,22 +33,29 @@ The user wants to:
### 3.1 Source List Surface
A Source list surface should support:
1. listing source pages for a selected Document
1. listing source pages globally or filtered by selected Document or Job
2. sorting by page_number
3. opening the owning Document or Job context
4. opening Source detail for a selected source
### 3.2 Source Detail Surface
Source detail and revision surfaces are deferred in the current UI.
Source detail supports:
1. pan/zoom image or PDF preview
2. read-only source metadata (page number, names, timestamps)
3. read-only original transcription text
4. editable revision text with save action
## 4. Entry Points
Primary entry points:
1. from Job workflow, Add sources while creating or configuring a job
2. from Job detail, open source preview and revision editor
2. from Job detail, open filtered Sources for the current Job
3. from Document detail, open filtered Sources for the current Document
4. from global navigation, open all Sources
Current implementation note:
1. source interaction currently occurs in job-create and document-scoped source list flows
1. source interaction occurs in job-create flow and dedicated Sources list/detail flows
## 5. Create Source Flow
@@ -120,11 +128,12 @@ The user wants to view each page file and understand file identity and processin
### 6.2 Read Surface Expectations
The UI should show:
1. source lists grouped by Document
1. source lists for current context (all, document-filtered, or job-filtered)
2. upload_name as the original user-provided filename
3. filename as the stored system filename
4. page_number and ordering context
5. the owning Document and Job navigation context
6. direct action to open Source detail
### 6.3 Read Empty and Missing States
@@ -143,7 +152,7 @@ The user primarily tracks page-level source records while preserving raw machine
### 7.2 Intended Editable Fields
Editable in first release:
1. revised_text in a later revision, not in the current simplified UI
1. revised_text in Source detail
Read-only in first release:
1. upload_name
@@ -157,11 +166,11 @@ Read-only in first release:
### 7.3 Revision Save Behavior
On save:
1. validate revision text is non-empty when the revision UI exists in a later release
2. persist revised_text when the revision UI exists
3. set date_revised when the revision UI exists
4. show success feedback when the revision UI exists
5. keep user in current source context when the revision UI exists
1. validate revision text is non-empty after trimming
2. persist revised_text
3. set date_revised
4. show success feedback
5. keep user in current source context
### 7.4 Revision Failure Behavior
@@ -217,3 +226,4 @@ Deferred to future revisions:
2. multi-file upload progress and resumable upload UX
3. revision history versions beyond a single revised_text field
4. richer per-page status dashboards
5. source delete UI with dependency-aware confirmation
+5 -5
View File
@@ -33,8 +33,8 @@ Status legend:
|---|---|---|---|---|
| Create entry and required links | CR-1, CR-2, CR-4, CR-5 | Implemented | src/transcription/services/store.py; src/transcription/ui/pages/jobs_page.py; src/transcription/ui/pages/upload_page.py; tests/services/test_store.py; tests/ui/test_jobs_page.py | Source upload/create is job-create-context only (legacy upload route redirects), with required Document and JobSource linkage enforced. |
| Ordering and filename policy | CR-3 | Implemented | src/transcription/services/store.py; tests/services/test_store.py; tests/ui/test_jobs_page.py | Multi-file/folder uploads are ordered alphabetically by original filename, helper text is visible, and stored filenames use generated unique-id plus extension. |
| Read and navigation visibility | RD-1, RD-2, RD-3 | Partial | src/transcription/ui/pages/documents_page.py; src/transcription/ui/pages/jobs_page.py; tests/ui/test_documents_page.py; tests/ui/test_jobs_page.py | Source list context is now document-scoped and job detail is link-oriented; source preview and revision surfaces are deferred. |
| Revision update behavior | UP-1, UP-2, UP-3, UP-4 | Planned | src/transcription/services/transcription.py; tests/services/test_transcription_service.py | Revised text service support remains, but the current UI does not expose the editor. |
| Read and navigation visibility | RD-1, RD-2, RD-3 | Implemented | src/transcription/ui/pages/sources_page.py; src/transcription/ui/pages/documents_page.py; src/transcription/ui/pages/jobs_page.py; tests/ui/test_sources_page.py; tests/ui/test_documents_page.py; tests/ui/test_jobs_page.py | Dedicated Sources list/detail routes support global, document-filtered, and job-filtered navigation plus source metadata and preview rendering. |
| Revision update behavior | UP-1, UP-2, UP-3, UP-4 | Implemented | src/transcription/ui/pages/sources_page.py; src/transcription/services/transcription.py; tests/ui/test_sources_page.py; tests/services/test_transcription_service.py | Source detail exposes revision edit/save UX with non-empty validation, success feedback, and refreshed state after save. |
| Delete and dependency guardrails | DL-1, DL-2, DL-3, DL-4, DL-5 | Planned | src/transcription/services/transcription.py; tests/services/test_transcription_service.py | Job-detail source delete UI was removed from the current simplified flow; backend guardrails remain for future reinstatement. |
## Job
@@ -45,9 +45,9 @@ Status legend:
| Source ordering and upload behavior | CR-3 | Implemented | src/transcription/services/store.py; src/transcription/ui/pages/jobs_page.py; tests/services/test_store.py; tests/ui/test_jobs_page.py | Multi-file and folder upload are supported through one widget, uploads are sorted alphabetically by original filename, and helper guidance is shown in create UI. |
| Provider/model/prompt visibility | CR-4, RD-4 | Implemented | src/transcription/services/workflows.py; src/transcription/ui/pages/jobs_page.py; tests/ui/test_jobs_page.py | Provider/model/prompt fields are visible in create and detail flows when known (with pending fallback labels). |
| Jobs list and detail read states | RD-1, RD-2, RD-3, RD-5 | Implemented | src/transcription/ui/pages/jobs_page.py; src/transcription/ui/components/table/jobs.py; tests/ui/test_jobs_page.py | Jobs list, detail route, document-scoped navigation, and invalid/missing id states are present. |
| Revision update behavior | UP-1, UP-2, UP-3, UP-4 | Planned | src/transcription/services/transcription.py; tests/services/test_transcription_service.py | Revision editing service support remains, but the current UI no longer exposes the editor. |
| Revision update behavior | UP-1, UP-2, UP-3, UP-4 | Implemented | src/transcription/ui/pages/jobs_page.py; src/transcription/ui/pages/sources_page.py; src/transcription/services/transcription.py; tests/ui/test_jobs_page.py; tests/ui/test_sources_page.py; tests/services/test_transcription_service.py | Job detail routes users to job-scoped Sources where Source detail provides revision edit/save workflow. |
| Lifecycle visibility and retry indicators | UP-5 | Implemented | src/transcription/services/jobs.py; src/transcription/services/workflows.py; src/transcription/ui/pages/jobs_page.py; tests/ui/test_jobs_page.py | Job detail now surfaces lifecycle status plus retry/update metadata while lifecycle fields remain system-managed (no direct user edit controls). |
| Delete and dependency guardrails | DL-1, DL-2, DL-3, DL-4, DL-5 | Planned | src/transcription/services/jobs.py; tests/services/test_job_service.py | Job delete UI is deferred in the current simplified flow. |
| Delete and dependency guardrails | DL-1, DL-2, DL-3, DL-4, DL-5 | Implemented | src/transcription/ui/pages/jobs_page.py; src/transcription/services/jobs.py; tests/ui/test_jobs_page.py; tests/services/test_job_service.py | Job delete page enforces processing-state block, confirms allowed deletes, and routes back to jobs list on success. |
## Quality Gate Coverage
@@ -74,5 +74,5 @@ Status legend:
|---|---|---|---|
| Document | None | src/transcription/ui/pages/documents_page.py; tests/ui/test_documents_page.py | Document criteria are covered by dedicated detail/edit/delete pages and document-scoped related views. |
| Person | None | src/transcription/ui/pages/people_page.py; tests/ui/test_people_page.py | Person criteria are covered by dedicated create/detail/edit/delete pages with relationship-aware delete guardrails. |
| Source | None | src/transcription/services/store.py; src/transcription/ui/pages/jobs_page.py; tests/services/test_store.py; tests/services/test_transcription_service.py | Source criteria are covered by job-context create behavior, ordering/filename policy, revision flow, and delete guardrails. |
| Source | None | src/transcription/services/store.py; src/transcription/ui/pages/sources_page.py; src/transcription/ui/pages/jobs_page.py; tests/services/test_store.py; tests/ui/test_sources_page.py; tests/services/test_transcription_service.py | Source criteria are covered by job-context create behavior, ordering/filename policy, dedicated list/detail read flow, revision flow, and delete guardrails. |
| Job | None | src/transcription/ui/pages/jobs_page.py; src/transcription/services/jobs.py; tests/ui/test_jobs_page.py; tests/services/test_job_service.py | Job criteria are covered by create/read/revision/lifecycle visibility and delete guardrails in dedicated routes. |