## Step 5: `app.py` + UI Pages (NiceGUI + FastAPI composition)

## Objective

Implement the MVP user-facing application layer so users can:

1. Upload a document from the UI
2. Trigger Step 4 upload/job creation flow
3. See live job lifecycle status (`queued`, `processing`, `transcribed`, `failed`)
4. Open a job detail view to read transcript text or failure details

This step composes Steps 1–4 into a usable UI.

---

## Architecture Summary (NiceGUI-aligned)

Step 5 uses a **FastAPI app factory + lifespan orchestration** and mounts/registers NiceGUI pages via explicit page modules.

Reference baseline: `resource://skills/nicegui/document`

### Core architecture decisions

- **App factory:** `create_app()`
- **Lifespan-managed resources:** worker start/stop managed in startup/shutdown
- **Modular pages:** upload and jobs pages in separate modules (no monolithic UI file)
- **Health endpoint:** FastAPI-side `/healthz`
- **UI composition:** route pages stay modular and reusable shared shell/components live under `ui/components` as needed
- **Styling architecture:** shared CSS loaded once at startup; avoid ad-hoc per-page styling drift
- **Dependency direction (one-way):**
  - `app` -> `config/logging/db/worker/ui/api`
  - `ui/pages` -> `ui/components` + `services`
  - `services` -> `db/models/providers`
  - no reverse imports from services into UI/API

### DB and AI stance (explicit)

- **DB:** already enabled (SQLModel + SQLite), session lifecycle remains request/service-scoped as built in prior steps.
- **AI workflow:** already in place via Step 3 transcription service + Step 4 worker; UI does not call provider SDK directly.
- **Mounted docs:** not in Step 5 scope; docs mounting remains disabled for MVP.

### Async and responsiveness stance

- Prefer `async def` for page handlers and service boundaries when I/O is involved.
- Keep UI handlers non-blocking (no blocking sleeps or synchronous long I/O calls).
- For long-running user actions, always provide explicit loading/progress/error states.
- Keep cancellation/timeout behavior explicit for refresh/poll operations where applicable.

---

## Scope

### In scope
- `src/transcription/app.py`
- `src/transcription/ui/upload_page.py`
- `src/transcription/ui/jobs_page.py`
- `src/transcription/ui/__init__.py`
- `src/transcription/api/health.py` (or equivalent FastAPI health route module)
- UI/app tests with MCP scaffold->fill flow

### Out of scope
- Auth
- advanced filtering/search UX
- batch upload UX beyond MVP
- deployment/container hardening

---

## Planned Deliverables

### Source files
- `src/transcription/app.py` (app factory + lifespan wiring)
- `src/transcription/api/health.py` (GET `/healthz`)
- `src/transcription/ui/upload_page.py` (upload flow)
- `src/transcription/ui/jobs_page.py` (status list + detail)
- `src/transcription/ui/__init__.py` (explicit `register_pages(...)` export)
- `src/transcription/ui/components/*` (shared shell/navigation/status components if introduced)
- `src/transcription/ui/static/*.css` (optional shared CSS loaded once at startup)

### Test files
- `tests/test_app.py`
- `tests/api/test_health.py`
- `tests/ui/test_pages_registration.py`
- `tests/ui/test_upload_page.py`
- `tests/ui/test_jobs_page.py`

---

## Implementation Plan + Checklist

Plan baseline and guardrails source: `resource://skills/nicegui/document`

## Phase A — App factory and lifespan orchestration

- [ ] Create `create_app()` in `src/transcription/app.py`
- [ ] Add FastAPI lifespan startup/shutdown handlers
- [ ] Startup responsibilities:
  - [ ] `setup_logging()`
  - [ ] `create_all()`
  - [ ] ensure directories exist (`upload_dir`, `prompt_dir`)
  - [ ] create worker stop event
  - [ ] start worker background thread/task
- [ ] Shutdown responsibilities:
  - [ ] signal stop event
  - [ ] join/cleanup worker thread/task cleanly
- [ ] Register API router(s), including health route
- [ ] Register NiceGUI pages via explicit page registration function
- [ ] Load shared CSS once at startup (if present)

## Phase B — FastAPI health endpoint

- [ ] Create `src/transcription/api/health.py`
- [ ] Add `GET /healthz` returning simple healthy payload
- [ ] Wire route into app factory

## Phase C — Upload page (`ui/upload_page.py`)

- [ ] Add upload route/page registration function
- [ ] Render file input accepting supported extensions
- [ ] On submit:
  - [ ] show loading/progress state
  - [ ] call `create_upload_job(filename, file_bytes, ...)`
  - [ ] show success state with job reference/link
- [ ] On error:
  - [ ] show user-safe error message
  - [ ] restore ready UI state
- [ ] Ensure non-blocking I/O in UI event handlers; offload CPU-heavy work to worker path
- [ ] Make timeout/cancellation behavior explicit for any long-running action

## Phase D — Jobs page (`ui/jobs_page.py`)

- [ ] Add jobs list route/page registration function
- [ ] Display jobs with status + timestamps
- [ ] Add job detail route/view
- [ ] Show transcript on success, error detail on failure
- [ ] Include explicit refresh action and loading state
- [ ] Ensure error states are surfaced to user and logged
- [ ] Keep refresh path async and bounded to avoid UI freeze

## Phase E — UI registration module

- [ ] Update `src/transcription/ui/__init__.py`
- [ ] Export `register_pages(...)`
- [ ] Ensure each page module exports `register_page(...)`
- [ ] Keep page registration explicit and modular

## Phase F — Shared components and style consistency

- [ ] Add `ui/components` module only for reusable shell elements (header/nav/status chips), not page-local logic
- [ ] Keep structural layout in Python; keep visual polish in shared CSS
- [ ] Avoid one-off styling duplication across upload/jobs pages

---

## MCP Testing Workflow (Required)

Use these resources directly:

- `resource://catalog/prompts/pytest-scaffold`
- `resource://prompts/pytest-scaffold/document`
- `resource://catalog/prompts/pytest-fill-scaffold`
- `resource://prompts/pytest-fill-scaffold/document`

## E1 — Scaffold tests first (structure only)

Target modules:
- `src/transcription/app.py`
- `src/transcription/api/health.py`
- `src/transcription/ui/upload_page.py`
- `src/transcription/ui/jobs_page.py`

Scaffold test files:
- `tests/test_app.py`
- `tests/api/test_health.py`
- `tests/ui/test_pages_registration.py`
- `tests/ui/test_upload_page.py`
- `tests/ui/test_jobs_page.py`

Scaffold constraints:
- [ ] class/method skeletons only
- [ ] one-line docstrings
- [ ] concise behavior-focused names
- [ ] no implementation assertions yet

Validation:
- [ ] `uv run pytest --collect-only -q`

## E2 — Fill scaffold tests

Fill constraints from MCP guidance:
- [ ] preserve scaffold class/method names and docstrings (locked baseline)
- [ ] one behavior target per method
- [ ] deterministic tests preferred
- [ ] minimal mocking; only nondeterministic boundaries

Stack:
- [ ] `fastapi` (or `mixed` if needed for UI+DB fixture combination)

Suggested coverage:

### `tests/api/test_health.py`
- [ ] `/healthz` returns success status and expected payload shape

### `tests/ui/test_pages_registration.py`
- [ ] page registration wiring succeeds
- [ ] expected routes are present

### `tests/test_app.py`
- [ ] startup path initializes runtime dependencies
- [ ] worker start is invoked on startup
- [ ] worker shutdown signal/cleanup is invoked on shutdown

### `tests/ui/test_upload_page.py`
- [ ] upload action calls upload service
- [ ] success feedback displayed
- [ ] error feedback displayed for `UploadError`
- [ ] loading/progress state behavior covered
- [ ] timeout/cancellation behavior covered (if implemented)

### `tests/ui/test_jobs_page.py`
- [ ] list renders job statuses
- [ ] detail shows transcript text for successful job
- [ ] detail shows error detail for failed job
- [ ] refresh/loading state behavior covered

Marker strategy:
- [ ] `unit` for pure helpers/state formatting
- [ ] `integration` for app/page/service+DB contracts
- [ ] `external` not required for default Step 5 lane

Async behavior assertions:
- [ ] long-running actions keep button/inputs in expected disabled state
- [ ] completion/failure returns controls to ready state

---

## Validation Sequence (strict)

- [ ] `uv run pytest --collect-only -q`
- [ ] `uv run pytest -m unit -q` *(if unit tests touched)*
- [ ] `uv run pytest tests/api/test_health.py -q`
- [ ] `uv run pytest tests/ui/test_pages_registration.py -q`
- [ ] `uv run pytest tests/test_app.py -q`
- [ ] `uv run pytest tests/ui/test_upload_page.py -q`
- [ ] `uv run pytest tests/ui/test_jobs_page.py -q`
- [ ] `uv run pytest -q`

---

## Guardrails (NiceGUI + MVP)

- [ ] Do not collapse pages into one file.
- [ ] Do not use implicit global side effects for runtime wiring.
- [ ] Keep UI responsive with explicit loading/progress/error states.
- [ ] Do not block UI handlers with synchronous long I/O.
- [ ] Do not place provider SDK calls in UI handlers.
- [ ] Keep dependency direction one-way and maintainable.
- [ ] Keep shared UI in `ui/components`; keep service logic out of page modules.

---

## Definition of Done

- [ ] App factory + lifespan are in place
- [ ] Health endpoint exists and is tested
- [ ] Upload page creates queued jobs through service boundary
- [ ] Jobs list/detail pages render status/transcript/failure data
- [ ] Worker lifecycle is started/stopped by app lifespan
- [ ] Async UI states (loading/success/error) are deterministic and tested
- [ ] Scaffold->fill testing flow completed and validated
- [ ] Full suite passes: `uv run pytest -q`

## Completion Checks (NiceGUI skill aligned)

- [ ] Uses app factory and FastAPI lifespan
- [ ] Pages are modularized (not single-file UI)
- [ ] Health endpoint exists on FastAPI side
- [ ] Dependency direction is clean and one-way
- [ ] Async-first guidance is applied where I/O exists, with explicit non-blocking UX states
- [ ] DB/AI/docs decisions are explicit and reflected in structure
- [ ] Plan references baseline URI: `resource://skills/nicegui/document`

---

## PR Checklist (Integrated)

### Implementation
- [ ] `app.py` app factory + lifespan implemented
- [ ] FastAPI health route (`/healthz`) implemented
- [ ] `ui/upload_page.py` implemented
- [ ] `ui/jobs_page.py` implemented
- [ ] `ui/__init__.py` explicit page registration implemented
- [ ] Worker startup/shutdown managed by lifespan

### Testing (MCP-compliant)
- [ ] Scaffold phase completed first for all Step 5 tests
- [ ] `--collect-only` passed on scaffolds
- [ ] Fill phase completed without renaming/re-nesting scaffolded tests
- [ ] Marker decisions documented (`unit` vs `integration`)
- [ ] Targeted tests passed
- [ ] Full suite passed

### Evidence
- [ ] Validation command outputs captured
- [ ] Files created/updated listed
- [ ] MCP prompt resources referenced in implementation notes
- [ ] Any residual risks/questions documented

---

