Skip to content

release: promote EPIC-08 Paperless-ngx Document Integration to main#385

Merged
steilerDev merged 16 commits into
mainfrom
beta
Mar 2, 2026
Merged

release: promote EPIC-08 Paperless-ngx Document Integration to main#385
steilerDev merged 16 commits into
mainfrom
beta

Conversation

@steilerDev
Copy link
Copy Markdown
Owner

Summary

EPIC-08: Paperless-ngx Document Integration — Cornerstone now integrates with Paperless-ngx for document management. Browse your entire document archive from within Cornerstone, and link invoices, contracts, permits, and receipts directly to work items and vendor invoices.

Highlights

  • Document Browser — A dedicated page to search, filter by tags, and browse all documents in your Paperless-ngx instance, with thumbnail previews, pagination, and a detail panel showing document metadata
  • Document Linking — Attach Paperless-ngx documents to work items and vendor invoices with a picker modal, view linked documents as thumbnail cards, and open them directly in Paperless-ngx
  • Secure Proxy Architecture — All Paperless-ngx communication is proxied through the Cornerstone backend, keeping your API token server-side
  • Graceful Degradation — Clear status messages when Paperless-ngx is not configured or unreachable, with retry functionality
  • Responsive & Accessible — Full keyboard navigation, ARIA roles, focus management, screen reader announcements, and responsive layout for desktop, tablet, and mobile

Configuration

PAPERLESS_URL=https://paperless.example.com
PAPERLESS_API_TOKEN=your-api-token-here

Stories Included

Additional PRs

Epic Metrics

  • 7 PRs reviewed by 4 agents
  • 0 Critical / 1 High / 17 Medium / 18 Low / 19 Informational findings (55 total)
  • 43% of PRs required fix loops (3 of 7)
  • UX designer flagged the most findings (31) — expected for a UI-heavy epic

UAT Validation

All UAT scenarios produced — see validation report on EPIC-08 issue #8.

🤖 Generated with Claude Code

steilerDev and others added 16 commits March 1, 2026 22:38
…pes, and config (#361)

Design and scaffold the EPIC-08 Paperless-ngx document integration:

Schema:
- Add document_links table (migration 0009) with polymorphic entity_type
  discriminator for linking Paperless-ngx docs to work items, household
  items, and invoices
- Add documentLinks to Drizzle ORM schema

API contract:
- Proxy endpoints: GET /api/paperless/{status,documents,documents/:id,
  documents/:id/thumb,documents/:id/preview,tags}
- Document link CRUD: POST/GET/DELETE /api/document-links
- New error codes: PAPERLESS_NOT_CONFIGURED, PAPERLESS_UNREACHABLE,
  PAPERLESS_ERROR, DUPLICATE_DOCUMENT_LINK

Shared types:
- PaperlessDocument, PaperlessTag, PaperlessSearchHit
- DocumentLink, DocumentLinkWithMetadata
- Request/response types for all new endpoints

Config:
- Add PAPERLESS_URL and PAPERLESS_API_TOKEN environment variables
- Add paperlessEnabled derived flag
- Update config test expectations

Wiki:
- ADR-015: Paperless-ngx Integration Architecture
- Updated Architecture.md, API-Contract.md, Schema.md, ADR-Index.md

Co-authored-by: Claude product-architect (Opus 4.6) <noreply@anthropic.com>
Co-authored-by: Frank Steiler <frank@steiler.dev>
* feat(paperless): implement Paperless-ngx proxy service and routes (#354)

Add the Paperless-ngx proxy backend for EPIC-08. The server now proxies
all document browsing and binary requests through /api/paperless/* endpoints,
keeping the API token server-side at all times.

Fixes #354

Co-Authored-By: Claude dev-team-lead (Sonnet 4.6) <noreply@anthropic.com>

* fix(paperless): address PR #362 security and quality review findings

- config.ts: validate PAPERLESS_URL scheme (http/https only) to prevent SSRF
  attacks via file://, ftp://, and other non-HTTP schemes
- paperless.ts: add MIME type allowlist for thumb/preview binary endpoints;
  disallowed upstream content-types fall back to application/octet-stream
- paperless.ts: add pattern constraint '^\\d+(,\\d+)*$' to tags query param
  to enforce comma-separated integer format
- paperlessService.ts: sanitize IP addresses and hostname:port from error
  messages in getStatus() to prevent information disclosure
- paperlessService.ts: remove duplicate local ListDocumentsQuery interface;
  use shared PaperlessDocumentListQuery instead
- .env.example: add PAPERLESS_URL and PAPERLESS_API_TOKEN (commented out)
- Tests updated: config.test.ts, paperless.test.ts, paperlessService.test.ts
  cover all new validation logic, sanitization, and allowlist behavior

Fixes #354

Co-Authored-By: Claude dev-team-lead (Sonnet 4.6) <noreply@anthropic.com>

* chore: update review metrics for PR #362

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude dev-team-lead (Sonnet 4.6) <noreply@anthropic.com>
* feat(paperless): implement document links CRUD API (Story #355)

Adds the document links backend for EPIC-08, enabling users to associate
Paperless-ngx documents with work items and invoices.

- documentLinkService: createLink, getLinksForEntity (with metadata enrichment),
  deleteLink, deleteLinksForEntity for cascade delete
- documentLinks route: POST/GET/DELETE /api/document-links with JSON schema validation
- Cascade delete: workItemService and invoiceService now delete document links before
  deleting the parent entity (polymorphic FK enforced at app layer)
- Service tests: 28 unit tests covering all service functions including
  Paperless metadata enrichment and error paths
- Route integration tests: 20 integration tests covering all endpoints,
  auth enforcement, validation, and cascade delete

Fixes #355

Co-Authored-By: Claude dev-team-lead (Sonnet 4.6) <noreply@anthropic.com>
Co-Authored-By: Claude qa-integration-tester (Sonnet 4.5) <noreply@anthropic.com>

* fix(paperless): fix import formatting in documentLinkService.test.ts

ESLint auto-fix during pre-commit split the AppError import into two
statements with missing space before closing brace, causing CI
format:check to fail. Consolidate into a single properly-formatted import.

Co-Authored-By: Claude dev-team-lead (Sonnet 4.6) <noreply@anthropic.com>

* fix(paperless): fix document links service and test helper issues

- documentLinkService.createLink: resolve userId against users table before
  inserting; store null if user no longer exists to avoid FK constraint failure
  (document_links.created_by is nullable with ON DELETE SET NULL)
- documentLinks.test.ts: fix createWorkItem helper to use correct response
  shape (POST /api/work-items returns work item directly, not { workItem: {...} })

Co-Authored-By: Claude dev-team-lead (Sonnet 4.6) <noreply@anthropic.com>

* docs(security): update wiki submodule ref for PR #363 security review

Records three new findings on the Security Audit page:
- Low: No ownership check on DELETE /api/document-links/:id
- Informational: deleteLinkSchema params lacks additionalProperties: false
- Informational: entityId field has no maxLength bound

Co-Authored-By: Claude security-engineer (Sonnet 4.6) <noreply@anthropic.com>

* chore: update review metrics for PR #363

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude dev-team-lead (Sonnet 4.6) <noreply@anthropic.com>
* feat(paperless): Document Browser & Search UI (Story #356)

Implements the Document Browser page for Paperless-ngx integration:

- `client/src/lib/paperlessApi.ts`: API client for status, list, get, tags, thumbnail URL, preview URL
- `client/src/hooks/usePaperless.ts`: React hook managing status/documents/tags/pagination/search/filter state
- `client/src/components/documents/DocumentBrowser.tsx`: Main reusable component with page/modal modes, search bar, tag filter strip, document grid, detail panel, and pagination
- `client/src/components/documents/DocumentCard.tsx`: Individual card with thumbnail, title, date, tags, accessible button role
- `client/src/components/documents/DocumentDetailPanel.tsx`: Expanded detail panel with metadata, content snippet, external link
- `client/src/components/documents/DocumentSkeleton.tsx`: Loading skeleton cards with shimmer animation
- All CSS modules use design tokens, no hardcoded hex values, responsive grid (3/2/1 col)
- Replaces stub DocumentsPage with full implementation delegating to DocumentBrowser
- Tests for all new modules (95%+ coverage target)

Fixes #356

Co-Authored-By: Claude dev-team-lead (Sonnet 4.6) <noreply@anthropic.com>
Co-Authored-By: Claude qa-integration-tester (Sonnet 4.5) <noreply@anthropic.com>

* fix(paperless): fix ESLint import() type annotations in test files

Replace inline import() type annotations with top-level import type * patterns
to satisfy @typescript-eslint/consistent-type-imports rule. Also fix TypeScript
type assertion for mock call args in usePaperless.test.tsx.

Co-Authored-By: Claude dev-team-lead (Sonnet 4.6) <noreply@anthropic.com>

* fix(paperless): apply Prettier formatting to document browser components

Co-Authored-By: Claude dev-team-lead (Sonnet 4.6) <noreply@anthropic.com>

* fix(paperless): fix overly broad date regex in DocumentCard test

The test `does not render date when created is null` used `/2025/` which
also matched the document title "Test Invoice 2025". Narrowed to a pattern
matching formatted date strings (e.g. "Mar 15, 2025") only.

Co-Authored-By: Claude dev-team-lead (Sonnet 4.6) <noreply@anthropic.com>

---------

Co-authored-by: Claude dev-team-lead (Sonnet 4.6) <noreply@anthropic.com>
)

* chore(agents): enforce strict delegation to Haiku in dev-team-lead

Implement layered controls to ensure the dev-team-lead agent delegates
all production code changes to Haiku developer agents instead of writing
code directly:

- Restructure dev-team-lead prompt with procedural workflow, tool usage
  policy table, and common failure modes table replacing negative rules
- Add mandatory delegation report to dev-team-lead return format
- Add pre-commit trailer verification step
- Insert delegation audit (step 6a) in develop skill between
  implementation and PR verification
- Add delegation audit to fix loop (step 9) in develop skill
- Add delegation reminder to dev-team-lead launch context
- Add Delegation Enforcement cross-team convention to CLAUDE.md
- Create pre-seeded dev-team-lead agent memory with delegation reminders

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: track agent memory in source control

Remove .claude/agent-memory/ from .gitignore so agent memory files are
version-controlled and shared across sessions and environments.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: add all agent memory files to source control

Copy agent memory from 9 agents (backend-developer, dev-team-lead,
docs-writer, frontend-developer, product-architect, product-owner,
qa-integration-tester, security-engineer, ux-designer) into version
control. The dev-team-lead MEMORY.md merges the new delegation
enforcement reminders with existing operational knowledge.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore(agents): fix consistency issues across delegation enforcement files

- Remove delegation bypass instruction in dev-team-lead memory that
  told agents to implement directly instead of using the Agent tool
- Fix conflicting Prettier directory advice in backend-developer memory
  (must run from worktree, not project root)
- Remove unsanctioned test exception in frontend-developer memory that
  allowed devs to fix tests inline (QA owns all tests, no exceptions)
- Align CLAUDE.md production file definition with agent definition
  (any file under server/client/shared, not just specific extensions)
- Expand delegation reminder in develop skill to mention both trailers
  and delegation report as audit mechanisms
- Fix wrong model attribution in docs workflow (frontend-developer is
  Haiku, not Sonnet)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* chore(agents): enforce strict delegation to Haiku in dev-team-lead

Implement layered controls to ensure the dev-team-lead agent delegates
all production code changes to Haiku developer agents instead of writing
code directly:

- Restructure dev-team-lead prompt with procedural workflow, tool usage
  policy table, and common failure modes table replacing negative rules
- Add mandatory delegation report to dev-team-lead return format
- Add pre-commit trailer verification step
- Insert delegation audit (step 6a) in develop skill between
  implementation and PR verification
- Add delegation audit to fix loop (step 9) in develop skill
- Add delegation reminder to dev-team-lead launch context
- Add Delegation Enforcement cross-team convention to CLAUDE.md
- Create pre-seeded dev-team-lead agent memory with delegation reminders

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: track agent memory in source control

Remove .claude/agent-memory/ from .gitignore so agent memory files are
version-controlled and shared across sessions and environments.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: add all agent memory files to source control

Copy agent memory from 9 agents (backend-developer, dev-team-lead,
docs-writer, frontend-developer, product-architect, product-owner,
qa-integration-tester, security-engineer, ux-designer) into version
control. The dev-team-lead MEMORY.md merges the new delegation
enforcement reminders with existing operational knowledge.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore(agents): fix consistency issues across delegation enforcement files

- Remove delegation bypass instruction in dev-team-lead memory that
  told agents to implement directly instead of using the Agent tool
- Fix conflicting Prettier directory advice in backend-developer memory
  (must run from worktree, not project root)
- Remove unsanctioned test exception in frontend-developer memory that
  allowed devs to fix tests inline (QA owns all tests, no exceptions)
- Align CLAUDE.md production file definition with agent definition
  (any file under server/client/shared, not just specific extensions)
- Expand delegation reminder in develop skill to mention both trailers
  and delegation report as audit mechanisms
- Fix wrong model attribution in docs workflow (frontend-developer is
  Haiku, not Sonnet)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore(skills): add /epic-run autonomous orchestration skill

Add a new /epic-run skill that chains the entire epic lifecycle
(plan → develop all stories → close) into a single autonomous session.
AUTO_MODE auto-approves intermediate gates (plan approval, bug specs,
PR merges, UAT) while preserving promotion-to-main as a mandatory
human checkpoint.

Changes:
- Create .claude/skills/epic-run/SKILL.md with 3-phase orchestration
- Add AUTO_MODE conditional blocks to epic-start (step 5),
  develop (steps 2 and 10), and epic-close (step 6)
- Update CLAUDE.md with /epic-run in skills table, AUTO_MODE
  convention section, and updated lifecycle descriptions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…kens, a11y (#368)

* fix(paperless): address review feedback — paperlessUrl passthrough, design tokens, a11y

- Add paperlessUrl field to PaperlessStatusResponse shared type
- Expose paperlessUrl in server status endpoint and propagate through
  service, hook, and component props so "View in Paperless-ngx" link renders
- Replace hardcoded spacing/padding/font-size/border-radius values with
  CSS custom properties (design tokens) across all document components
- Fix card border weight (2px → 1px), grid breakpoint overlap (1024 → 1023),
  and selected-card box-shadow to use primary-bg ring
- Add focus-visible states with shadow-focus-subtle on buttons
- Add aria-label on tag filter chips, aria-expanded/aria-controls on cards,
  id on detail panel for accessible pairing
- Add 44px min-height touch targets for tag chips on mobile
- Add prefers-reduced-motion: reduce media query for skeleton shimmer
- Fix deferred type imports in test files (after mock registration)
- Add tests for paperlessUrl passthrough and null cases

Fixes #356

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(paperless): apply Prettier formatting to 4 files

Pre-commit lint-staged was skipped due to corrupted git index in
worktree. Apply Prettier line-length fixes to pass CI format check.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude product-architect (Opus 4.6) <noreply@anthropic.com>
…re (#371)

Replace nested agent invocation (orchestrator → dev-team-lead → Haiku agents)
with a flat model where the orchestrator launches all agents directly using
specs produced by the dev-team-lead.

The dev-team-lead now operates in three modes:
- [MODE: spec] — reads wiki/codebase, returns structured implementation specs
- [MODE: review] — reads modified files, returns VERDICT with fix specs
- [MODE: commit] — stages, commits with trailers, pushes, creates PR, watches CI

This eliminates the unreliable nested Agent tool calls that caused the
dev-team-lead to write production code directly.

Co-authored-by: Claude product-architect (Opus 4.6) <noreply@anthropic.com>
#372)

* feat(documents): add document linking section to work item detail page

Adds a Documents section to the work item detail page that allows users
to link, view, and unlink Paperless-ngx documents. Includes document
picker modal, inline detail panel, loading/error/empty states, and
full accessibility support.

Fixes #357

Co-Authored-By: Claude dev-team-lead (Sonnet 4.6) <noreply@anthropic.com>
Co-Authored-By: Claude backend-developer (Haiku 4.5) <noreply@anthropic.com>
Co-Authored-By: Claude frontend-developer (Haiku 4.5) <noreply@anthropic.com>
Co-Authored-By: Claude qa-integration-tester (Sonnet 4.5) <noreply@anthropic.com>

* fix(documents): resolve CI failures — TypeScript ordering, Prettier format, CSS tokens

- Move closePicker declaration before useEffect that references it (TS2448/TS2454)
- Fix Prettier formatting in LinkedDocumentsSection.test.tsx
- Replace remaining hardcoded CSS values with design tokens in responsive breakpoint

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude frontend-developer (Haiku 4.5) <noreply@anthropic.com>

* fix(documents): address review findings — badge tokens, focus-visible, mobile modal

- Change count badge to neutral tokens (--color-bg-tertiary, --color-text-muted)
- Add :focus-visible styles to retryButton, modalClose, modalCancelButton, modalDeleteButton
- Make mobile modal full-viewport sheet at <768px
- Fix notConfiguredTitle font-size to var(--font-size-sm)
- Adjust modalContentLarge max-width to match UX spec (860px)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude frontend-developer (Haiku 4.5) <noreply@anthropic.com>

* chore: update review metrics for PR #372

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude product-architect (Opus 4.6) <noreply@anthropic.com>
* feat(documents): Add invoice support to document linking

- Updated useDocumentLinks hook to accept entityType and entityId instead of hardcoded workItemId
- Changed LinkedDocumentsSection to support work_item, household_item, and invoice entity types
- Added entity-specific copy for empty states, picker subtitle, and unlink confirmations
- Removed margin-top from LinkedDocumentsSection.section CSS (parent gap handles spacing)
- Updated WorkItemDetailPage to pass entityType="work_item" and entityId
- Added LinkedDocumentsSection to InvoiceDetailPage to display documents linked to invoices

Fixes #358

Co-Authored-By: Claude frontend-developer (Haiku 4.5) <noreply@anthropic.com>

* test(documents): update and add unit tests for Story #358 document linking for invoices

Update useDocumentLinks.test.ts to match new 2-arg signature (entityType + entityId),
add tests for invoice entity type, and fix waitFor conditions that relied on isLoading
starting as true (it starts as false).

Update LinkedDocumentsSection.test.tsx to match new props (entityType + entityId instead
of workItemId), add invoice entity type tests and work_item backwards-compatibility tests,
and add makeInvoiceLink helper fixture.

Create InvoiceDetailPage.test.tsx covering loading/error states, successful render, and
LinkedDocumentsSection integration (entityType=invoice, entityId=invoiceId).

Fixes #358

Co-Authored-By: Claude qa-integration-tester (Sonnet 4.6) <noreply@anthropic.com>

* style(documents): fix Prettier formatting in test files

Co-Authored-By: Claude qa-integration-tester (Sonnet 4.6) <noreply@anthropic.com>

* fix(documents): fix 3 test assertions blocking CI for Story #358

- useDocumentLinks: include isLoading check inside waitFor to avoid
  race condition with async state updates
- InvoiceDetailPage: use getAllByText for status badge since it renders
  in two places (page header + info list)
- LinkedDocumentsSection: skip invoice unlink copy test pending fix for
  bug #379 (hardcoded "this work item" in unlink modal)

Co-Authored-By: Claude qa-integration-tester (Sonnet 4.6) <noreply@anthropic.com>

* fix(documents): use entity-specific copy in unlink confirmation modal

The unlink confirmation dialog hardcoded "this work item" instead of
using the entity-specific copy from entityCopy[entityType].unlinkBody.
This caused invoice document unlink dialogs to incorrectly say
"will be removed from this work item" instead of "this invoice".

Also unskips the previously-skipped test for this scenario.

Fixes #379

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: update review metrics for PR #378

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude product-architect (Opus 4.6) <noreply@anthropic.com>
…ntegration (#380)

* feat(documents): add responsive design and accessibility polish for document integration

- Add touch scrolling and tablet breakpoints for DocumentBrowser, DocumentCard, and LinkedDocumentsSection
- Replace hardcoded pixel values with CSS custom properties (design token compliance)
- Add ARIA attributes, focus trap, keyboard navigation, and screen reader support to document components
- Add reduced motion support via prefers-reduced-motion media query
- Fix DocumentDetailPanel CSS for responsive layout on mobile viewports
- Update DocumentsPage CSS for consistent spacing across breakpoints
- Add and update unit tests for a11y and responsive behaviour coverage

Fixes #360

Co-Authored-By: Claude frontend-developer (Haiku 4.5) <noreply@anthropic.com>
Co-Authored-By: Claude qa-integration-tester (Haiku 4.5) <noreply@anthropic.com>
Co-Authored-By: Claude dev-team-lead (Sonnet 4.6) <noreply@anthropic.com>

* style(documents): fix Prettier formatting in DocumentBrowser and LinkedDocumentsSection test

Co-Authored-By: Claude dev-team-lead (Sonnet 4.6) <noreply@anthropic.com>

* chore: update review metrics for PR #380

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude product-architect (Opus 4.6) <noreply@anthropic.com>
…ations (#381)

- Backend: add additionalProperties: false and maxLength: 36 to documentLinks schemas
- Frontend: replace template literal query construction with URLSearchParams; add mobile touch target for modal close button
- QA: add validation tests for maxLength constraints and URLSearchParams encoding

Co-authored-by: Claude product-architect (Opus 4.6) <noreply@anthropic.com>
* test(e2e): add EPIC-08 document integration E2E test coverage

- Update DocumentsPage POM from stub to full implementation with locators
  for the DocumentBrowser "not configured" state
- Remove Documents test from stub-pages.spec.ts (page graduated to full
  feature in EPIC-08)
- Add e2e/tests/documents/documents-browser.spec.ts covering 8 scenarios:
  page load smoke, not-configured state rendering, env var instructions,
  navigation, responsive layout, dark mode, accessibility, and API status
- Add e2e/tests/documents/documents-linked-sections.spec.ts covering 10
  scenarios: LinkedDocumentsSection on work item detail (6) and invoice
  detail (4) — heading visibility, disabled add button, not-configured
  banner, aria-labelledby, responsive layout, dark mode

All tests validate against the "not configured" state since PAPERLESS_URL
and PAPERLESS_API_TOKEN are not set in the E2E testcontainer environment.

Fixes #360

Co-Authored-By: Claude qa-integration-tester (Sonnet 4.5) <noreply@anthropic.com>

* chore: update qa-integration-tester memory with EPIC-08 E2E findings

Records DocumentBrowser state machine, LinkedDocumentsSection selectors,
invoice detail route URL pattern, and Paperless API endpoints for future
test sessions.

Co-Authored-By: Claude qa-integration-tester (Sonnet 4.5) <noreply@anthropic.com>

---------

Co-authored-by: Claude product-architect (Opus 4.6) <noreply@anthropic.com>
…te (#383)

Add a new Documents guide section covering Paperless-ngx setup, document
browsing, and document linking to work items and invoices. Update the
landing page, roadmap, configuration, and README to reflect EPIC-08
completion. Write RELEASE_SUMMARY.md for the epic promotion.

Also fix pre-existing broken screenshot image references in work-items
and tags pages by replacing them with admonition blocks.

Fixes #360

Co-authored-by: Claude product-architect (Opus 4.6) <noreply@anthropic.com>
@steilerDev
Copy link
Copy Markdown
Owner Author

UAT Validation Criteria

Prerequisites

  • Scenario A (without Paperless): Run Cornerstone without PAPERLESS_URL / PAPERLESS_API_TOKEN set
  • Scenario B (with Paperless): Run Cornerstone with a Paperless-ngx instance accessible

Manual Testing Steps

1. Not Configured State (Scenario A)

  • Navigate to Documents page → "Paperless-ngx Not Configured" heading shown
  • Navigate to a work item detail → "Linked Documents" section shows "not configured" guidance
  • Navigate to an invoice detail → same "not configured" guidance
  • GET /api/paperless/status returns { configured: false }

2. Document Browser (Scenario B)

  • Documents page shows search input and document grid
  • Search filters documents with debounce
  • Tag filter strip shows available tags
  • Clicking a tag filters the document list
  • Clicking a document card opens detail panel
  • "Open in Paperless" link opens Paperless-ngx in new tab
  • Pagination works (next/previous)

3. Document Linking — Work Items (Scenario B)

  • Work item detail shows "Linked Documents" section
  • "Add Document" button opens picker modal
  • Selecting a document links it to the work item
  • Linked documents show as cards with thumbnails
  • Unlink button with confirmation removes the link
  • Duplicate linking is prevented

4. Document Linking — Invoices (Scenario B)

  • Invoice detail shows "Linked Documents" section
  • Same link/unlink flow as work items

5. Cascade Deletion

  • Delete a work item → its document links are also removed
  • Delete a vendor → its invoice document links are also removed

6. Responsive Design

  • Documents page renders without horizontal scroll at 375px (mobile)
  • Modal close button has adequate touch target on mobile
  • Cards stack vertically on narrow viewports

7. Accessibility

  • Keyboard-only navigation through document browser (Tab + Enter)
  • Modal closes with Escape key
  • Focus returns to trigger element after modal close
  • All interactive elements have visible focus indicators

8. Dark Mode

  • Documents page renders correctly in dark mode
  • Document cards and linked sections have appropriate contrast

@steilerDev steilerDev merged commit b34197d into main Mar 2, 2026
32 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

ghost commented Mar 2, 2026

🎉 This PR is included in version 1.11.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant