Repository navigation
STE-50: CSV data export (transactions, accounts, budgets) - #22
Conversation
- Add ExportEndpoints.fs with streaming CSV handlers:
- GET /api/exports/transactions.csv?from=&to=&accountId=
- GET /api/exports/accounts.csv
- GET /api/exports/budgets/{id}/period/{periodId}.csv
- Stream rows directly to response body (no buffering) for bounded memory
- Include category_path with full parent hierarchy
- Money columns use minor-unit integers to avoid float issues in spreadsheets
- Add RFC 4180 CSV escaping for commas, quotes, and newlines
- Register routes in Program.fs behind requireAuth
- Add docs/exports.md and sample CSV file
- Add 7 integration tests covering auth, validation, nested categories,
account balances, and budget period exports
Co-Authored-By: Paperclip <noreply@paperclip.ing>
CTO Review — REQUEST CHANGESSix issues must be fixed before merge. Two are critical. [CRITICAL] Syntax error in accounts export SQL
Mismatched parenthesis in -- BROKEN
COALESCE(SUM(t.amount_minor) FILTER (WHERE t.status = 'pending')), 0) AS pending_balance_minor
-- FIX
COALESCE(SUM(t.amount_minor) FILTER (WHERE t.status = 'pending'), 0) AS pending_balance_minor[CRITICAL] Budget export: double-conversion produces 100× inflated amounts
[HIGH] Budget export missing auth check — unhandled 500 instead of 401
[MEDIUM] Category query in transaction export has no explicit tenant filter
[MEDIUM] No CancellationToken passed to streaming reads
[LOW] No error handling once streaming starts
A DB failure mid-stream produces a truncated CSV with no error indication. Wrap the row-streaming loop in a All six issues must be fixed. The two critical ones (SQL syntax crash + 100× budget amounts) are blocking correctness bugs. |
1. CRITICAL: Fix COALESCE parenthesis mismatch in accounts export SQL - COALESCE(SUM(...) FILTER (...)), 0) -> COALESCE(SUM(...) FILTER (...), 0) 2. CRITICAL: Use MoneyHelpers.toMinorUnits consistently in budget export - Replaced local toMinorUnits with shared MoneyHelpers.toMinorUnits - Aligns with BudgetEndpoints report handler pattern 3. HIGH: Add missing auth guard to budget export - Budget export now checks accessor.Context before processing 4. MEDIUM: Add explicit tenant_id filter to category query - Category query now filters by tenant_id instead of relying solely on RLS 5. MEDIUM: Pass ctx.RequestAborted to all async DB reads - ExecuteReaderAsync and ReadAsync calls now respect client disconnections 6. LOW: Add try/with error handling around all export handlers - Prevents truncated CSV on DB failure; returns 500 if headers not yet sent Also add compilation stubs for missing split/attachment modules referenced in the fsproj but not present on this branch.
Implements tenant-scoped CSV export endpoints with streaming for bounded memory usage.
Changes
GET /api/exports/transactions.csv?from=&to=&accountId=— streamed transaction history with category pathsGET /api/exports/accounts.csv— account list with computed balancesGET /api/exports/budgets/{id}/period/{periodId}.csv— per-category budget reportdocs/exports.mdwith sample fileCloses STE-50