User Stories
User Stories: Bilko{{PROJECT_NAME}}
Project:
Bilko — Balkan Accounting SaaS{{PROJECT_NAME}} Version:1.0{{VERSION}} Date:2026-02-25{{DATE}} Author:John (AI Director){{AUTHOR}} Status:FinalDraft | In Review | Approved Reviewers:Alem Bašić (CEO){{REVIEWERS}}
Document History
| Version | Date | Author | Changes |
|---|---|---|---|
| 0.1 | Initial draft | ||
1. Epic Overview
| Epic ID | Epic Name | Business Goal | Story Count | Status | Target Release |
|---|---|---|---|---|---|
| EP-01 | Backlog / In Progress | ||||
| EP-02 | |||||
| EP-03 | |||||
2. Epic SummariesTemplates
EpicEpic: EP-01 — Authentication{{EPIC_NAME}}
Epic Statement:
As ana SMB owner{{PERSONA}}, I need to securely register, log in, and manage my team's access{{CAPABILITY}} so that only authorized people can view and modify my financial data{{BUSINESS_VALUE}}.
Business Goal: BR-014 (secure multi-tenancy), BR-007 (RBAC){{BUSINESS_OBJECTIVE_REFERENCE}}
Priority: Must Have | Should Have | Could Have
Estimated Size: {{X}} story points (rough)
Target Sprint:Sprint(s): Sprint 1{{X}} – Sprint {{Y}}
Acceptance Criteria at Epic Level:
-
User can register, verify email, and log in{{HIGH_LEVEL_CRITERION_1}} -
Organization is created on registration with Serbian Chart of Accounts pre-populated{{HIGH_LEVEL_CRITERION_2}} -
Owner can invite accountant with Accountant role; accountant has full financial access but cannot manage billing{{HIGH_LEVEL_CRITERION_3}}
Epic EP-02 — Invoicing + SEF E-Invoicing
EpicStories Statement:in This Epic:
As a Serbian business owner, I need to create invoices and submit them to SEF automatically so that I am compliant with the 2023 mandatory e-invoicing law without using the SEF portal manually.
Business
Goal:
Epic EP-03 — Expense Tracking
Epic Statement:
As a business owner, I need to record business expenses with categories and receipts so that my P&L is accurate and I have documentation for tax purposes.
Business Goal: BR-009
Priority: Must Have | Target Sprint: Sprint 2
3. Story Format Guide
Standard Story Format:
As a [persona/role],
I want [feature/action],
So that [benefit/outcome].
Acceptance Criteria Format (Given/When/Then):
Given [a precondition that must be true],
When [the user performs an action],
Then [the expected outcome occurs].
Key Principles:
- Stories describe WHAT the user needs, not HOW to build it
- Each story must be independently valuable and testable
- Stories should be completable within a single sprint
- If a story takes > 8 story points, break it into smaller stories
- Acceptance criteria should be written as tests (they become test cases)
4. Story Backlog
Epic EP-01: Authentication & Organization Setup{{EPIC_NAME}}
US-001: Register and Create Organization{{STORY_TITLE}}
| Attribute | Value |
|---|---|
| Epic | EP-01: |
| Priority | Must Have |
| Story Points | |
| Sprint | |
| Assigned To | |
| Status | Backlog |
| FR Reference | FR- |
| BR Reference | BR- |
Story:
As a new Bilko user{{PERSONA}},
I want to register with my email and create my first organization{{ACTION/FEATURE}},
So that I can start managing my business finances immediately after signing up{{BENEFIT/OUTCOME}}.
Context:
On registration, a default Organization is automatically created named after the user's business (or their name if not provided). Serbian Chart of Accounts (Kontni Okvir 2021) is pre-populated. The user becomes the Owner of this organization.{{ADDITIONAL_CONTEXT_THAT_HELPS_UNDERSTAND_THE_STORY}}
Acceptance Criteria:
- Given
a valid email and strong password,{{PRECONDITION}}, whenuser submits registration form with full name and organization name,{{USER_ACTION}}, thenaccount + organization created; verification email sent within 2 minutes{{EXPECTED_RESULT}} - Given
user clicks verification link (valid for 48h){{PRECONDITION}}, whenlink is valid,{{USER_ACTION}}, thenemail confirmed; user redirected to dashboard of their new organization{{EXPECTED_RESULT}} - Given
duplicate email submitted,{{ERROR_CONDITION}}, whenuser registers,{{USER_ACTION}}, thenerror "An account with this email already exists" shown; no new account created Givenorganization created,whenuser first views Chart of Accounts,thenall standard Serbian Kontni Okvir accounts (Classes 0-9) are present{{ERROR_HANDLING}}
Technical Notes:
Organization seeding: callseedChartOfAccounts(organizationId, 'RS')on org creationJWT: access token 15min TTL, refresh token 30d rolling{{TECHNICAL_CONSTRAINT_OR_HINT}}
UI/UX Notes:
Screen:Screen/auth/register+component:email verification page{{SCREEN_NAME}}Responsive:Designfull-screenreference:centered{{FIGMA_LINK_OR_FILE}}- Responsive
onbehavior:mobile + desktop{{NOTES}}
Dependencies:
- Blocked by:
None{{US-XXX | None}} - Blocks: {{US-
003XXX | None}} - External: {{THIRD_PARTY_DEPENDENCY | None}}
Definition of Done:
- Code complete and follows coding standards
- Unit tests written (
invite≥users),80%US-010coverage on new code) - Code review approved by Tech Lead
- Merged to
develop - Deployed to staging
- All acceptance criteria manually verified
- No critical or high bugs open
- Documentation updated (
createifinvoice)applicable)
US-002: Login with JWT{{STORY_TITLE}}
| Attribute | Value |
|---|---|
| Epic | EP-01 |
| Priority | Must Have |
| Story Points | |
| Sprint | |
| Assigned To | |
| Status | Backlog |
| FR Reference | FR- |
Story:
As a registered Bilko user{{PERSONA}},
I want to log in securely and have my session persist for a reasonable time{{ACTION}},
So that I don't have to re-authenticate every time I open the app{{BENEFIT}}.
Acceptance Criteria:
- Given
valid credentials,{{PRECONDITION}}, whenuser submits login form,{{USER_ACTION}}, thenauthenticated; access + refresh tokens set; redirected to last-used organization dashboard{{EXPECTED_RESULT}} - Given
invalid credentials,whenuser submits,thengeneric error "Pogrešan email ili lozinka" (Serbian) shown; no user enumeration Given5 failed attempts within 15 minutes,whenanother attempt made,thenerror "Nalog je privremeno zaključan. Pokušajte za 15 minuta."Givenaccess token expires (15min idle){{PRECONDITION}}, whenuser makes API call,{{USER_ACTION}}, thenrefresh token used to silently issue new access token; user not logged out{{EXPECTED_RESULT}}
Dependencies: Blocked by: {{US-001
|
US-003: Invite Accountant to Organization
Story:
As an organization Owner,
I want to invite my accountant to access my organization with appropriate permissions,
So that my accountant can manage my books without being able to change billing or delete the organization.None}}
AcceptanceDefinition Criteria:
GivenDone:owner(sameisasinstandardSettingsDoD> Team,whenthey enter [email protected] and select Accountant role,theninvitation email sent with 48h-valid accept linkGiveninvited user accepts and is already registered,whenlink clicked,thenadded to organization with Accountant role; no new registration requiredGiveninvited user is new,whenlink clicked,thenregistration flow with role pre-assignedGivenAccountant logs in,whenthey navigate to organization,thenfull financial access; billing and org-deletion options hidden
Dependencies: Blocked by: US-001
US-004: Switch Between Organizations
Story:
As an accountant managing multiple client organizations,
I want to switch between my clients' organizations without logging out,
So that I can efficiently manage multiple clients from one session.
Acceptance Criteria:
Givenuser belongs to 3 organizations,whenthey click the org switcher in the sidebar,thenall 3 organizations shown with current one highlightedGivenuser selects a different organization,whenswitched,thenall data (invoices, expenses, reports) immediately reflects the new organization; URL updates to reflect active org
Dependencies: Blocked by: US-001, US-003above)
Epic EP-02: Invoicing + SEF E-Invoicing{{EPIC_NAME}}
US-010: Create Invoice with PDV Auto-Calculation
Story:
As a Serbian business owner,
I want to create an invoice with automatic PDV calculation,
So that I don't have to manually calculate PDV and risk incorrect tax amounts.
Context:
Serbia uses PDV (Porez na dodatu vrednost) — equivalent to VAT. Standard rate 20%, reduced rate 10%. Bilko must auto-calculate and display both the base amount and PDV amount per line item, and total PDV payable.
Acceptance Criteria:
Givenauthenticated user,whenthey open the invoice creation wizard and complete all 6 steps,theninvoice saved as Draft with correct PDV (20% standard or 10% reduced per item)Givenline item with unit_price 1000 RSD and PDV rate 20%,whenuser views invoice,thenPDV = 200.0000 RSD, total = 1200.0000 RSD (NUMERIC precision)Giveninvoice with 3 line items at different PDV rates,wheninvoice created,thenPDV breakdown shown per rate; total PDV is sum of all line-item PDVGiveninvoice saved as Draft,whenuser edits a line item quantity,thenPDV and totals immediately recalculate
Technical Notes:
All amounts: NUMERIC(19,4) — Prisma Decimal typePDV calculation:pdv_amount = ROUND(base_amount * pdv_rate, 4)— server-side only
UI/UX Notes:
Screen:/invoices/create— 6-step wizardStep 3: line items with inline PDV calculationStep 5: invoice preview with all amounts
Dependencies:
Blocked by: US-001 (auth)Blocks: US-011 (SEF submission)
US-011: Submit Invoice to SEF (Serbia){{STORY_TITLE}}
| Attribute | Value |
|---|---|
| Epic | EP-02 |
| Priority | |
| Story Points | |
| Sprint | |
| Assigned To | |
| Status | Backlog |
Story:
As a Serbian B2B business owner{{PERSONA}},
I want Bilko to automatically submit my invoice to SEF when I send it{{ACTION}},
So that I am compliant with Serbia's mandatory e-invoicing law without using the SEF portal.
Context:
Since 2023, all B2B invoices in Serbia must be submitted to SEF (efaktura.gov.rs). UBL 2.1 XML format required. SEF assigns an invoice ID and returns acceptance/rejection status.
Acceptance Criteria:
Givenuser clicks "Send Invoice" on a Serbian B2B invoice,whensend action executes,thenUBL 2.1 XML generated and submitted to SEF within 10 secondsGivenSEF accepts,whenresponse received,theninvoice SEF status = "Accepted"; SEF invoice ID stored; user notified in UIGivenSEF rejects,whenrejection received,thenuser sees rejection reason in Serbian; invoice status = "SEF Rejected"; user can correct and resubmitGivenSEF API returns 503,whensubmission attempted,thenqueued for retry; user informed "Faktura će biti prosleđena SEF-u u roku od 30 minuta"; max 3 retries with exponential backoff
Technical Notes:
SefService: abstract all SEF calls behindapps/api/src/services/sef.service.tsSEF credentials: per-organization, stored encrypted in DB
Dependencies: Blocked by: US-010
US-012: Track Invoice Payment
Story:
As a business owner,
I want to mark invoices as paid and track overdue invoices,
So that I know which clients have paid and which need follow-up{{BENEFIT}}.
Acceptance Criteria:
- Given
invoice is Sent,{{PRECONDITION}}, whenuser marks as Paid with payment date,{{USER_ACTION}}, thenstatus = Paid; double-entry transaction created (Debit bank, Credit accounts receivable) Giveninvoice due_date has passed and invoice is still Sent,whensystem runs daily check,thenstatus = Overdue; user notified via in-app notificationGiveninvoice list,whenuser filters by Overdue,thenonly overdue invoices shown{{EXPECTED_RESULT}}
Dependencies: Blocked by: US-010
Epic EP-03: Expense Tracking
US-020: Record Business Expense
Story:
As a business owner or accountant,
I want to record a business expense with category and receipt,
So that my expenses are tracked for P&L accuracy and tax documentation.None
Acceptance Criteria:
Givenvalid expense data (vendor, amount, category, date),whensubmitted,thenexpense saved; double-entry transaction created (Debit expense account, Credit payment account)Givenexpense in EUR with org base currency RSD,whencreated,thenEUR amount stored + RSD equivalent calculated at locked exchange rateGivenJPEG receipt (≤10MB) attached,whenexpense saved,thenreceipt stored and accessible from expense recordGivenexpense list,whenfiltered by category "Putni troškovi",thenonly matching expenses shown
Dependencies: Blocked by: US-001
Epic EP-04: Double-Entry Bookkeeping
US-030: View and Navigate ChartDefinition of Accounts
Story:Done: As an accountant,
I want to view the pre-populated Serbian Chart of Accounts and add custom sub-accounts,
So that I can organize transactions per Balkan GAAP standards and my client's specific needs.
Acceptance Criteria:
Givennew Serbian org,whenaccountant opens/settings/accounts,thenall 10 account classes(0-9) with Serbianstandardaccounts shown in hierarchical treeGivenaccountant adds sub-account "4111 — Dobavljači u zemlji" under class 411,whensaved,thenappears in account tree and is selectable in manual journal entriesGivenaccount has posted transactions,whenuser attempts to delete it,thendeletion blocked; message explains account has transactions
Dependencies: Blocked by: US-001
US-031: View General Ledger (Knjiga)
Story:
As an accountant,
I want to view all journal entries (knjiženja) in the general ledger,
So that I can verify every debit/credit entry is correctly recorded.
Acceptance Criteria:
Givenauthenticated accountant,whenopening journal ledger,thenall transactions shown with date, description, debit account, credit account, amountGivenjournal entry,whenexpanded,thenshows audit log (LoggedAction) of who created it and whenGivenany filter period,whensum of all debits calculated,thenexactly equals sum of all credits (invariant display)
Dependencies: Blocked by: US-020, US-010
Epic EP-05: Bank Reconciliation
US-040: Import Bank Statement CSV
Story:
As a business owner or accountant,
I want to import my Serbian bank statement as a CSV file,
So that I can reconcile bank transactions with invoices and expenses without manual entry.
Acceptance Criteria:
Givenvalid Serbian bank CSV (Raiffeisen format),whenuploaded,thenall transactions parsed and listed for review with amount, date, descriptionGivenbank transaction of 1200 RSD on 2026-03-05 matches an open invoice for 1200 RSD due on 2026-03-04,whenparsed,thenmatch suggested with 90% confidenceGivenunmatched transaction,whenuser categorizes manually (e.g., "Kirija — account 480"),thendouble-entry transaction created
Dependencies: Blocked by: US-010
Epic EP-06: VAT/PDV Management
US-050: Generate Monthly PDV Report
Story:
As a Serbian business owner or accountant,
I want to generate the monthly PDV report in one click,
So that I can file PDV with Poreska Uprava by the 15th without spending hours on calculations.
Context:
Serbian VAT (PDV) is filed monthly by the 15th. The report must show: output PDV (on sales), input PDV (on purchases), and net PDV payable/refundable. Must export in format compatible with ePorezi portal.
Acceptance Criteria:
GivenJanuary 2026 selected,whenPDV report generated,thenall January invoices and expenses with PDV correctly aggregated; output PDV, input PDV, and net position shownGivenstandard PDV period,whenexport as PDF clicked,thenPDF generated with all required fields per Poreska Uprava formatGivenzero PDV period (no PDV transactions),whenreport generated,thenzero-value report generated (still legally required)Givenreminder setting enabled,when14th of month arrives,thenin-app notification "PDV rok sutra — generiši izveštaj"
Dependencies: Blocked by: US-010, US-020, US-040
Epic EP-07: Financial Reports
US-060: View Profit & Loss Statement
Story:
As a business owner,
I want to see my Profit & Loss statement for any period,
So that I can understand if my business is profitable without waiting for my accountant's monthly report.
Acceptance Criteria:
Givenany date range (e.g., Q1 2026),whenP&L generated,thenall revenue accounts summed, all expense accounts summed, net profit calculated; matches double-entry ledger totalsGivenmulti-currency org,whenP&L generated in RSD,thenall EUR/BAM transactions converted using locked historical exchange rates; totals in RSDGivenP&L viewed,whenuser clicks on a revenue line,thendrill-down shows individual transactions contributing to that amount
Dependencies: Blocked by: US-010, US-020
US-061: View Balance Sheet
Story:
As an accountant,
I want to view the Balance Sheet for any date,
So that I can verify the accounting is correct and prepare the annual financial statements.
Acceptance Criteria:
Givenany date (e.g., 2026-03-31),whenBalance Sheet generated,thenTotal Assets = Total Liabilities + Total Equity (double-entry invariant)Givenany imbalance detected (should never happen),whenBalance Sheet calculated,thenalert shown to accountant and John notified via monitoring
Dependencies: Blocked by: US-030, US-031
Epic EP-08: Multi-Currency
US-070: Create Invoice in Foreign Currency
Story:
As a Serbian exporter invoicing European clients,
I want to create invoices in EUR with automatic RSD conversion,
So that my financial reports are accurate in my base currency and I comply with exchange rate locking requirements.
Acceptance Criteria:
Giveninvoice created in EUR with 1 EUR = 117.5 RSD on 2026-03-01,wheninvoice saved,thenEUR amount and 117.5 RSD rate locked; cannot be edited retroactivelyGivenpayment received 1 month later,whenmarked paid,thenoriginal locked rate used for P&L; exchange gain/loss calculated if payment at different rateGivenECB rate API unavailable,whenuser creates EUR invoice,thenprompted to enter exchange rate manually; rate stored with "manual" flag
Dependencies: Blocked by: US-010DoD)
5. Story Estimation Guide
| Points | Complexity | |
|---|---|---|
| 1 | Trivial | Update |
| 2 | Simple | |
| 3 | Moderate | |
| 5 | Complex | |
| 8 | Very Complex | |
| 13+ | Too Large | Break into |
Planning Poker: Use async estimation — each team member estimates independently, then compare and discuss outliers.
6. Definition of Ready Checklist
Before a story can enterbe added to a sprint:sprint, verify:
- Story is written in As a / I want / So that format
-
AtStory has at least 2 acceptance criteria in Given/When/Then format -
EstimatedStory has been estimated in story points - Dependencies are identified and not blocking
-
FRUI/UXreferencedesigndocumentedexists (or story is backend-only) -
AccountingTechnicallogicapproachverifiedis understood (fornofinancialmajorstories:unknowns) -
PDV,PrioritySEF)is assigned (MoSCoW) - Story size is ≤ 8 points (or confirmed as a spike)
- Acceptance criteria are testable by QA
- FR reference documented
7. Story Breakdown Techniques
| Technique | When to Use | How |
|---|---|---|
| CRUD Split | Create/Read/Update/Delete are all in one story | Split into 4 stories (View, Create, Edit, Delete) |
| Happy Path First | Story handles many edge cases | First story = happy path only; subsequent stories = edge cases |
| Data Variations | Story handles many data types | Split by data type or category |
| Workflow Steps | Multi-step process in one story | Split by step (Step 1 as standalone value, etc.) |
| User Type Split | Different users, different experiences | One story per user type |
| Performance Deferred | Core function + performance optimization mixed | Functional story first; performance story second |
| UI + API Split | Full-stack story too large | API story first; UI story depends on API story |
8. Story Mapping Visualization
USER JOURNEY: [Register]Discovery] → [Create Invoice]Registration] → [SubmitCore to SEF]Feature] → [Track Payment]Management] → [MonthlyReporting]
PDV] → [P&L Report]
Phase 1 MVP:MVP US-001 US-010020 US-011030 US-012040 —
(Release 1)
Release 2 — US-021 US-031 US-041 US-050
US-060Release US-002 US-020 (Expense) US-040 (Bank)
Phase 2: US-003 Croatian eRačun3 — HR— VATUS-032 AnalyticsUS-042 (multi-org) eRačun invoice auto-submitUS-051
Replace with actual story IDs mapped to user journey steps and release priority
8.9. Backlog Summary
| Epic | Total Stories | Estimated Points | In Sprint | Done | Remaining |
|---|---|---|---|---|---|
| EP-01: |
|||||
| EP-02: |
|||||
| Total |
Velocity target:(last sprint): 20 story points/sprint{{STORY_POINTS_COMPLETED}}
Projected completion: Sprint 4{{X}} (8 weeks from 2026-02-23){{DATE}})
Approval
| Role | Name | Date | Signature |
|---|---|---|---|
| Author | |||
| Reviewer | |||
| Business Analyst | |||
| Product Owner | |||
| AI Director (John) | |||