Files
red/.planning/phases/07-audit-trail-and-download/07-VERIFICATION.md
2026-03-21 11:02:37 -06:00

14 KiB

phase, verified, status, score, re_verification, previous_status, previous_score, gaps_closed, gaps_remaining, regressions, human_verification
phase verified status score re_verification previous_status previous_score gaps_closed gaps_remaining regressions human_verification
07-audit-trail-and-download 2026-03-21T17:00:00Z human_needed 10/10 must-haves verified true gaps_found 8/10
GET /api/documents/[id]/file NEVER serves the signed PDF — signedFilePath fallback removed, doc.filePath only
LEGAL-03: sole signed PDF download path is now /api/documents/[id]/download?adt=[token] — /file route confirmed clean
PdfViewer Download anchor absent when docStatus is 'Signed' — {docStatus !== 'Signed' && ...} conditional confirmed at line 60
test expected why_human
Navigate to a Signed document detail page (http://localhost:3000/portal/documents/[id]) and inspect the PDF viewer toolbar The toolbar Download anchor is absent for Signed documents. Only the PreparePanel 'Download Signed PDF' button should be visible. The {docStatus !== 'Signed' && ...} conditional is confirmed in code, but runtime rendering with an actual Signed document cannot be verified statically.
test expected why_human
With a valid Auth.js session, visit /api/documents/[known-signed-uuid]/file directly in the browser The response is the original unsigned PDF — NOT the signed PDF. The signed PDF is available only via /api/documents/[id]/download?adt=[token]. The signedFilePath reference is confirmed absent from /file route, but runtime behavior (correct original file serving) requires a running app and a Signed document in the DB.
test expected why_human
Visit http://localhost:3000/uploads/ and http://localhost:3000/uploads/clients/ in a browser Both URLs return 404 — no directory listing or file contents. Requires a running dev or prod server — static file serving behavior cannot be verified programmatically.
test expected why_human
Click 'Download Signed PDF' in PreparePanel for a Signed document Browser PDF download dialog appears; downloaded file is a PDF containing the drawn signature. End-to-end flow requires a running app and a Signed document with signedFilePath populated.

Phase 7: Audit Trail and Download — Verification Report

Phase Goal: Agent can download any signed PDF securely, and signed documents are never accessible via guessable public URLs Verified: 2026-03-21 Status: human_needed Re-verification: Yes — after gap closure (Plan 07-04)


Re-verification Summary

Item Previous Status Current Status
Gap 1: /file route serving signedFilePath PARTIAL CLOSED
Gap 2: LEGAL-03 two download paths FAILED CLOSED

Both gaps from the initial verification were closed by Plan 07-04. All 10 observable truths now pass automated verification. Remaining items require human testing with a running application.


Goal Achievement

Observable Truths

# Truth Source Plan Status Evidence
1 GET /api/documents/[id]/download?adt=[token] streams the signed PDF when the agent-download JWT is valid 07-01 VERIFIED Route exists at src/app/api/documents/[id]/download/route.ts. verifyAgentDownloadToken called, readFile + Response streaming confirmed.
2 A missing or expired adt token returns 401 — no file served 07-01 VERIFIED Lines 22-27 (missing adt) and 33-38 (catch block) both return 401.
3 An adt token for document A cannot download document B (documentId vs id mismatch returns 403) 07-01 VERIFIED if (documentId !== id) returns 403 at line 41-46.
4 A signedFilePath containing path traversal characters returns 403 07-01 VERIFIED absPath.startsWith(UPLOADS_DIR) guard before readFile at lines 61-67.
5 A document with no signedFilePath (unsigned) returns 404 07-01 VERIFIED `if (!doc
6 Agent sees a Download button on the document detail page when document status is Signed 07-02 VERIFIED PreparePanel: if (currentStatus === 'Signed') branch renders <a href={agentDownloadUrl}> at line 53-57.
7 Download button is absent when document status is Draft, Sent, or Viewed 07-02 VERIFIED Signed branch returns early; non-Draft branch at line 76-82 renders read-only message; Draft renders prepare form.
8 Dashboard table shows a Date Signed column populated for Signed documents 07-02 VERIFIED DocumentsTable.tsx: signedAt in type, th header, td cell. Dashboard query includes signedAt.
9 GET /api/documents/[id]/file NEVER serves the signed PDF — always reads doc.filePath only 07-04 VERIFIED /file/route.ts line 25: const relativePath = doc.filePath. Zero grep matches for signedFilePath in that file. Comment updated to reference LEGAL-03.
10 LEGAL-03: sole download path for signed PDFs is /api/documents/[id]/download?adt=[token] (presigned, 5-min TTL) LEGAL-03 VERIFIED Two-part evidence: (1) /file route no longer references signedFilePath — confirmed by grep returning no matches. (2) PdfViewer.tsx line 60: {docStatus !== 'Signed' && (<a href=...download>)} — toolbar Download anchor hidden for Signed documents. Only download path remaining is PreparePanel presigned URL.

Score: 10/10 truths verified


Required Artifacts

Plan 07-01 Artifacts

Artifact Expected Status Details
teressa-copeland-homes/src/lib/signing/token.ts createAgentDownloadToken and verifyAgentDownloadToken exports VERIFIED Both functions present at lines 52-64. TTL 5m, purpose:'agent-download'. Existing 4 exports untouched.
teressa-copeland-homes/src/app/api/documents/[id]/download/route.ts GET handler streaming signed PDF for authenticated agent download VERIFIED 87-line file. 401/403/404 security paths all implemented. Streaming via new Uint8Array(fileBuffer).

Plan 07-02 Artifacts

Artifact Expected Status Details
teressa-copeland-homes/src/app/portal/(protected)/documents/[docId]/page.tsx Server component generating agentDownloadUrl and passing to PreparePanel VERIFIED Line 9 imports createAgentDownloadToken. Lines 35-37 generate URL. Lines 66-67 pass props to PreparePanel.
teressa-copeland-homes/src/app/portal/(protected)/documents/[docId]/_components/PreparePanel.tsx Download button rendered only when currentStatus === Signed and agentDownloadUrl is non-null VERIFIED Lines 6-13 interface. Line 34: Signed branch. Line 53: agentDownloadUrl conditional anchor. Sent/Viewed/Draft branches all distinct.
teressa-copeland-homes/src/app/portal/_components/DocumentsTable.tsx DocumentRow type with signedAt field + Date Signed column VERIFIED signedAt: Date
teressa-copeland-homes/src/app/portal/(protected)/dashboard/page.tsx Select includes signedAt from documents table VERIFIED signedAt: documents.signedAt in db.select().

Plan 07-04 Artifacts (Gap Closure)

Artifact Expected Status Details
teressa-copeland-homes/src/app/api/documents/[id]/file/route.ts Restricted /file route — doc.filePath only, no signedFilePath reference VERIFIED Line 25: const relativePath = doc.filePath. Grep for signedFilePath returns zero matches. Comment reads "Serve the original unsigned PDF only — see LEGAL-03".
teressa-copeland-homes/src/app/portal/(protected)/documents/[docId]/_components/PdfViewer.tsx Download anchor absent when docStatus is 'Signed' VERIFIED Line 60: {docStatus !== 'Signed' && ( wrapping the Download <a>. Document file prop (/api/documents/${docId}/file) unchanged at line 74 — viewer still loads original for display.

From To Via Status Details
route.ts (download) token.ts import { verifyAgentDownloadToken } WIRED Line 2: import present. Used at line 31.
route.ts (download) uploads/ directory readFile + path.join(UPLOADS_DIR, signedFilePath) + startsWith guard WIRED UPLOADS_DIR at line 9. startsWith guard at line 62. readFile at line 71.
From To Via Status Details
documents/[docId]/page.tsx token.ts import { createAgentDownloadToken } WIRED Line 9: import present. Called at line 36.
documents/[docId]/page.tsx PreparePanel agentDownloadUrl prop WIRED Line 66: agentDownloadUrl={agentDownloadUrl}. Line 67: signedAt={doc.signedAt ?? null}.
dashboard/page.tsx DocumentsTable rows prop including signedAt field WIRED signedAt in select at line 25. rows={filteredRows} passed to DocumentsTable.
From To Via Status Details
PdfViewer.tsx /api/documents/[id]/file Document file prop (viewing only — not downloadable for Signed) WIRED (viewing) / GATED (download) Document component still uses /file for display (line 74). Download <a> pointing to /file is wrapped in {docStatus !== 'Signed' && ...} at line 60.

Requirements Coverage

Requirement Source Plans Description Status Evidence
SIGN-07 07-01, 07-02, 07-03, 07-04 Agent can download the signed PDF from the dashboard SATISFIED Presigned download route (07-01), PreparePanel Download button (07-02), human checkpoint (07-03). REQUIREMENTS.md shows [x] at line 51.
LEGAL-03 07-01, 07-02, 07-03, 07-04 Signed PDFs never accessible via public or guessable URLs; agent downloads via authenticated presigned URLs only SATISFIED Presigned URL system (07-01/02). /file route restricted to filePath only — signedFilePath reference removed (07-04). PdfViewer Download anchor hidden for Signed (07-04). REQUIREMENTS.md shows [x] at line 57. Both requirements marked Complete in requirements table (lines 137-138).

Both requirement IDs from all four PLANs are accounted for. No orphaned requirements found in REQUIREMENTS.md for Phase 7.


Anti-Patterns Found

No blockers or warnings remaining. Previous anti-patterns were resolved by Plan 07-04:

File Previous Pattern Resolution
src/app/api/documents/[id]/file/route.ts doc.signedFilePath ?? doc.filePath served signed PDF via session auth Removed — line 25 now reads doc.filePath only
src/app/portal/(protected)/documents/[docId]/_components/PdfViewer.tsx Persistent <a href=.../file download> for all statuses Wrapped in {docStatus !== 'Signed' && ...} at line 60

Human Verification Required

All automated checks pass. The following items require a running application and a Signed document in the database to confirm end-to-end behavior.

1. PdfViewer Toolbar — Download Anchor Absent for Signed Documents

Test: Log in to the portal. Navigate to a Signed document detail page (/portal/documents/[id]). Examine the PDF viewer toolbar (top of viewer). Expected: No "Download" anchor appears in the toolbar for Signed documents. The only download option visible is the PreparePanel "Download Signed PDF" button in the right sidebar. Why human: The conditional {docStatus !== 'Signed' && (...)} is confirmed in source at line 60, but runtime rendering with an actual Signed document cannot be verified statically.

2. /file Route Serves Original PDF Only for Signed Documents

Test: With a valid agent Auth.js session, navigate directly to http://localhost:3000/api/documents/[known-signed-doc-uuid]/file in the browser. Expected: The response is the original unsigned PDF (before signing), NOT the signed PDF. The signed PDF is exclusively available via /api/documents/[id]/download?adt=[token]. Why human: The signedFilePath reference is confirmed absent from the route, but runtime behavior (serving the correct original file) requires a running app with a Signed document in the DB.

3. Guessable /uploads/ URL Returns 404

Test: In a browser, visit http://localhost:3000/uploads/ and http://localhost:3000/uploads/clients/. Expected: Both URLs return 404 — no directory listing, no file contents accessible. Why human: Requires a running dev or prod server — Next.js static file serving behavior cannot be verified programmatically.

4. End-to-End Presigned Download Flow

Test: From the dashboard, click a Signed document, then click "Download Signed PDF" in the PreparePanel. Expected: Browser PDF download dialog appears. The downloaded file is a valid PDF containing the drawn signature (not the blank original). Why human: End-to-end flow requires a running application, a complete signing ceremony in the DB, and a signedFilePath-populated document.


Summary

The two gaps from the initial verification were both closed by Plan 07-04 (committed 2026-03-21, commits 6775cc7 and cac5d5b):

  1. /api/documents/[id]/file/route.ts — Line 25 changed from doc.signedFilePath ?? doc.filePath to doc.filePath. The signedFilePath fallback that created a second, non-presigned download path for signed PDFs has been removed. Grep confirms zero occurrences of signedFilePath in this file.

  2. PdfViewer.tsx — Line 60 wraps the toolbar Download anchor in {docStatus !== 'Signed' && (...)}. The Download link pointing to /file is now absent when viewing a Signed document. The <Document file=...> prop for in-browser display is unchanged (still uses /file to load the original PDF).

LEGAL-03 is now satisfied: the only download path for a signed PDF is GET /api/documents/[id]/download?adt=[token] — a presigned, 5-minute JWT-gated route created in Plan 07-01. REQUIREMENTS.md confirms both SIGN-07 and LEGAL-03 are marked [x] complete.

The four remaining human verification items are observational (runtime behavior, rendering confirmation, and file serving confirmation) — they do not represent code gaps, only testing checkpoints that require a running application.


Verified: 2026-03-21 Verifier: Claude (gsd-verifier)