Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/workflows/auto-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,13 @@ jobs:
fi
echo "tag=$RAW" >> "$GITHUB_OUTPUT"
echo "number=${RAW#v}" >> "$GITHUB_OUTPUT"
# Detect prerelease: v0.x.y is prerelease
# Detect prerelease:
# - v0.x.y is always prerelease (pre-1.0)
# - any tag with a SemVer pre-release identifier (e.g. -alpha, -beta,
# -rc, -alpha.18) is prerelease, regardless of major
MAJOR="${RAW#v}"
MAJOR="${MAJOR%%.*}"
if [[ "$MAJOR" -eq 0 ]]; then
if [[ "$MAJOR" -eq 0 ]] || [[ "$RAW" == *-* ]]; then
echo "prerelease=true" >> "$GITHUB_OUTPUT"
else
echo "prerelease=false" >> "$GITHUB_OUTPUT"
Expand Down
16 changes: 9 additions & 7 deletions .planning/STATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
gsd_state_version: 1.0
milestone: v1.1
milestone_name: Admin & Deploy
status: complete
stopped_at: Milestone v1.1 Admin & Deploy complete
last_updated: "2026-03-25T00:00:00Z"
status: ready_to_plan
last_updated: "2026-05-06T22:57:57.618Z"
progress:
total_phases: 7
completed_phases: 7
total_plans: 26
completed_plans: 26
percent: 100
---

# Project State
Expand All @@ -19,18 +19,18 @@ progress:
See: .planning/PROJECT.md (updated 2026-03-25 after v1.1 Admin & Deploy)

**Core value:** Democratizing legal advice by making contract analysis accessible and affordable for non-lawyers.
**Current focus:** Planning v2.0
**Current focus:** Phase 03 β€” pdf-export-history

## Current Position

Phase: 7 (COMPLETE)
Plan: Complete
Phase: 04
Plan: Not started

## Performance Metrics

**Velocity:**

- Total plans completed: 26
- Total plans completed: 29
- v1.0: 22 plans across 5 phases
- v1.1: 4 plans across 2 phases

Expand All @@ -48,10 +48,12 @@ All decisions logged in PROJECT.md Key Decisions table.
### Blockers/Concerns

**Resolved:**

- Admin analytics dashboard β€” Complete (Phase 6)
- Production deployment infrastructure β€” Complete (Phase 7)

**Known Gaps:**

- DEPLOY-01 live verification pending β€” Requires human testing on production environment

---
Expand Down
107 changes: 107 additions & 0 deletions .planning/phases/03-pdf-export-history/03-03-SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
phase: 03-pdf-export-history
plan: 03
subsystem: pdf-export-history
type: gap_closure
tags: [pdf, history, filters, uat]
requires: [03-01]
provides: ["Inclusive PDF footer", "Latin-1 PDF metrics", "Inclusive TO date filter", "Limpiar filtros button"]
affects: [server/utils/pdf-generator.ts, pages/history.vue]
tech-stack:
added: []
patterns:
- "pdfkit bufferPages + switchToPage post-pass for per-page footer"
key-files:
created: []
modified:
- server/utils/pdf-generator.ts
- pages/history.vue
decisions:
- "Use pdfkit bufferPages + iterate range over pageAdded event: simpler, works with autoFirstPage:true and yields correct total page count for 'PΓ‘gina X de N'"
- "Replace emoji with Spanish text labels rather than colored circles: avoids any font-glyph dependency and keeps metrics accessible to screen readers when copied"
metrics:
duration: ~10m
completed: 2026-05-06
requirements: [PDF-01, HISTORY-01, HISTORY-02]
---

# Phase 3 Plan 03: PDF & History UAT Gap Closure Summary

One-liner: Closed four UAT-diagnosed defects β€” PDF emoji garbling, missing footer on multi-page PDFs, exclusive TO date filter, and inaccessible "clear filters" action β€” restoring the polish promised by PDF-01 and HISTORY-02.

## Tasks Completed

| Task | Name | Commit | Files |
|------|------|--------|-------|
| 1 | Fix PDF emoji garbled characters | 3e1ab5d | server/utils/pdf-generator.ts |
| 2 | Fix PDF footer missing on most pages | e2b5cc0 | server/utils/pdf-generator.ts |
| 3 | Fix TO date filter not inclusive | e9f449f | pages/history.vue |
| 4 | Add "Limpiar filtros" button to main filter bar | 7c608c2 | pages/history.vue |

## What Changed

### Task 1 β€” PDF metrics readable text
Replaced the Helvetica-incompatible emoji (`πŸ”΄ 🟑 🟒`) with Spanish text labels:
`Hallazgos: N crΓ­ticos, N medios, N bajos`. Helvetica is Latin-1 only, so the
previous emoji glyphs rendered as `Ø=Ý`-style mojibake.

### Task 2 β€” Footer on every page
- Enabled `bufferPages: true` on the PDFDocument constructor.
- After all content is written, iterate `doc.bufferedPageRange()` and call
`doc.switchToPage(...)` on each, stamping the footer with correct `i+1 / total`.
- Removed the inline `addFooterToPage` calls that previously fired before each
`doc.addPage()` (no longer needed and produced placeholder `1 of 1` numbers).
- Added `doc.flushPages()` before `doc.end()` to ensure footer writes are committed.

### Task 3 β€” Inclusive TO date filter
The TO comparison previously used the raw midnight timestamp from
`new Date('YYYY-MM-DD')`, excluding any analysis created later that same day.
Now we set the parsed `Date` to `23:59:59.999` before comparing.

### Task 4 β€” Limpiar filtros button
Added a button to the main filter bar (between the date range inputs and the
risk-level pill group) that is visible only when `hasActiveFilters` is true and
calls the existing `resetFilters` helper. The reset path was previously only
reachable from the empty-results state, which is unreachable when filters return
results.

## Verification

- ESLint: `pages/history.vue` and `server/utils/pdf-generator.ts` pass after
prettier auto-fix on the latter (only a pre-existing `any` warning on the
helper signature remains; out of scope per SCOPE BOUNDARY).
- Functional verification (PDF render, multi-page footer, date inclusivity, button
toggle) requires a running app; UAT verifier will confirm in browser/PDF reader
per the plan's verification checklist.

## Deviations from Plan

**1. [Rule 3 - Tooling] Ran `eslint --fix` for prettier formatting**
- **Found during:** Task 2
- **Issue:** Touching `pdf-generator.ts` surfaced 23 pre-existing prettier
formatting errors that block lint gate.
- **Fix:** Auto-fix via `npx eslint --fix` (formatting only, no behavior change).
- **Files modified:** server/utils/pdf-generator.ts
- **Commit:** e2b5cc0 (folded into Task 2 commit since both touched same file)

**2. [Rule 1 - Bug] Plan suggested `pageAdded` event; used `bufferPages` + post-pass instead**
- **Found during:** Task 2
- **Issue:** `pageAdded` fires when a page is added, but at that point the page
count is not yet final, so `PΓ‘gina X de N` would still be wrong (X = page
number, N = unknown). Also doesn't help for the first page (which is added
before any listener attaches).
- **Fix:** Used `bufferPages: true` and looped over `bufferedPageRange()` after
content rendering. This yields correct totals and covers page 1.
- **Files modified:** server/utils/pdf-generator.ts
- **Commit:** e2b5cc0

## Authentication Gates
None.

## Known Stubs
None.

## Self-Check: PASSED
- FOUND: server/utils/pdf-generator.ts (modified)
- FOUND: pages/history.vue (modified)
- FOUND: 3e1ab5d, e2b5cc0, e9f449f, 7c608c2 (all commits in git log)
48 changes: 48 additions & 0 deletions .planning/phases/03-pdf-export-history/03-HUMAN-UAT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
status: complete
phase: 03-pdf-export-history
source: [03-VERIFICATION.md]
started: 2026-05-06T00:00:00Z
updated: 2026-05-06T23:30:00Z
---

## Current Test

[all 5 tests complete]

## Tests

### 1. PDF visual render on multi-page Forensic analysis
expected: Footer with disclaimer + "PΓ‘gina X de N" appears on every page; metrics text (no emoji) renders cleanly without garbled characters
result: passed (after fix 6c077fc) β€” 3-page generated PDF shows NOTA LEGAL + 2-line disclaimer + "PΓ‘gina X de 3" on pages 1, 2, 3; metrics line renders as "Hallazgos: 5 crΓ­ticos, 3 medios, 2 bajos" with clean accents and no garbled glyphs.
defect_found: original 03-03 footer post-pass auto-paginated due to doc.y inherited from switchToPage(); 9 spurious pages were generated. Fixed in 6c077fc by resetting doc.y/doc.x and forcing lineBreak:false on each text call.

### 2. Date TO filter inclusivity
expected: Selecting a TO date in history filters includes analyses created on that date through end-of-day (23:59:59)
result: passed (after fix 6c077fc) β€” HASTA=2026-05-06 returns all 5 seeded analyses including today's (created at 17:15 local).
defect_found: original `new Date(value); setHours(23,59,59)` resolved to end-of-day UTC, which is the prior day in UTC-6, so HASTA=today excluded today's analyses. Fixed by anchoring to local time via `new Date(value + "T23:59:59.999")`.

### 3. "Limpiar filtros" button visibility toggle
expected: Button appears in main filter bar when any filter is active and clears all filters when clicked; hidden when no filters active
result: passed β€” button appeared after setting HASTA, cleared both date inputs on click, and disappeared once no filter was active.

### 4. PDF caching round-trip
expected: Subsequent PDF downloads of the same analysis return cached PDF from Supabase Storage
result: passed β€” first export-pdf returned `cached: false`, second returned `cached: true` against the same signed Storage URL (verified via fetch).

### 5. Cross-user PDF access denial
expected: User A cannot download PDF for an analysis owned by User B (RLS/ownership enforced)
result: passed β€” seeded user2 (3273b585...) with private analysis 18072af2. User1 fetching `/api/analyses/18072af2.../export-pdf` returns 404 NOT_FOUND_ERROR. Endpoint correctly denies and does not leak ownership (404 rather than 403).

## Summary

total: 5
passed: 5
issues: 0
pending: 0
skipped: 0
blocked: 0

## Gaps

None outstanding from this run. Two defects were caught during runtime testing (timezone-sensitive TO filter, footer post-pass overflow) and resolved in commit 6c077fc β€” recorded under each test's `defect_found` line.
Loading
Loading