User Stories
Purpose
User stories are governing design artifacts, not throwaway tickets. Each story defines one persona’s complete vertical journey through feature behavior that is independently implementable and testable. Tracker issues reference stories; stories don’t reference tracker issues. Stories are more stable than the implementation beads that fulfill them.
The feature spec owns behavior and boundaries. A user story owns a journey through that behavior: who starts it, what they do, what the system shows, and what outcome proves the slice works.
Authoring guidance
- One story, one vertical slice — a story should trace a complete path from user action to outcome. If it can’t be demonstrated end-to-end, it’s not a story yet.
- Stable reference — stories will be referenced by multiple tracker issues across design, implementation, and testing. Write them to last.
- Implementer-sufficient — an implementer reading only this story and the parent feature spec should be able to build it without asking clarifying questions.
- Test-first friendly — acceptance criteria and test scenarios should be concrete enough to write tests before writing code.
- Traceable to feature behavior — each story should name the feature requirements it exercises. Do not invent behavior outside the parent feature spec.
Quality checklist from the prompt
After drafting, verify every item. If any blocking check fails, revise before committing.
Blocking
- Story names a specific persona from the PRD (not a generic role)
- “I want” describes a user action, not a system behavior
- “So that” names a measurable outcome, not a tautology
- Walkthrough traces a complete path from trigger to outcome
- Every acceptance criterion is independently testable (one Given/When/Then)
- Test scenarios include concrete values, not placeholders
- Story links to parent feature spec by ID
- Story names the parent feature requirement IDs it exercises
Warning
- Context would be missed if removed (not generic filler)
- At least one edge case is documented
- Test scenarios cover both happy path and at least one edge case
- Out of scope excludes something plausible
- No compound acceptance criteria (split into separate items)
- Story does not invent behavior outside the parent feature spec
Example
Show a worked example of this artifact
---
ddx:
id: example.user-story.depositmatch.upload-csv
depends_on:
- example.feature-specification.depositmatch.csv-import
---
# US-001: Upload CSV Files for a Client
**Feature**: FEAT-001 - CSV Import and Column Mapping
**Feature Requirements**: UP-01, UP-02
**Priority**: P0
**Status**: Approved
## Story
**As a** Maya, the reconciliation lead
**I want** to upload bank and invoice CSV files for one client
**So that** I can start weekly reconciliation from the client's current source
data without rebuilding the import context by hand.
## Context
Maya receives weekly bank and invoice exports from each client she manages. This
story covers the first step of FEAT-001: associating one bank deposit CSV and
one invoice export CSV with the selected client and import session. It exercises
UP-01 and UP-02 only; mapping, validation, and import summary behavior are
covered by follow-on stories.
## Walkthrough
1. Maya opens Acme Dental's reconciliation workspace and chooses to start a new
import session.
2. DepositMatch shows bank deposit and invoice export upload controls for Acme
Dental.
3. Maya selects `acme-bank-2026-05-08.csv` and
`acme-invoices-2026-05-08.csv`.
4. DepositMatch accepts both CSV files, associates them with the Acme Dental
import session, and opens the mapping review step.
## Acceptance Criteria
- [ ] Given Maya is viewing Acme Dental, when she uploads one valid bank CSV and
one valid invoice CSV, then DepositMatch creates one draft import session for
Acme Dental and opens mapping review.
- [ ] Given Maya is viewing Acme Dental, when she uploads a PDF instead of a
CSV for either required file, then DepositMatch rejects the file before
parsing and keeps the import session in draft.
- [ ] Given Maya has uploaded both required CSV files, when the files are
accepted, then the import session records the client, file names, upload time,
and source type for each file.
## Edge Cases
- **Wrong file type**: Reject non-CSV files before parsing and identify which
file slot failed.
- **Missing second file**: Keep the import session in draft until both bank and
invoice files are present.
- **Client changed mid-upload**: Associate accepted files only with the client
selected at upload confirmation time.
## Test Scenarios
| Scenario | Input / State | Action | Expected Result |
|----------|---------------|--------|-----------------|
| Happy path | Client `Acme Dental`; files `acme-bank-2026-05-08.csv` and `acme-invoices-2026-05-08.csv` | Maya uploads both files | Draft import session is created for Acme Dental and mapping review opens |
| Wrong file type | Client `Acme Dental`; bank file `statement.pdf`; invoice file `acme-invoices-2026-05-08.csv` | Maya uploads both files | PDF is rejected before parsing; session remains draft |
| Missing invoice file | Client `Acme Dental`; bank file only | Maya uploads the bank file | Bank file is attached to draft session; mapping review does not open |
## Dependencies
- **Stories**: None.
- **Feature Spec**: FEAT-001 - CSV Import and Column Mapping.
- **Feature Requirements**: UP-01, UP-02.
- **External**: Browser file upload support; no external APIs for v1.
## Out of Scope
- Column mapping.
- Row-level validation.
- Match suggestion generation.
- Saving accepted rows into the review queue.Reference
| Activity | Frame — Define what the system should do, for whom, and how success will be measured. | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Default location | docs/helix/01-frame/user-stories/ | ||||||||||||||
| Requires | None | ||||||||||||||
| Enables | None | ||||||||||||||
| Informs | Solution Design Test Cases Tracker Issues | ||||||||||||||
| Generation prompt | Show the full generation prompt | ||||||||||||||
| Template | Show the template structure |