User Story
/ Library.
30 reusable user-story patterns for common SaaS jobs. Copy, paste, adapt. Stop reinventing the auth flow.
PM: ______
Sprint: ______
How to use this library
These patterns are starting points, not done-state stories. Every team adapts the acceptance criteria for their stack, segment, and risk tolerance. The story text usually survives copy-paste; the AC almost never does. Pull a pattern, tighten the persona, swap in your own thresholds, and discard the rest. The point is to skip the staring-at-Jira blank-cursor problem — not to outsource your judgment.
Format reminder
Acceptance criteria scaffold Given [context], when [action], then [observable outcome].
Edge case: [boundary or failure mode].
Out of scope: [what this story does not cover].
Authentication & Identity
As a prospective user, I want to sign up with my work email and a password, so that I can start a trial without leaving the marketing site.
- Given a valid email and a password meeting policy, account is created and session starts within 2 seconds.
- Given a duplicate email, show “account exists” with a one-click “sign in instead” link.
- Verification email sent within 30 seconds; unverified accounts retain access for 7 days, then prompt-only.
- Edge: email containing a plus-tag (alice+work@) is accepted.
As an enterprise user, I want to sign in with my company SSO, so that I don’t manage another password and IT controls access.
- Given an org with SAML/OIDC configured, redirect to IdP on email-domain match.
- JIT provisioning creates the user with role mapped from IdP claim.
- SSO-required orgs reject password login with a clear message; no fallback unless explicitly enabled.
- Audit log captures every SSO sign-in with IdP timestamp.
As a returning user who forgot my password, I want a self-serve reset, so that I’m not blocked from my account or forced to email support.
- Reset link valid for 30 minutes, single-use, invalidates on any successful login.
- Response is identical for valid and invalid emails (no enumeration).
- Active sessions are terminated when password changes.
As a user who hates passwords, I want to sign in with a one-time emailed link, so that I can get into the product without remembering credentials.
- Link valid for 10 minutes, single-use, scoped to the originating IP/device fingerprint or warns on mismatch.
- Rate-limited to 3 link requests per email per 10 minutes.
- Edge: clicking the link in a different browser shows a confirmation step rather than auto-signing in.
Billing & Subscription
As an admin, I want to upgrade my workspace to a higher plan inline, so that I unlock the feature I just hit a limit on without contacting sales.
- Prorated charge previewed before confirmation; new entitlements active within 60 seconds of payment.
- Upgrade can be triggered from the upsell modal that surfaced the limit.
- Receipt emailed to billing contact, not the actor, if they differ.
As an admin, I want to downgrade at the end of the billing period, so that I’m not double-charged and I see what I’ll lose before I commit.
- Pre-downgrade screen lists features lost and any data over the new plan’s limits.
- Downgrade scheduled for period-end; admin can cancel the schedule until that moment.
- Over-limit data is read-only on the new plan, not deleted.
As an admin canceling, I want to give one reason in 5 seconds, so that I’m not held hostage by a survey but the team learns why I left.
- Reason is one required radio (5–7 options) plus an optional free-text field.
- Cancellation is processed regardless of whether free-text is filled.
- Reason and free-text written to the customer record and the signal store.
As a billing contact, I want to view and download every past invoice, so that I can hand them to finance without asking support.
- Invoices listed with date, amount, status, and per-line breakdown; PDF download per row.
- Filterable by year and status; bulk download as ZIP for a given range.
- Tax fields shown when applicable to the customer’s region.
Search
As a power user, I want results to appear as I type, so that I can recognize what I want without pressing Enter.
- First results render within 150ms of keystroke; debounced at 80ms.
- Up/down arrows navigate the list; Enter opens the highlighted result.
- Empty query state shows recent + suggested entries, not a blank dropdown.
As an analyst, I want to combine multiple filters (status + owner + date), so that I can slice the dataset without exporting it.
- Filters compose with AND across fields and OR within a field; behavior visible in UI copy.
- Active filter chips are individually removable; “clear all” resets the view.
- Result count updates within 300ms of a filter change.
As a returning user, I want my last 5 searches to surface as suggestions, so that I don’t retype the same query daily.
- Recent list is per-user, last 5, ordered by recency.
- Items can be pinned (max 3) so they don’t fall off the list.
- “Clear recent” available in the dropdown footer.
Filter & Sort
As a manager, I want to filter the table by multiple fields at once, so that my saved view answers a real question, not just one dimension.
- Each filter shows the count of items it would remove before applying.
- Filters survive a page reload via URL parameters.
As a returning user, I want my last view (filters, sort, columns) to be there when I come back, so that I don’t reconfigure every Monday.
- View state stored per-user-per-table in user profile, not just localStorage.
- “Reset to default” control restores the team default view.
- Saved view is shareable via URL but does not override the recipient’s default.
As a PM, I want to sort by a computed field (e.g., score, days-open), so that I see the top of the list without exporting.
- Sort indicator visible in column header; ascending/descending toggles on click.
- Computed fields sort in the same response, not via a follow-up call.
- Tie-break by created_at desc to keep order stable across reloads.
Export & Import
As an analyst, I want to export the current view to CSV, so that I can join it with data outside the product.
- Export respects active filters, sort, and visible columns.
- Exports > 5,000 rows run async with email delivery.
- UTF-8 with BOM so Excel doesn’t mangle non-ASCII characters.
As an ops lead, I want a weekly CSV emailed to me, so that I don’t log in just to export the same view.
- Schedule supports daily, weekly (day-of-week), monthly (day-of-month).
- Schedules pause automatically after 3 consecutive delivery failures.
- Emails include a one-click unsubscribe and a manage-schedules link.
As an admin migrating from a competitor, I want to upload a CSV and map columns, so that I don’t need a custom export from their side.
- First-row preview shown; user maps each source column to a target field or “ignore”.
- Validation runs before commit; errors listed by row with downloadable error CSV.
- Idempotency key on the import prevents duplicate runs from a refresh.
Bulk Actions
As a power user, I want to select many rows quickly (shift-click, select-all, select-page), so that I can act on a set without clicking each.
- Select-all selects only the current page; explicit “select all 3,421 matching” affordance for full-set.
- Selection persists across pagination but clears on filter change.
As an admin, I want to update one field on many records at once, so that I don’t open each record for the same change.
- Confirmation shows the number of records affected and a sample of three.
- Bulk edits run async with progress visible; partial failures surface a per-row error report.
- Audit log entry per record includes the bulk operation ID for traceability.
As an admin, I want to delete many records and undo within 30 seconds, so that mistakes don’t turn into a support ticket.
- Delete is soft for 30 seconds with a toast-level “Undo” affordance.
- After the window, records move to a 30-day trash before permanent removal.
- Records with downstream dependencies (e.g., referenced by another record) prompt before deletion.
Notifications
As a user, I want to control which events ping me in-app, so that the bell isn’t a permanent red dot I’ve learned to ignore.
- Per-event-type toggle, grouped by surface (in-app / email / push).
- Defaults follow least-noise: high-signal events on, low-signal off.
- Preferences persist across devices and survive logout.
As a user, I want a daily or weekly digest of the events I missed, so that I get the signal without 14 separate emails.
- Digest sent only if there is at least one event since last digest.
- Time-of-day setting respects user’s timezone; default 8am local.
- One-click “switch to weekly” from the email footer, no auth wall.
As a mobile user, I want push notifications for high-urgency events only, so that my phone isn’t buzzing for every comment.
- Push respects in-app preferences and does not duplicate delivered email.
- Edge: device with notifications disabled at OS level surfaces an in-app reminder once per 30 days.
Permissions & Roles
As an admin, I want preset roles (owner, admin, member, viewer), so that I don’t configure permissions per-user on day one.
- Each role has a published permission matrix in-product, not just docs.
- Role changes take effect within 60 seconds across all sessions of the affected user.
As an admin on a higher plan, I want to compose custom roles, so that I can match my company’s segregation-of-duties without contorting users into preset roles.
- Custom roles are additive over a base role; conflicts resolve to least-privilege.
- A custom role with zero permissions is rejected at save with a clear message.
- Custom roles export/import as JSON for cross-environment parity.
As a compliance owner, I want a searchable audit log of admin and data-modifying actions, so that I can answer SOC 2 and incident questions without engineering.
- Every entry: actor, action, target, timestamp, IP, user agent, request ID.
- Retention ≥ 12 months; export to CSV/JSON.
- Filter by actor, action type, and date range.
Onboarding
As a brand-new user, I want a 60-second guided tour of the 3 things that matter, so that I don’t bounce trying to find the value.
- Tour has at most 5 steps; user can skip at any time without re-prompt.
- Progress is per-user and per-version; a tour update re-shows only the changed steps.
As a new user, I want to complete the “first valuable task” in under 5 minutes, so that I have a reason to come back tomorrow.
- First-task prompt is contextual to the user’s sign-up answers, not a generic checklist.
- Completion tracked as the activation event; first-task abandonment surfaces in the activation funnel.
As an experienced user, I want to skip onboarding entirely, so that I can poke around and configure later.
- “Skip” available on every onboarding step, not buried.
- Skipped users see a one-line, dismissible “Need help?” tip on the dashboard for 7 days.
Patterns to avoid
As a developer, I want to migrate the auth service to OAuth 2.1, so that we are on the new stack.
Why it’s broken: the user is the developer, the value is internal, the outcome is a tech artifact. This is an engineering ticket, not a user story. Rewrite as the customer-facing capability the migration unlocks — or accept it’s a tech-debt ticket and stop pretending.
As a PM, I want the API team to expose a new endpoint, so that I can build the dashboard.
Why it’s broken: the persona is internal, the “outcome” is another team’s output, and there’s no end-user value. File the dependency as a coordination ticket; write the actual user story for the dashboard the customer will see.
As an admin, I want everything I need to manage my workspace, so that I can do my job.
Why it’s broken: no testable outcome, no boundaries, no acceptance criteria possible. Mega-stories live in the backlog forever because they can never be “done.” Split into the smallest verifiable jobs (invite a user, change a role, remove a user) and write each.