Feature breakdown · built with CraftHQ
Tabular data export (CSV / spreadsheet)
Whole-team time at this build's pace
2 people incl. the product owner, requirements to merge
Estimate at this build's pace, not a measurement of this feature
Any list can be taken out as CSV or a spreadsheet, matching the filter on screen. A sensitive-data export is restricted to administrators and audited. The measured window here is one list switched to spreadsheet format.
How long a feature this size usually takes
Whole-team time — this build vs a typical team
~5 FP · FP × 6.8 to 9.4 h (ISBSG 2023)
Estimate at this build's pace, not a measurement of this feature
Both figures are whole-team time over the whole lifecycle, so they compare like for like. Ours is this build's pace — about 0.8 hours per function point across the whole build (two people, including the product owner, with requirements and review time). The industry range is an ISBSG project-level figure applied to one feature, so it is indicative.
The pull request time covers one change to this feature; the estimate covers building the whole feature.
Workflow
How it moved through the workflow
Select a stage. The build shipped, so every stage is complete; a person approved the merge.
Request
Switch one list export from CSV to spreadsheet format, keeping filter parity, plain headers, resolved display names, and the guard on sensitive columns.
Questions
Two decisions were recorded before building: offer CSV, a spreadsheet, or both; and resolve internal ids to display names or leave them raw.
Approved
The product owner signs off the breakdown by moving the story into the approved state, and the build runs against that reference.
Definition of ready
Building
This change shipped as one pull request: switching one list to spreadsheet format, with its test. The filter-parity work and the export-change guard shipped as separate changes.
Checks
Three checks run on every pull request: one on the product owner's machine as CraftHQ builds, one on the engineer's machine before review, and a code-quality scan in CI. Merging is gated by the CI check passing and a person's approval, enforced by branch protection.
Review
An engineer reviews the pull request and merges it.
Merged
The pull request is merged to main after a person approves it. Nothing merges without that approval. The measured window here is one pull request, opened to merged.
Definition of done
Breakdown
The feature breakdown
Business first, then the engineering view. Tab through it.
Overview
The gap it closes
People need to work with a list outside the product, but a raw export can leak sensitive columns, resolve ids to personal data, or drift from what is on screen.
Who uses it
Staff who export a list to work with it elsewhere; an administrator-only rule governs a sensitive register export.
User story
As a staff user, I want to export a list to a spreadsheet so that I can work with it outside the product.
Examples
Example 1
A user filters a list on screen, exports it, and gets a spreadsheet with the same rows, plain headers, and display names in place of raw ids.
Example 2
A staff register export carries a sensitive identifier. It is available only to administrators and writes an audit row; a non-admin who can view the list cannot export it. A customer's own export is scoped to their records and capped at 10,000 rows, raising an error rather than silently truncating.
Dependencies & risks
Depends on
A CSV and spreadsheet writer, the on-screen filter query run under the user's tenant and role scope, an admin-only-and-audited rule for a sensitive register export, and a 10,000-row cap on the customer export.
Risk & mitigation
An export could carry sensitive data or drift from the screen. Reduced by running the same authorised, tenant-scoped query as the screen, restricting a sensitive register export to administrators with an audit row, and capping the customer export.
How it works
Simplified diagrams of the parts involved, the steps of one request, and where it runs.
Architecture
- 1exports the list
- 2with the on-screen filter
- 3same authorised, tenant-scoped read
- 4admin-only for a sensitive register export
- 5record a sensitive export
Sequence
- 1export this list
- 2run the same authorised, tenant-scoped query as the screen
- 3the filtered rows
- 4resolve ids to display names, apply the admin-only control for a sensitive export
- 5append an audit row for a sensitive export
- 6a CSV or spreadsheet file
Infrastructure
- 1export request (authenticate + tenant check)
- 2scoped read, append audit
Acceptance criteria
Each scenario is written as a Gherkin spec. The Engineering tab shows the test that covers each one, or notes where it was verified by review.
@platform @dataFeature: Tabular data exportAs a staff userI want to export a list to a spreadsheetSo that I can work with it outside the productAny list can be taken out as CSV or a spreadsheet, matching the filter on screen. A sensitive register export is restricted to administrators and audited.Background:Given a staff user is viewing a listRule: A list exports in the format the user picks, for a user who may exportScenario: Export a list to CSV or a spreadsheetGiven a list on screenWhen the user exports itThen they can choose CSV or a spreadsheetScenario: A user without export permission is refusedGiven a user whose role may not export a listWhen they try to export itThen the export is refusedRule: The export matches what is on screenScenario: The export matches the on-screen filterGiven the list is filtered on screenWhen the user exports itThen the export runs the same authorised, tenant-scoped query as the screenAnd it contains the same rows as the filtered listRule: A sensitive register export is administrator-only and auditedScenario: A sensitive register export is restricted to administratorsGiven a staff register export carries a sensitive identifier columnWhen a non-administrator who can view the list tries to export itThen the export is refusedAnd an administrator may export it, with an audit row writtenScenario: A build-time guard flags a new sensitive exportGiven a new download sink or sensitive column is added without a declared carve-outWhen the build runsThen the build failsRule: A customer's own export is scoped and cappedScenario: A customer export is scoped to its own records and cappedGiven a customer exports their own listWhen the export runsThen it includes only the customer's own records, writes an audit row, and is capped at 10,000 rows, raising an error rather than silently truncatingScenario: A staff caller cannot use the customer exportGiven a staff caller calls the customer exportWhen the request is madeThen it is refused@edge-casesScenario Outline: Export by role and sensitivityGiven a list with sensitive columns "<sensitive>" exported by a "<role>"When the export runsThen the result is "<result>"Examples:| sensitive | role | result || none | staff | the filtered rows, with plain headers || register column | administrator | exported with an audit row written || register column | non-admin | export refused || none | customer | own records only, capped at 10,000, an audit row |
Questions
Questions raised in planning, each with the decision taken.
Should a list export as CSV or as a spreadsheet?
CSV is simple and universal; a spreadsheet preserves formatting and is easier to read. Offering both covers each use.
Should internal ids be resolved in the export, or left as raw ids?
Raw internal ids are meaningless outside the product. Resolving them to display names is usable, but a display name can be personal data (an email address), so it is treated as personal data and a sensitive register export is restricted to administrators and audited.
How we sized it
A function point measures what the software does — its inputs, outputs, lookups and the data it stores — regardless of language or how many lines it took. Each counted item is weighted by complexity: a user input counts 3–6 points, an output or report 4–7, a lookup 3–6, data the feature owns 7–10, and data read from elsewhere 5–7.
- Export a list to CSV or a spreadsheetOutput or report5
- Total5
Not counted here
- Sensitive-column handling: part of the export, not a separate function
Components touched
Export writer
Writes a list to CSV or a spreadsheet, the user's choice, for a user whose role may export it.
Filter parity
The export runs the same authorised, tenant-scoped query as the screen, so it contains the same rows the user can see.
Sensitive-export control
A staff register export that carries a sensitive identifier is restricted to administrators and writes an audit row; a non-admin who can view the list cannot export it. A build-time guard fails the build if a new download sink or sensitive column is added without a declared carve-out.
Customer export cap
A customer's own export is scoped to their records and capped at 10,000 rows, raising an explicit error rather than truncating; a staff caller is refused.
Data touched
List recordsread
Read with the same filter as the on-screen list, under the user's tenant and role scope. Tenant isolation is enforced in the database (row-level security on every table, pinned per transaction); see Multi-tenant data isolation.
Audit logappend
An audit row is written for an administrator's export of a sensitive register column.
Security decisions
- The export runs the same authorised, tenant-scoped query as the screen, so a crafted request cannot widen it beyond what the user may see; a customer export is additionally capped at 10,000 rows.
- A staff register export that carries a sensitive identifier is administrator-only and writes an audit row. A build-time guard flags any new download sink or sensitive column added without a declared carve-out.
Subtasks
- A CSV and spreadsheet writer, gated by export permission.
- Filter parity with the authorised, tenant-scoped on-screen query.
How each scenario is verified
- Export a list to a spreadsheetAn XLSX export test checks the header row, the values and the date format.
- The export matches the on-screen filterA filter-parity integration test checks the list equals the export under a filter, and that a mapped staff member exports only their own customers.
- A customer export is scoped, audited and cappedA portal-export test checks a customer exports only its own records with an audit row, a staff caller is refused (403), no session is 401, a malformed filter is 400, and the 10,000-row cap raises an error rather than truncating.
Risk tier
Logic A person approves every merge. This is a Logic-tier change: an export can carry sensitive data out of the product. The risk is a leak or a drift from the screen, reduced by the authorised tenant-scoped query and the administrator-only, audited register export.
Activity
Real pull-request window for one small export change.
- Pull request opened: switch a list export to spreadsheet format
- Merged to main after a person approved
Start here
Want this on your backlog?
Get a free baseline report on one repository, or scope a 3-month pilot measured against what your team’s work costs today.