Final audit pass on feat/berth-recommender (3 parallel Opus agents) caught 5 critical and ~12 high-severity findings. All addressed in-branch; medium/low items deferred to docs/audit-final-deferred.md. Critical: - Add filesystem-backend PUT handler at /api/storage/[token] so presigned uploads stop 405-ing in filesystem mode (every browser-driven berth-PDF + brochure upload was broken). Same token-verify + replay protection as GET, plus magic-byte gate when c=application/pdf. - Forward req.signal into streamExpensePdf so an aborted 1000-receipt export no longer keeps grinding for minutes. - Strengthen Content-Disposition filename sanitization: \s matches CR/LF which would let documentName forge headers; restrict to [\w. -]+ and add filename* RFC 5987 fallback. - Lock public berths feed behind an explicit slug allowlist instead of ?portSlug= enumeration. - Reject cross-port interest_berths upserts (defense-in-depth on top of the recommender SQL port filter). High: - Recommender: width-only feasibility now caps length via L/W ratio so a 200ft berth doesn't surface for a 30ft beam request; total_interest_count filters out junction rows whose interest is in another port. - Mooring normalization follow-up migration (0034) catches un-hyphenated padded forms (A01) the original 0024 WHERE missed. - Send-out rate limit moved AFTER validation and scoped per-(port, user) so typos don't burn a slot and a multi-port rep can't be DoS'd by another tenant. - Default-brochure path now blocks an archived row from sneaking through the partial unique index. - NocoDB import --update-snapshot honoured under --dry-run so reps can refresh the seed JSON without committing DB writes. - PDF export: orderBy desc(expenseDate); apply isNull(archivedAt) when expenseIds are passed (was bypassed); flag rate-unavailable rows with an amber footer instead of silently treating them as 1:1; skip the USD->EUR chain when source already matches target. - expense-form-dialog: revokeObjectURL captures the URL in the closure instead of revoking the still-displayed one; reset upload state on close. - scan/page: handleClearReceipt resets in-flight scan/upload mutations; Save disabled while upload pending. - updateExpense re-asserts receipt-or-acknowledgement at the merged row so PATCH can't slip past the create-time refine. Plus the in-progress receipt upload UI for the expense form dialog (receipt picker + "I have no receipt" checkbox + warning banner) and a noReceiptAcknowledged flag on ExpenseRow for edit-mode hydration. Includes the canonical plan doc (referenced in CLAUDE.md), the handoff prompt, and a deferred-findings index for follow-up issues. 1163/1163 vitest passing. Typecheck clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
56 lines
1.0 KiB
Plaintext
56 lines
1.0 KiB
Plaintext
node_modules/
|
|
.next/
|
|
.nuxt/
|
|
.worktrees/
|
|
.env
|
|
.env.local
|
|
.env.production
|
|
*.pem
|
|
*.key
|
|
drizzle/*.sql
|
|
coverage/
|
|
.turbo/
|
|
out/
|
|
dist/
|
|
test-results/
|
|
playwright-report/
|
|
nginx/certs/
|
|
tsconfig.tsbuildinfo
|
|
.playwright-mcp/
|
|
docker-compose.override.yml
|
|
.remember/
|
|
.DS_Store
|
|
# Root-only ad-hoc EOI scratch dir; routes under src/app/.../eoi/ must NOT match.
|
|
/eoi/
|
|
|
|
# Brainstorming companion mockup files
|
|
.superpowers/
|
|
|
|
# Ad-hoc screenshots / scratch artifacts at repo root
|
|
/*.png
|
|
/*.jpg
|
|
|
|
# Legacy Nuxt portal — kept on disk for reference, not tracked here
|
|
/client-portal/
|
|
|
|
# Sister marketing site — separate Nuxt project, not part of CRM tracking
|
|
/website/
|
|
|
|
# Mobile audit screenshots — generated locally, regenerable
|
|
/.audit/
|
|
/.audit-screenshots/
|
|
|
|
# Migration script output (CSV reports, transcripts)
|
|
.migration/
|
|
|
|
# Tool caches / runtime state
|
|
/.claude/
|
|
/.serena/
|
|
/ruvector.db
|
|
|
|
# Filesystem storage backend root (FilesystemBackend default location)
|
|
/storage/
|
|
|
|
# Local berth-PDF + brochure samples used as upload fixtures during dev.
|
|
/berth_pdf_example/
|