NWP-101: let ops choose export columns and scope - #161
Open
yvonne-so wants to merge 3 commits into
Open
Conversation
- CLAUDE.md: commands, app architecture map, Release Standards section - merchant-console/public/architecture.html: architecture page covering the payments export flow end to end - layout.tsx: beige page background in light mode - package-lock.json: refreshed by npm install Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Adds an options dialog to the Export button on /payments. - csv.ts: DEFAULT_EXPORT_COLUMNS (last four excluded), parseExportColumns server-side allowlist preserving requested order, scope segment in exportFilename - queries.ts: scope allowlist and exportRows, reusing the one query builder unpaginated so the file covers the whole scope, not the current page - export route: rejects an empty column selection with a 400 - export-dialog.tsx: column checkboxes, scope radios with row counts, Download disabled on an empty selection csv.test.ts: 9 new tests covering column subsets in requested order, the default exclusion of the card last four, empty and unknown selections, and scoped filenames. 37 tests pass. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The page still described the old fixed export and listed NWP-101 as pending. Now documents the seven-step flow including the dialog, a before/after table, and the rough edges left open. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ticket
Closes NWP-101
What changed
The Export button on
/paymentsnow opens an options dialog instead of immediately downloading a fixed file. Ops chooses which columns are included and whether the export covers the current filter or all payments, with the row count for each visible before download. The card last four is excluded by default, so a file bound for a merchant is clean unless someone ticks it on purpose.Business impact: ops stops hand-editing every export, removing 3–4 hours a month of spreadsheet cleanup and the risk of sending card data to the wrong merchant.
How I verified it
npm test:npm run lintclean,npm run buildsucceeds. All 9 pre-existing CSV tests still pass unchanged.Against a running dev server:
last4status=disputedpayments-disputed-2026-09-10.csv, 33 rowsscope=allpayments-all-2026-09-10.csv, 1,658 rows, filters ignoredcolumns=amount,id,merchantcolumns=or unknown names only{"message":"Select at least one column to export."}In the browser: opened the dialog on
/payments?status=disputed, confirmed both scope counts (33 and 1,658), confirmed the card last four starts unchecked, and deselected every column to confirm Download becomes a disabled button with a visible error rather than producing an empty file.npm testpassesAcceptance criteria
DEFAULT_EXPORT_COLUMNSinsrc/lib/csv.tsexportFilename(date, scope), e.g.payments-disputed-2026-09-10.csvNotes from the team, addressed
parseExportColumnschecks every name againstEXPORT_COLUMNS, drops unknowns, and returns an empty list rather than falling back to everything. A request ofcolumns=password,1=1,cvvyields a 400. The scope is also sanitized before it reaches a filename.exportRowsinsrc/data/queries.ts, which is unpaginated on purpose. Verified: 1,658 rows for all payments versus 20 on screen.exportRowscalls the samefilterPaymentsandsortPaymentsthe table uses. No second filter path.Bugs fixed along the way
None fixed. Two found and documented rather than changed, since both sit outside this ticket:
sortPaymentsinsrc/data/queries.tssorts by amount withString(...).localeCompare, so 900 orders after 10000. Affects export order when sorting by amount.src/components/has noDialog.tsx, though.claude/rules/components.mdlists one as available. This dialog reusesDrawer, which is the same Radix dialog primitive.Notes for the reviewer
On acceptance criterion 4: the
amountcell still renders throughformatMoney, so it reads$250.00while thecurrencycolumn separately readsUSD. Amounts remain integer minor units everywhere upstream and are formatted exactly once, at the edge, insrc/lib/csv.ts, and currency does have its own column. I left the symbol in place because two pre-existing tests pin that output andcsv.test.tsstates outright that this ticket changes which columns ship, not how a cell is written. Happy to switch the column to a plain decimal and update those two tests if you would rather the symbol went away.The first commit on this branch is unrelated onboarding work: root
CLAUDE.mdadditions, an architecture page underpublic/, and a beige light-mode background. Happy to split it out if you want this PR narrowed to the feature.🤖 Generated with Claude Code