| 04-pdf-ingest |
02 |
api |
| next.js |
| api-routes |
| pdf |
| authentication |
| file-upload |
| path-traversal |
|
| phase |
provides |
| 04-pdf-ingest |
form_templates table + documents schema extension + seeds/forms/ directory |
|
| phase |
provides |
| 03-agent-portal-shell |
auth pattern (auth() from @/lib/auth), db pattern, portal data layer |
|
|
| GET /api/forms-library — authenticated form template list ordered by name |
| POST /api/documents — creates document record + copies seed PDF or writes custom upload to uploads/clients/{clientId}/{uuid}.pdf |
| GET /api/documents/[id]/file — authenticated PDF streaming with path traversal guard |
|
|
| added |
patterns |
|
|
| node:fs/promises (copyFile, mkdir, writeFile, readFile) for local file operations — no cloud storage |
| Path traversal guard |
| destPath.startsWith(UPLOADS_DIR) before any fs write |
|
| uploads/ kept outside public/ — files never served as static assets |
| Relative paths stored in DB (clients/{clientId}/{uuid}.pdf) — not absolute paths |
| content-type header branching for multipart/form-data vs JSON in POST handler |
|
|
| created |
modified |
| teressa-copeland-homes/src/app/api/forms-library/route.ts |
| teressa-copeland-homes/src/app/api/documents/route.ts |
| teressa-copeland-homes/src/app/api/documents/[id]/file/route.ts |
|
|
|
| uploads/ directory at project root (not under public/) — PDFs never accessible without auth |
| Relative paths stored in DB (clients/{clientId}/{uuid}.pdf) — absolute paths would break on server move |
| Path traversal guard on both write (POST) and read (GET /file) — prevents directory escape via malicious clientId or filePath |
| content-type branching in POST — single endpoint handles both form-data (custom upload) and JSON (template copy) |
|
| File serving routes: always guard with startsWith(BASE_DIR) before readFile |
| File writing routes: always guard with startsWith(UPLOADS_DIR) before copyFile/writeFile |
| params is a Promise in Next.js 15 App Router dynamic routes — always await params before destructuring |
|
|
1min |
2026-03-20 |