# Business Requirements

Business requirements documentation for Bilko — BRD, functional requirements, user stories, acceptance criteria, and RTM.

# Business Requirements Document (BRD)

# Business Requirements Document (BRD): Bilko

> **Project:** Bilko — Balkan Accounting SaaS
> **Version:** 0.1
> **Date:** 2026-02-23
> **Author:** John (AI Director)
> **Status:** Draft
> **Reviewers:** Alem Bašić (CEO)

## Document History
| Version | Date | Author | Changes |
|---------|------|--------|---------|
| 0.1     | 2026-02-23 | John (AI Director) | Initial draft — Phase 1 Serbia focus |

---

## 1. Executive Summary

**Project Overview:**
Bilko is a cloud SaaS accounting platform for Balkan SMBs — the first modern, cloud-native tool purpose-built for Serbian, Bosnian, and Croatian small businesses with full local tax compliance, native language support, and affordable pricing. Phase 1 targets Serbia (300K+ active SMBs) where e-invoicing via SEF has been mandatory since 2023.

**Business Problem:**
348,000+ Balkan SMBs have no affordable, modern, cloud-native accounting tool with full local regulatory compliance — they are forced to choose between over-engineered ERP software (Pantheon, Minimax at €150+/month), global tools with no Balkan compliance (QuickBooks/Xero), or manual spreadsheets that violate SEF e-invoicing law.

**Proposed Solution:**
Bilko — a Fiken-inspired SaaS at €8-25/month with SEF e-invoicing, PDV auto-calculation, double-entry bookkeeping, bank reconciliation, and financial reports in Serbian/Bosnian/Croatian.

**Expected Outcomes:**
- 100 paying organizations within 90 days of Serbia launch
- €500 MRR by end of Month 3 post-launch
- 80% activation rate (users create their first invoice within 7 days)
- Full SEF compliance for all invoices submitted through Bilko

**Investment:** €11,000–17,000 EUR | **Timeline:** ~10 weeks to Serbia launch | **Priority:** High — CEO GO decision 2026-02-20

---

## 2. Business Objectives & Goals

| ID | Objective | Description | Target | Timeframe |
|----|-----------|-------------|--------|-----------|
| BO-01 | Launch compliant Serbia product | Deliver a fully SEF-compliant invoicing and accounting platform for Serbian SMBs | Production launch with 0 critical compliance bugs | 2026-05-01 |
| BO-02 | Acquire first paying customers | Onboard 100 paying organizations in Serbia within 90 days of launch | 100 orgs × avg €15/month | By 2026-08-01 |
| BO-03 | Achieve product-market fit signals | Reach NPS > 50 and < 5% monthly churn among early adopters | NPS ≥ 50, churn ≤ 5%/month | 60 days post-launch |
| BO-04 | Establish Balkan market position | Launch Croatia by Q4 2026, establish Bilko as the leading Balkan cloud accounting brand | Croatia beta by 2026-10-01 | 2026-10-01 |
| BO-05 | Generate ARR for ALAI | Bilko becomes a revenue pillar for ALAI Holding, reducing consulting dependency | €50K ARR by 2026-12-31 | 2026-12-31 |

**Alignment to Strategic Goals:**
- **ALAI product portfolio:** Bilko is ALAI's first B2B SaaS product — validates the product-building capability and creates recurring revenue
- **Balkan market expansion:** Bilko establishes ALAI's brand and infrastructure in Serbia, Croatia, and BiH for future products

---

## 3. Current State Analysis (AS-IS)

### 3.1 Current Process Overview

A typical Serbian SMB owner currently manages accounting through one of three workflows:
1. **Pantheon/Minimax desktop software** — installed locally, managed by an accountant, significant monthly cost (€100-200+), complex interface
2. **Manual spreadsheet + paper invoices** — technically illegal post-2023 SEF mandate; exposes business to fines
3. **Outsourced accountant only** — accountant submits SEF invoices manually; owner has no real-time visibility into finances

None of these provide: (a) real-time cloud access, (b) affordable self-service, or (c) simple enough UX for non-accountants.

### 3.2 AS-IS Process Flow

```mermaid
flowchart LR
    A([SMB Owner]) --> B[Create invoice in Excel/Word]
    B --> C{SEF registered?}
    C -->|Yes| D[Export to SEF format manually]
    C -->|No| E[Send paper/PDF invoice — non-compliant]
    D --> F[Submit to efaktura.gov.rs portal]
    E --> G[Risk of fine: up to 500K RSD]
    F --> H[Track payment manually in spreadsheet]
    H --> I[Send data to accountant monthly]
    I --> J[Accountant reconciles, prepares PDV report]
    J --> K[Submit PDV to Poreska Uprava — 15th of month]
```

### 3.3 Current Systems & Tools

| System / Tool | Purpose | Users | Limitations |
|--------------|---------|-------|-------------|
| Pantheon ERP | Full accounting + SEF | Mid-market SMBs | Complex UI, high cost (~€150+/month), desktop-only |
| Minimax | Accounting + invoicing | Accountants managing multiple clients | Older architecture, no mobile, limited cloud |
| efaktura.gov.rs portal | SEF e-invoice submission | All businesses (manual) | Manual only, no API for small software |
| Excel / Google Sheets | Expense tracking, reconciliation | Micro-businesses | Non-compliant, error-prone, no audit trail |
| Paper invoices | B2C / informal invoicing | Retail / services | Illegal for B2B from 2023 |

### 3.4 Current State Pain Points

| # | Pain Point | Category | Affected Users | Business Impact | Severity |
|---|-----------|----------|---------------|-----------------|----------|
| PP-01 | SEF compliance is time-consuming without dedicated software | Process | All B2B SMBs in Serbia | 1-2 hours per invoice in manual workflow; fine risk | High |
| PP-02 | Existing solutions (Pantheon) cost as much as a part-time salary | Technology | Budget-constrained SMBs | 80% of SMBs cannot justify >€50/month | High |
| PP-03 | No local language + local compliance in affordable tools | Technology | Non-English speakers | QuickBooks/Xero require English + have no SEF | High |
| PP-04 | Accountants cannot manage multiple clients from one platform | Process | Bookkeepers | 2-3 hours/client/month in manual reconciliation | Medium |
| PP-05 | No real-time financial visibility for business owners | Data | SMB owners | Decisions made on stale monthly reports | Medium |
| PP-06 | Multi-currency transactions (BAM, EUR, RSD) managed manually | Data | Import/export businesses | Exchange rate errors in VAT calculations | Medium |

### 3.5 Current State Metrics (Baseline)

| Metric | Current Value | Source | Notes |
|--------|-------------|--------|-------|
| Time to create + submit SEF invoice (manual) | 45-90 minutes | User research | Includes portal navigation |
| Time to create + submit SEF invoice (Bilko target) | < 5 minutes | Product target | Wizard + auto-submit |
| Monthly software cost for compliant accounting | €100-200+ (Pantheon) | Market research | For Serbian SMB |
| Bilko target price | €8-25/month | Pricing model | 4-20× cheaper than incumbents |
| SMBs currently non-compliant with SEF | ~60% of eligible | APR estimates | Regulatory enforcement risk |

---

## 4. Future State Vision (TO-BE)

### 4.1 Future State Description

With Bilko, a Serbian SMB owner opens their browser, creates a compliant e-invoice in under 5 minutes (including line items, PDV, multi-currency), and submits it directly to SEF without touching the government portal. Expenses are categorized automatically. Bank statements are imported via CSV and matched to transactions. At month end, the PDV report is generated in one click and exported in the format required by Poreska Uprava. The owner has real-time P&L, cash flow, and balance sheet visibility from any device.

### 4.2 TO-BE Process Flow

```mermaid
flowchart LR
    A([SMB Owner]) --> B[Open Bilko — Create Invoice]
    B --> C[Select client, add items, auto-PDV]
    C --> D[One-click: Email PDF + submit to SEF]
    D --> E[SEF confirms — status updated in Bilko]
    E --> F[Invoice marked Sent/Paid automatically]
    F --> G[Double-entry transaction auto-created]
    G --> H[Dashboard updates P&L + cash flow]
    H --> I[Month end: 1-click PDV report export]
    I --> J([Owner files PDV in < 10 minutes])
```

### 4.3 Key Improvements

| Area | AS-IS | TO-BE | Improvement |
|------|-------|-------|-------------|
| Time to create + submit SEF invoice | 45-90 min | < 5 min | 90% time reduction |
| Monthly accounting software cost | €100-200+ | €8-25 | 4-20× cheaper |
| Real-time financial visibility | Monthly (accountant) | Instant | Continuous |
| SEF compliance rate | ~40% (market average) | 100% for Bilko users | Compliance guaranteed |
| PDV report preparation | 2-4 hours/month | < 10 minutes | 95% time reduction |

---

## 5. Market Analysis & Competitive Landscape

### 5.1 Market Context

The Balkan region has 348,000+ active SMBs across Serbia (300K+), Croatia (140K+), and Bosnia-Herzegovina (~80K VAT-registered). The 2023 Serbian SEF mandate and January 2026 Croatian eRačun mandate create regulatory forcing functions that are driving digital adoption at a pace not seen since SEPA in Western Europe. The €50-150M TAM is currently served by legacy ERP vendors (Pantheon, Minimax) who have not modernized their UX or pricing to match the SMB segment.

### 5.2 Competitive Analysis

| Competitor | Solution Type | Key Features | Pricing | Our Advantage |
|-----------|--------------|-------------|---------|---------------|
| Pantheon | ERP (direct) | Full accounting, SEF, inventory, payroll | €150-300+/month | Bilko is 6-20× cheaper; Fiken-simple UX; cloud-native |
| Minimax | Accounting SaaS (direct) | Invoicing, accounting, SEF support | €50-100/month | Bilko has better UX; lower price; modern stack |
| QuickBooks | Global SaaS (indirect) | Full accounting, mobile, 700+ integrations | €30-50/month | Bilko has SEF/eRačun; local language; local currency |
| Xero | Global SaaS (indirect) | Full accounting, bank feeds, multi-currency | €35-55/month | Bilko has Balkan compliance; cheaper for basic use |
| Manual + Excel | Substitute (indirect) | Free | Free | Bilko is affordable + compliant; fines avoided |

### 5.3 Positioning

**Unique Value Proposition:** The only cloud accounting software built for Balkan SMBs — with local language, local tax compliance (SEF, eRačun, PDV), and Fiken-level UX simplicity at €8-25/month.
**Target Market:** Serbian SMBs (Phase 1) → Croatian SMBs (Phase 2) → BiH SMBs (Phase 3)
**Differentiators:** Local compliance out-of-the-box · Native languages · Affordable SaaS model · Modern cloud UX · Double-entry with Balkan Chart of Accounts

---

## 6. Stakeholder Needs Analysis

| Stakeholder Group | Primary Needs | Secondary Needs | Pain Points Addressed | Priority |
|------------------|--------------|----------------|----------------------|----------|
| SMB Owner (non-accountant) | Create SEF invoices fast; see P&L; file PDV easily | Mobile access; expense receipts; client management | PP-01, PP-02, PP-03, PP-05 | High |
| Bookkeeper / Accountant | Manage multiple client orgs; export VAT reports; double-entry accuracy | Client collaboration tools; bulk operations | PP-04, PP-05 | High |
| Import/export business | Multi-currency invoices (EUR, BAM, RSD); exchange rate locking | Currency reports; consolidated P&L in base currency | PP-06 | Medium |
| Tech-savvy early adopter | REST API; webhook notifications; data export | CSV/JSON export; OAuth integration | — | Low |

---

## 7. Business Requirements

| ID | Requirement | Description | Priority | Rationale | Source | BO Reference |
|----|------------|-------------|----------|-----------|--------|-------------|
| BR-001 | SEF e-invoice submission | System must create, sign, and submit e-invoices to efaktura.gov.rs (SEF) in UBL 2.1 format | Must Have | Serbia launch blocker; legal requirement since 2023 | Regulatory research + APR | BO-01 |
| BR-002 | PDV auto-calculation (Serbia) | System auto-calculates 20% standard and 10% reduced PDV on all invoice line items | Must Have | Core tax compliance; manual calculation error-prone | Regulatory research | BO-01 |
| BR-003 | Double-entry bookkeeping | Every financial event generates a balanced debit + credit entry per Balkan GAAP standards | Must Have | Required for legal compliance and Balance Sheet accuracy | Accounting law | BO-01 |
| BR-004 | Multi-currency support | System handles BAM, RSD, EUR, USD with exchange rate locking at transaction date | Must Have | Balkan businesses transact in multiple currencies | User research | BO-01, BO-02 |
| BR-005 | Bank statement import | System accepts CSV uploads from Serbian banks for transaction reconciliation | Must Have | Live bank API not available in Phase 1; manual reconciliation is blocking pain | User research | BO-02 |
| BR-006 | Financial reports | System generates P&L, Balance Sheet, Cash Flow Statement, and VAT/PDV report | Must Have | Required for business owners and accountants; PDV report needed for monthly filing | User research | BO-03 |
| BR-007 | Multi-user collaboration with RBAC | Organizations can invite multiple users with roles: Owner, Admin, Accountant, Viewer | Must Have | Accountants need access to client orgs; business owners need to control what accountants see | User research | BO-02, BO-03 |
| BR-008 | PDF invoice generation + email delivery | System generates professional PDF invoices with Bilko/client branding and delivers via email | Must Have | Standard B2B invoicing requirement | User research | BO-02 |
| BR-009 | Expense tracking | System records expenses with category, amount, payment method, and receipt photo | Must Have | Core accounting requirement; feeds P&L and cash flow | User research | BO-02 |
| BR-010 | Chart of Accounts (Balkan GAAP) | System provides pre-populated Serbian/Balkan Chart of Accounts per Pravilnik 2021 | Must Have | Required for legal compliance and proper financial reporting | Regulatory research | BO-01 |
| BR-011 | Serbian language support | All UI, invoices, and reports available in Serbian (Latin and Cyrillic) | Must Have | Target market speaks Serbian; global tools fail here | User research | BO-02 |
| BR-012 | Immutable audit trail | System logs all financial actions with user, timestamp, before/after values; append-only | Must Have | Required by Serbian accounting law; non-negotiable | Regulatory research | BO-01 |
| BR-013 | Data export (GDPR-aligned) | Users can export all their organization's data in machine-readable format | Must Have | GDPR Article 20 portability; user trust | Legal | BO-01 |
| BR-014 | Secure multi-tenancy | Each organization's data is completely isolated; no cross-tenant data access | Must Have | Financial data confidentiality; SaaS security baseline | Security | BO-01 |
| BR-015 | Croatian eRačun integration | System submits e-invoices to HR-FISK (FINA) in Croatian format | Should Have | Croatia Phase 2; eRačun mandatory Jan 2026 | Regulatory research | BO-04 |
| BR-016 | Bosnian/Croatian language support | Full UI and invoice support in Bosnian and Croatian | Should Have | Phase 2 expansion markets | User research | BO-04 |
| BR-017 | AI-assisted bookkeeping | System suggests expense categories and transaction classifications | Could Have | Reduces manual entry; competitive differentiator | Market research | BO-05 |
| BR-018 | Payroll management | Track employee salaries, generate payroll documents | Won't Have (Phase 1) | Complexity high; Phase 2 feature | Strategic decision | — |

---

## 8. Success Metrics & KPIs

| ID | KPI | Category | Baseline | Target | Measurement Method | Evaluation Date | Owner |
|----|-----|----------|----------|--------|--------------------|-----------------|-------|
| KPI-01 | Paying organizations | Revenue | 0 | 100 orgs by Day 90 | Billing system | 90 days post-launch | John |
| KPI-02 | Monthly Recurring Revenue | Revenue | €0 | €500 MRR by Month 3 | Billing system | 3 months post-launch | Alem |
| KPI-03 | Activation rate | Adoption | 0% | ≥ 80% create invoice in 7 days | Analytics | Monthly | John |
| KPI-04 | Monthly churn | Retention | N/A | ≤ 5%/month | Billing system | Monthly | John |
| KPI-05 | NPS score | Satisfaction | N/A | ≥ 50 | In-app survey | 60 days post-launch | John |
| KPI-06 | SEF submission success rate | Compliance | N/A | 100% | SEF API response logs | Launch day + ongoing | John |
| KPI-07 | System uptime | Reliability | N/A | ≥ 99.9% monthly | Monitoring | Ongoing | John |
| KPI-08 | Page load time (subsequent) | Performance | N/A | < 1 second p95 | Lighthouse + monitoring | Launch + 30 days | John |
| KPI-09 | Time to create first invoice | UX | 45-90 min (incumbent) | < 5 minutes in Bilko | In-app analytics | Post-launch | John |

---

## 9. Business Rules & Constraints

### 9.1 Business Rules

| ID | Rule | Category | Source | Enforced By |
|----|------|----------|--------|-------------|
| RUL-01 | All monetary amounts stored as NUMERIC(19,4) — NEVER float | Financial | Internal engineering standard | Database schema + Prisma |
| RUL-02 | Every financial transaction must generate balanced debit + credit entries | Financial | Serbian Accounting Law | Application layer + DB constraint |
| RUL-03 | Exchange rate locked at transaction date — cannot be edited retroactively | Financial | Accounting standards (IFRS) | Database immutability + LoggedAction |
| RUL-04 | LoggedAction table is append-only — no deletes, no updates | Legal/Audit | Serbian accounting law (document retention) | Database constraint + application |
| RUL-05 | SEF invoice numbers must follow Serbian sequential numbering format | Legal | APR / SEF specification | Invoice numbering service |
| RUL-06 | PDV rate applied based on organization's country + product/service category | Tax | Serbian Tax Law (Zakon o PDV) | VAT calculation engine |
| RUL-07 | Financial data must be retained for minimum 10 years (Serbia), 11 years (Croatia) | Legal | Local accounting laws | Data retention policy |
| RUL-08 | Organizational data is strictly scoped — no cross-tenant queries permitted | Security | Multi-tenancy design | Organization-scoped middleware |

### 9.2 Regulatory & Compliance Requirements

| Regulation | Applicability | Requirements | Responsible |
|------------|--------------|-------------|-------------|
| Zakon o elektronskom fakturisanju (Serbia) | Yes — mandatory B2B since 2023 | SEF e-invoice submission; UBL 2.1 XML; digital signatures | John (Tech Lead) |
| Zakon o PDV (Serbia) | Yes | 20% standard, 10% reduced PDV; monthly filing by 15th | John + Asmir |
| Zakon o računovodstvu (Serbia) | Yes | Double-entry; 10-year document retention; annual balance sheet | John + Asmir |
| GDPR (EU-adjacent) | Yes — applies to data of EU citizens and ALAI Holding AS (Norway) | Data minimization, right to deletion, DPA, 72h breach notification | John + Alem |
| Croatian Zakon o fiskalizaciji (Phase 2) | Future | eRačun (HR-FISK/FINA) submission; 25% VAT; 11-year retention | Phase 2 |
| BiH PDV regulations (Phase 3) | Future | 17% PDV; CPF e-invoice (expected 2027) | Phase 3 |

### 9.3 Technical Constraints

- Must integrate with: SEF API (efaktura.gov.rs) — REST/UBL 2.1
- Must support: Chrome 100+, Firefox 100+, Safari 16+, Edge 100+ (desktop + mobile)
- Must run on: Cloud infrastructure (no on-premises requirement)
- All monetary arithmetic: NUMERIC(19,4) — no float/number types for currency
- Monorepo structure: Turborepo — cannot deviate from established Next.js + Express stack without ADR
- Database: PostgreSQL via Prisma — no ORM substitution

---

## 10. Assumptions & Dependencies

### 10.1 Assumptions

| # | Assumption | Risk if False | Validation Owner |
|---|-----------|--------------|-----------------|
| A-01 | SEF API (efaktura.gov.rs) sandbox is available for development testing | Integration delayed 4-6 weeks | John / Asmir |
| A-02 | No software certification required by Serbian tax authority for MVP launch | Compliance blocker; launch delayed | Asmir (legal research) |
| A-03 | UBL 2.1 XML format accepted by SEF for all invoice types in Phase 1 | Invoice engine rework required | John |
| A-04 | €11-17K budget sufficient for Phase 1 MVP | Scope reduction required | Alem + John |
| A-05 | Beta testers (5 SMBs + 3 accountants) can be recruited through Asmir's network | Beta delayed; less feedback | John + Asmir |

### 10.2 Dependencies

| # | Dependency | Type | Impact if Unavailable | Target Date | Status |
|---|-----------|------|----------------------|-------------|--------|
| DEP-01 | SEF API sandbox access credentials | External (APR) | Cannot develop/test e-invoicing | 2026-03-01 | Pending |
| DEP-02 | ALAI Tech d.o.o. Serbia registration | External (government) | Cannot legally operate in Serbia | 2026-04-01 | In progress |
| DEP-03 | Exchange rate API selection (ECB / fixer.io) | Internal decision | Multi-currency features incomplete | 2026-03-07 | Open |
| DEP-04 | Beta tester recruitment | External | Beta phase delayed | 2026-03-28 | Open |
| DEP-05 | bilko.rs + bilko.io domain SSL setup | External (registrar) | Cannot launch production | 2026-04-14 | Open |

---

## 11. ROI Analysis / Cost-Benefit

### 11.1 Investment Summary

| Cost Category | One-Time (EUR) | Annual (EUR) | Notes |
|--------------|---------------|-------------|-------|
| Development (Phase 1) | €12,000 | — | Includes backend + frontend + DevOps |
| Infrastructure (Year 1) | €1,200 | €1,200 | Cloud hosting, CDN, monitoring |
| Third-party APIs + services | €800 | €500 | SEF, exchange rate, email |
| Design + branding | €1,500 | — | Landing page, invoice templates |
| **Total Year 1** | **€15,500** | **€1,700** | Within €17K ceiling |

### 11.2 Benefit Projections

| Benefit | Year 1 (EUR) | Year 2 (EUR) | Year 3 (EUR) | Confidence |
|---------|-------------|-------------|-------------|-----------|
| SaaS subscription revenue (Serbia) | €18,000 | €42,000 | €72,000 | Medium |
| Additional revenue (Croatia + BiH) | — | €15,000 | €45,000 | Low |
| Total Revenue | €18,000 | €57,000 | €117,000 | Medium |

### 11.3 ROI Summary

| Metric | Value |
|--------|-------|
| Total Phase 1 Investment | €17,000 |
| Net Benefit Year 1 | €18,000 - €1,700 = €16,300 |
| Payback Period | ~12-14 months (post-launch) |
| 3-Year ROI | ~800% |
| 3-Year NPV (discount rate: 10%) | ~€140,000 |

---

## 12. Implementation Roadmap

| Phase | Description | Key Deliverables | Duration | Success Criteria |
|-------|-------------|-----------------|----------|-----------------|
| Phase 1 — Serbia MVP | Core accounting + SEF e-invoicing | 50 API endpoints, 8 frontend modules, SEF integration | 10 weeks | 100 paying orgs in 90 days; 100% SEF success rate |
| Phase 2 — Croatia | eRačun integration + HR-FISK | Croatian locale, 25% VAT, eRačun submission | 8 weeks | Croatia beta by Q4 2026 |
| Phase 3 — BiH | BiH PDV + CPF (when available) | Bosnian locale, 17% PDV, CPF integration | 6 weeks | BiH beta by Q2 2027 |
| Phase 4 — Enhancement | Payroll, AI bookkeeping, API | Payroll module, AI suggestions, public API | Ongoing | Reduce churn; increase ARPU |

---

## 13. Risk Assessment

| # | Risk | Probability | Business Impact | Mitigation |
|---|------|------------|-----------------|------------|
| BR-R01 | SEF API instability at launch | Medium | Critical — users cannot submit invoices | Abstract behind service layer; fallback to manual submission instructions |
| BR-R02 | Serbian regulatory changes pre-launch | Low | High — compliance requirements change | Asmir monitors APR; 2-week buffer in timeline for regulatory updates |
| BR-R03 | Pricing underestimation — SMBs won't pay even €8/month | Low | High — entire business model at risk | Beta price testing; free tier with conversion; Freemium model as backup |
| BR-R04 | Pantheon launches competitive cloud product | Low | Medium — reduces TAM addressable | Bilko wins on UX simplicity and price; switching costs are low but brand loyalty builds |
| BR-R05 | Currency volatility (RSD depreciation) | Medium | Low — affects EUR pricing attractiveness | Price in EUR; local currency display only |

> Full technical risk register: [`../governance/RISK-REGISTER.md`](../governance/RISK-REGISTER.md)

---

## Approval

| Role | Name | Date | Signature |
|------|------|------|-----------|
| Author | John (AI Director) | 2026-02-23 | |
| Reviewer | | | |
| Business Analyst | John | 2026-02-23 | |
| Product Owner | John | 2026-02-23 | |
| AI Director (John) | John | 2026-02-23 | |
| Client Sponsor | N/A — internal product | — | |
| CEO (Alem) | Alem Bašić | | |

# Functional Requirements Specification

# Functional Requirements Specification (FRS): Bilko

> **Project:** Bilko — Balkan Accounting SaaS
> **Version:** 0.1
> **Date:** 2026-02-23
> **Author:** John (AI Director)
> **Status:** Draft
> **Reviewers:** Alem Bašić (CEO)

## Document History
| Version | Date | Author | Changes |
|---------|------|--------|---------|
| 0.1     | 2026-02-23 | John (AI Director) | Initial draft — Phase 1 Serbia MVP |

---

## 1. System Overview

**System Name:** Bilko — Balkan Accounting SaaS
**System Purpose:** Bilko is a cloud-based accounting platform for Balkan SMBs that handles e-invoicing (Serbian SEF), expense tracking, double-entry bookkeeping, bank reconciliation, VAT/PDV management, and financial reporting. It provides a simple, compliant, affordable alternative to legacy ERP systems, accessible from any browser.

**System Context Diagram:**

```mermaid
graph TB
    subgraph "Bilko Platform"
        UI[Web App\nNext.js 15 + React 19]
        API[Backend API\nExpress + TypeScript]
        DB[(PostgreSQL\nPrisma ORM)]
    end
    U1[SMB Owner] -->|Uses| UI
    U2[Accountant] -->|Uses| UI
    U3[Viewer / Employee] -->|Read-only| UI
    API -->|Reads/Writes| DB
    API -->|Submits e-invoices| SEF[SEF Platform\nefaktura.gov.rs]
    API -->|Sends invoice PDFs| EMAIL[Email Provider\nTransactional]
    API -->|Fetches rates| FX[Exchange Rate API\nECB / fixer.io]
    ADM[Admin\nOrg Owner] -->|Manages org + users| UI
```

---

## 2. Actors & Personas

| Actor ID | Actor Name | Type | Description | Access Level |
|----------|-----------|------|-------------|-------------|
| ACT-01 | Organization Owner | Human | Business owner who created the Bilko account; full control | Owner role — all permissions |
| ACT-02 | Admin | Human | Designated admin (accountant or office manager) | Admin role — all except billing |
| ACT-03 | Accountant | Human | External bookkeeper managing the organization's books | Accountant role — financial data, reports; cannot delete |
| ACT-04 | Viewer | Human | Employee or partner with read-only access | Viewer role — read only |
| ACT-05 | SEF Platform | System | Serbian government e-invoice platform | External API |
| ACT-06 | Email Provider | System | Transactional email for invoice delivery | External API |
| ACT-07 | Exchange Rate API | System | Currency rate provider (ECB / fixer.io) | External API |

### Persona Detail

**Persona: Marko Petrović — SMB Owner**
- **Role:** Owner of a 8-person IT consulting firm in Belgrade
- **Goal:** Create and submit SEF invoices fast; see real-time P&L; file PDV without an accountant
- **Pain Points:** SEF portal is slow; Pantheon is complex; doesn't understand bookkeeping jargon
- **Tech Savviness:** Medium — uses Google Suite, smartphones, but not accounting software
- **Frequency of Use:** Daily (invoices) + monthly (PDV report)

**Persona: Ana Nikolić — Accountant**
- **Role:** Independent bookkeeper managing 12 SMB clients
- **Goal:** Access all client organizations from one login; export VAT reports in required formats
- **Pain Points:** Each client uses different software; reconciliation takes too long each month
- **Tech Savviness:** High — experienced with accounting software, Excel, CSV workflows
- **Frequency of Use:** Daily across multiple client orgs

---

## 3. Functional Requirements

### 3.1 Module: Authentication & User Management

#### Module Overview
Handles user registration, login, session management, organization creation, and role-based access control (RBAC). Multi-tenant: one user can belong to multiple organizations.

---

**FR-001: User Registration**

| Attribute | Value |
|-----------|-------|
| Module | Authentication |
| Priority | Must Have |
| Trace | BR-014 |
| UI Reference | `/auth/register` page |

**Description:**
A new user registers with email and password. On successful registration, a verification email is sent and a default organization is created for the user with Owner role.

**Acceptance Criteria:**
- [ ] **Given** a valid, unregistered email and strong password (≥8 chars, 1 uppercase, 1 number), **when** user submits registration form, **then** account is created, verification email sent, user redirected to email verification page
- [ ] **Given** an already-registered email, **when** user submits, **then** error "An account with this email already exists" shown; no account created
- [ ] **Given** password does not meet complexity rules, **when** user submits, **then** inline validation error shown before submission

**Data Requirements:**
- Input: email (unique), password, full name, organization name
- Output: user record, organization record, Owner role assignment, verification token
- Validation: email format, password complexity, uniqueness check

**Business Rules:** RUL-08 (org scoping from first login)

---

**FR-002: User Login**

| Attribute | Value |
|-----------|-------|
| Module | Authentication |
| Priority | Must Have |
| Trace | BR-014 |
| UI Reference | `/auth/login` page |

**Description:**
Authenticated users log in with email and password. Returns JWT access token (15-min TTL) + refresh token (30-day TTL).

**Acceptance Criteria:**
- [ ] **Given** valid credentials, **when** user submits login, **then** JWT issued, user redirected to dashboard
- [ ] **Given** invalid credentials, **when** user submits, **then** generic error "Invalid email or password" (no user enumeration)
- [ ] **Given** 5 consecutive failed attempts, **when** user tries again, **then** account locked for 15 minutes
- [ ] **Given** idle session > 30 minutes, **when** user attempts action, **then** redirected to login

---

**FR-003: Invite User to Organization**

| Attribute | Value |
|-----------|-------|
| Module | Authentication |
| Priority | Must Have |
| Trace | BR-007 |
| UI Reference | `/settings/team` page |

**Description:**
Organization Owner or Admin can invite users by email with a specific role (Admin, Accountant, Viewer). Invited user receives email with accept link; on acceptance, they are added to the organization with the assigned role.

**Acceptance Criteria:**
- [ ] **Given** an Owner invites user@email.com as Accountant, **when** invite is sent, **then** invitation email received within 2 minutes with unique accept link
- [ ] **Given** invited user accepts link within 48 hours, **when** they register or log in, **then** added to organization with Accountant role
- [ ] **Given** invite link expires (48h), **when** user clicks link, **then** error shown with option to request new invite

---

### 3.2 Module: Invoicing

#### Module Overview
Core invoicing functionality. Create, edit, preview, send, and track invoices. For Serbia: automatic SEF submission on send. Multi-currency. PDF generation with client/Bilko branding.

---

**FR-010: Create Invoice**

| Attribute | Value |
|-----------|-------|
| Module | Invoicing |
| Priority | Must Have |
| Trace | BR-001, BR-002, BR-004, BR-008 |
| UI Reference | `/invoices/create` — 6-step wizard |

**Description:**
User creates a new invoice by selecting a client (Contact), adding line items with quantities and unit prices, selecting currency and PDV rate. System auto-calculates PDV and totals. Preview shows PDF representation before sending.

**Acceptance Criteria:**
- [ ] **Given** an authenticated user, **when** they complete the 6-step invoice wizard with valid data, **then** invoice is created in Draft status with correct PDV calculation
- [ ] **Given** Serbian PDV rate of 20%, **when** line item total is 1000 RSD, **then** PDV = 200 RSD, total = 1200 RSD
- [ ] **Given** multi-currency invoice in EUR, **when** created, **then** exchange rate at transaction date is locked and stored
- [ ] **Given** invoice is in Draft, **when** user sends it, **then** status changes to Sent, PDF emailed to client, SEF submission initiated (Serbia)

**Data Requirements:**
- Input: client (Contact), invoice_date, due_date, currency, line_items (description, qty, unit_price, vat_rate), notes
- Output: Invoice record with auto-generated invoice_number, PDV amounts, total_amount in NUMERIC(19,4)
- Validation: due_date > invoice_date; at least one line item; contact required

**Business Rules:** RUL-01 (NUMERIC), RUL-02 (double-entry on payment), RUL-05 (sequential numbering), RUL-06 (PDV rate selection)

---

**FR-011: SEF E-Invoice Submission (Serbia)**

| Attribute | Value |
|-----------|-------|
| Module | Invoicing |
| Priority | Must Have |
| Trace | BR-001 |
| UI Reference | Automatic on invoice send; status shown in invoice detail |

**Description:**
When a user sends an invoice for a Serbian B2B transaction, Bilko automatically submits the invoice to SEF (efaktura.gov.rs) in UBL 2.1 XML format. SEF status (sent, accepted, rejected) is tracked and displayed.

**Acceptance Criteria:**
- [ ] **Given** a Serbian B2B invoice is sent, **when** the send action is triggered, **then** UBL 2.1 XML is generated and submitted to SEF API within 30 seconds
- [ ] **Given** SEF accepts the invoice, **when** success response received, **then** invoice SEF status updated to "Accepted" and SEF invoice ID stored
- [ ] **Given** SEF rejects the invoice, **when** rejection response received, **then** user is notified with the rejection reason from SEF; invoice stays in Sent status pending correction
- [ ] **Given** SEF API is unavailable, **when** submission attempted, **then** invoice queued for retry; user notified; max 3 retries with exponential backoff

**Data Requirements:**
- Input: Invoice record + organization SEF credentials
- Output: SEF invoice ID, submission timestamp, SEF status
- Validation: Required SEF fields present (buyer tax ID, invoice type, issue date)

---

**FR-012: Track Invoice Status**

| Attribute | Value |
|-----------|-------|
| Module | Invoicing |
| Priority | Must Have |
| Trace | BR-001, BR-008 |

**Description:**
Invoices progress through status states: Draft → Sent → SEF Accepted → Paid / Overdue. Users can mark invoices as paid, add payment date and amount.

**Acceptance Criteria:**
- [ ] **Given** invoice is Sent, **when** user marks as paid with payment date and amount, **then** status changes to Paid and payment transaction auto-created
- [ ] **Given** invoice is Sent and due_date has passed, **when** system checks daily, **then** status automatically changes to Overdue
- [ ] **Given** a list of invoices, **when** user filters by status, **then** only matching invoices shown

---

### 3.3 Module: Expense Tracking

#### Module Overview
Record business expenses with categorization, multi-currency support, and receipt attachment. Feeds double-entry bookkeeping automatically.

---

**FR-020: Create Expense**

| Attribute | Value |
|-----------|-------|
| Module | Expenses |
| Priority | Must Have |
| Trace | BR-009 |
| UI Reference | `/expenses/create` |

**Description:**
User records a business expense with vendor, amount, currency, category, payment method, and optional receipt photo. System auto-creates the double-entry transaction.

**Acceptance Criteria:**
- [ ] **Given** valid expense data, **when** user submits, **then** expense saved with debit to expense account + credit to payment account
- [ ] **Given** a foreign currency expense, **when** created, **then** exchange rate at expense date locked and stored; amount also shown in base currency
- [ ] **Given** receipt image uploaded (JPG/PNG/PDF, max 10MB), **when** expense saved, **then** receipt stored and accessible from expense record

---

### 3.4 Module: Double-Entry Bookkeeping

#### Module Overview
The accounting engine. Every financial event generates balanced debit + credit Transaction entries. Supports Chart of Accounts per Balkan GAAP (Serbian Kontni Okvir 2021).

---

**FR-030: Chart of Accounts**

| Attribute | Value |
|-----------|-------|
| Module | Bookkeeping |
| Priority | Must Have |
| Trace | BR-003, BR-010 |
| UI Reference | `/settings/accounts` |

**Description:**
Every organization is seeded with the Serbian Kontni Okvir (Chart of Accounts) per Pravilnik 2021 on creation. Accountants can add custom sub-accounts. Pre-populated accounts cover all 10 account classes (0-9).

**Acceptance Criteria:**
- [ ] **Given** a new Serbian organization is created, **when** setup completes, **then** all standard Kontni Okvir accounts are pre-populated (Classes 0-9)
- [ ] **Given** an accountant adds a custom sub-account under 411, **when** saved, **then** account 411xxx appears in Chart of Accounts and is available in transaction entry
- [ ] **Given** an account has transactions, **when** user attempts to delete it, **then** deletion blocked with explanation

---

**FR-031: Double-Entry Transaction Recording**

| Attribute | Value |
|-----------|-------|
| Module | Bookkeeping |
| Priority | Must Have |
| Trace | BR-003 |
| UI Reference | Auto-generated; viewable in `/bookkeeping/journal` |

**Description:**
Every financial event (invoice paid, expense recorded, bank reconciliation) automatically generates a balanced Transaction record with debitAccountId, creditAccountId, and amount in NUMERIC(19,4).

**Acceptance Criteria:**
- [ ] **Given** an invoice of 1200 RSD (1000 + 200 PDV) is marked paid, **when** payment recorded, **then** Transaction created: Debit 1200 (bank account), Credit 1000 (revenue), Credit 200 (PDV payable)
- [ ] **Given** any transaction is created, **when** saved, **then** sum of all debits = sum of all credits (ACID enforcement)
- [ ] **Given** a transaction is created, **when** user attempts to delete it, **then** soft-delete only — LoggedAction records the deletion; original data preserved

**Business Rules:** RUL-01, RUL-02, RUL-03, RUL-04

---

### 3.5 Module: Bank Reconciliation

#### Module Overview
Import bank statements via CSV upload. Auto-match transactions. Manual reconciliation for unmatched items.

---

**FR-040: Bank Statement CSV Import**

| Attribute | Value |
|-----------|-------|
| Module | Banking |
| Priority | Must Have |
| Trace | BR-005 |
| UI Reference | `/banking` page |

**Description:**
Users upload bank statement CSV files (Serbian bank format). System parses transactions and attempts to auto-match with existing invoices/expenses by amount and date proximity.

**Acceptance Criteria:**
- [ ] **Given** a valid CSV in supported Serbian bank format, **when** uploaded, **then** all transactions parsed and displayed for review
- [ ] **Given** parsed transaction matches an open invoice by amount ± 5%, **when** suggested, **then** match highlighted for user confirmation
- [ ] **Given** unmatched transaction, **when** user manually matches or categorizes, **then** Transaction and double-entry entry created

---

### 3.6 Module: VAT / PDV Management

#### Module Overview
Auto-calculate, track, and generate PDV reports for monthly filing with Poreska Uprava (Serbia).

---

**FR-050: PDV Report Generation**

| Attribute | Value |
|-----------|-------|
| Module | VAT/PDV |
| Priority | Must Have |
| Trace | BR-002, BR-006 |
| UI Reference | `/reports/vat` |

**Description:**
System aggregates all VAT-applicable transactions for a period and generates the PDV report in the format required by Poreska Uprava. Export in PDF and XML/JSON formats.

**Acceptance Criteria:**
- [ ] **Given** a reporting period (month), **when** user generates PDV report, **then** all sales PDV and input PDV correctly summed; net PDV payable/refundable calculated
- [ ] **Given** PDV report generated, **when** user exports, **then** PDF and XML export available; XML format compatible with ePorezi portal
- [ ] **Given** zero PDV period, **when** report generated, **then** zero report generated correctly (still required by law)

---

### 3.7 Module: Financial Reports

#### Module Overview
P&L Statement, Balance Sheet, Cash Flow Statement — generated from double-entry transaction data. PDF and Excel export.

---

**FR-060: Profit & Loss Statement**

| Attribute | Value |
|-----------|-------|
| Module | Reports |
| Priority | Must Have |
| Trace | BR-006 |
| UI Reference | `/reports` hub |

**Acceptance Criteria:**
- [ ] **Given** a date range, **when** P&L generated, **then** all revenue and expense accounts summarized; net profit/loss calculated and matches double-entry totals
- [ ] **Given** multi-currency org, **when** P&L generated, **then** all amounts shown in base currency using locked exchange rates

---

**FR-061: Balance Sheet**

| Attribute | Value |
|-----------|-------|
| Module | Reports |
| Priority | Must Have |
| Trace | BR-006 |

**Acceptance Criteria:**
- [ ] **Given** any date, **when** Balance Sheet generated, **then** Assets = Liabilities + Equity (double-entry balance enforced)
- [ ] **Given** Balance Sheet is unbalanced (should be impossible), **when** detected, **then** alert raised immediately for investigation

---

### 3.8 Module: Multi-Currency

#### Module Overview
Support BAM, RSD, EUR, USD. Exchange rates fetched daily from ECB / fixer.io. Rates locked at transaction date per IFRS requirements.

---

**FR-070: Exchange Rate Management**

| Attribute | Value |
|-----------|-------|
| Module | Multi-Currency |
| Priority | Must Have |
| Trace | BR-004 |

**Acceptance Criteria:**
- [ ] **Given** a transaction in non-base currency, **when** created, **then** exchange rate at transaction date is fetched, stored, and locked — cannot be edited later
- [ ] **Given** ECB rate API unavailable, **when** transaction attempted, **then** system uses cached rate (max 24h old) or prompts user for manual entry
- [ ] **Given** organization base currency is RSD, **when** EUR invoice created, **then** both EUR amount and RSD equivalent stored; reports show RSD

---

## 4. Use Case Diagrams

### 4.1 Core Workflows

```mermaid
graph LR
    Owner((Owner)) --> UC1[FR-001: Register]
    Owner --> UC2[FR-010: Create Invoice]
    Owner --> UC3[FR-011: Submit to SEF]
    Owner --> UC4[FR-050: Generate PDV Report]
    Owner --> UC5[FR-060: View P&L]
    Accountant((Accountant)) --> UC2
    Accountant --> UC6[FR-030: Manage Chart of Accounts]
    Accountant --> UC7[FR-031: Record Manual Transaction]
    Accountant --> UC4
    Accountant --> UC8[FR-040: Import Bank CSV]
    Viewer((Viewer)) --> UC9[View Reports — Read Only]
    SEF((SEF API)) --> UC3
```

---

## 5. System Behavior Specifications

### 5.1 Error Handling
- All user-facing errors display human-readable Serbian/English message (no stack traces)
- All errors logged with correlation ID, timestamp, user ID (if authenticated), and action
- Validation errors shown inline, adjacent to the invalid field
- SEF API errors: show SEF's rejection reason in user-readable format + link to fix

### 5.2 Data Persistence
- All financial data persisted within 500ms of user action
- Optimistic UI updates rolled back if server confirmation fails
- All mutations (create/update/delete) audited in LoggedAction with user ID and timestamp

### 5.3 Session & State
- Session timeout: 30 minutes of inactivity (JWT expiry)
- Refresh token: 30-day rolling TTL
- Concurrent sessions: allowed (mobile + desktop)
- Browser refresh: state restored from server (no stale data)

### 5.4 Notifications
- Email notifications: invoice sent, invoice paid, SEF acceptance/rejection, account invitation
- In-app notifications: overdue invoices, PDV filing reminder (14th of month), bank import complete
- All marketing emails include unsubscribe link (GDPR)

### 5.5 Accessibility
- WCAG 2.1 Level AA compliance
- Keyboard navigation for all interactive elements
- Screen reader compatibility (Radix UI / shadcn ARIA labels)
- Color contrast ratio ≥ 4.5:1 (Bilko mint green #00E5A0 on dark backgrounds verified)

---

## 6. Requirements Summary Table

| ID | Feature Name | Module | Priority | Status | Trace |
|----|-------------|--------|----------|--------|-------|
| FR-001 | User Registration | Authentication | Must Have | Draft | BR-014 |
| FR-002 | User Login | Authentication | Must Have | Draft | BR-014 |
| FR-003 | Invite User to Organization | Authentication | Must Have | Draft | BR-007 |
| FR-010 | Create Invoice | Invoicing | Must Have | Draft | BR-001, BR-002, BR-004, BR-008 |
| FR-011 | SEF E-Invoice Submission | Invoicing | Must Have | Draft | BR-001 |
| FR-012 | Track Invoice Status | Invoicing | Must Have | Draft | BR-001, BR-008 |
| FR-020 | Create Expense | Expenses | Must Have | Draft | BR-009 |
| FR-030 | Chart of Accounts | Bookkeeping | Must Have | Draft | BR-003, BR-010 |
| FR-031 | Double-Entry Transaction Recording | Bookkeeping | Must Have | Draft | BR-003 |
| FR-040 | Bank Statement CSV Import | Banking | Must Have | Draft | BR-005 |
| FR-050 | PDV Report Generation | VAT/PDV | Must Have | Draft | BR-002, BR-006 |
| FR-060 | P&L Statement | Reports | Must Have | Draft | BR-006 |
| FR-061 | Balance Sheet | Reports | Must Have | Draft | BR-006 |
| FR-070 | Exchange Rate Management | Multi-Currency | Must Have | Draft | BR-004 |

**Requirements Count:**
- Must Have: 14
- Should Have: 0 in this document (Croatian eRačun in Phase 2 FRS)
- Could Have: 0
- Won't Have (Phase 1): Payroll, AI bookkeeping, live bank feeds

---

## 7. Traceability to Business Requirements

| FR ID | Feature Name | Business Requirement (BR ID) | Business Objective (BO ID) |
|-------|-------------|------------------------------|---------------------------|
| FR-001 | User Registration | BR-014 | BO-01 |
| FR-002 | User Login | BR-014 | BO-01 |
| FR-003 | Invite User | BR-007 | BO-02 |
| FR-010 | Create Invoice | BR-001, BR-002, BR-004, BR-008 | BO-01, BO-02 |
| FR-011 | SEF Submission | BR-001 | BO-01 |
| FR-012 | Invoice Status Tracking | BR-001, BR-008 | BO-02 |
| FR-020 | Create Expense | BR-009 | BO-02 |
| FR-030 | Chart of Accounts | BR-003, BR-010 | BO-01 |
| FR-031 | Double-Entry Recording | BR-003 | BO-01 |
| FR-040 | Bank CSV Import | BR-005 | BO-02 |
| FR-050 | PDV Report | BR-002, BR-006 | BO-01, BO-03 |
| FR-060 | P&L Statement | BR-006 | BO-03 |
| FR-061 | Balance Sheet | BR-006 | BO-01, BO-03 |
| FR-070 | Exchange Rates | BR-004 | BO-01 |

> Full traceability matrix: [`RTM.md`](RTM.md)

---

## Approval

| Role | Name | Date | Signature |
|------|------|------|-----------|
| Author | John (AI Director) | 2026-02-23 | |
| Reviewer | | | |
| Business Analyst | John | 2026-02-23 | |
| Tech Lead | John | 2026-02-23 | |
| Product Owner | John | 2026-02-23 | |
| AI Director (John) | John | 2026-02-23 | |
| CEO (Alem) | Alem Bašić | | |

# Non-Functional Requirements

# Non-Functional Requirements (NFR): Bilko

> **Project:** Bilko — Balkan Accounting SaaS
> **Version:** 0.1
> **Date:** 2026-02-23
> **Author:** John (AI Director)
> **Status:** Draft
> **Reviewers:** Alem Bašić (CEO)

## Document History
| Version | Date | Author | Changes |
|---------|------|--------|---------|
| 0.1     | 2026-02-23 | John (AI Director) | Initial draft — Phase 1 Serbia MVP |

---

## 1. NFR Overview

| Category | # Requirements | Highest Priority | Owner |
|----------|---------------|-----------------|-------|
| Performance | 8 | Critical | John |
| Scalability | 5 | High | John / DevOps agent |
| Availability | 6 | Critical | John / DevOps agent |
| Security | 10 | Critical | John |
| Reliability | 6 | Critical | John |
| Usability | 7 | High | John / Designer |
| Compatibility | 6 | High | John |
| Maintainability | 6 | Medium | John |
| Compliance | 8 | Critical | John + Asmir |
| Data | 8 | Critical | John |

---

## 2. Performance Requirements

| ID | Requirement | Metric | Target | Measurement Conditions | Measurement Method | Priority |
|----|------------|--------|--------|----------------------|-------------------|----------|
| NFR-P01 | Dashboard page load (initial) | Time to Interactive | < 3 seconds | 4G connection, cold cache | Lighthouse / WebPageTest | Must Have |
| NFR-P02 | Dashboard page load (subsequent) | Time to Interactive | < 1 second | Warm cache, average device | Lighthouse | Must Have |
| NFR-P03 | Invoice creation wizard navigation | Time per step | < 500ms | Any device, warm cache | Lighthouse | Must Have |
| NFR-P04 | API response time (standard CRUD) | p95 response time | < 300ms | ≤ 1000 concurrent users | APM tool / k6 | Must Have |
| NFR-P05 | API response time (reports) | p95 response time | < 2 seconds | ≤ 1000 concurrent orgs | APM tool | Must Have |
| NFR-P06 | SEF submission response | End-to-end latency | < 30 seconds | SEF API response time | API monitoring | Must Have |
| NFR-P07 | Core Web Vitals: LCP | Largest Contentful Paint | < 2.5 seconds | Mobile, 4G | Lighthouse | Must Have |
| NFR-P08 | Core Web Vitals: CLS | Cumulative Layout Shift | < 0.1 | Any device | Lighthouse | Must Have |

---

## 3. Scalability Requirements

| ID | Requirement | Metric | Launch Target | 12-Month Target | Measurement Method | Priority |
|----|------------|--------|-------------|----------------|-------------------|----------|
| NFR-S01 | Concurrent organizations | Active organizations | 1,000 | 10,000 | Load testing (k6) | Must Have |
| NFR-S02 | Concurrent user sessions | Simultaneous sessions | 500 | 5,000 | Load testing | Must Have |
| NFR-S03 | API throughput | Requests per second | 200 RPS | 2,000 RPS | k6 load test | Must Have |
| NFR-S04 | Data volume per organization | Transactions per org/year | 50,000 | 200,000 | Storage + query monitoring | Should Have |
| NFR-S05 | Auto-scaling response | Time to add new instance | < 3 minutes | < 3 minutes | Cloud console metrics | Should Have |

---

## 4. Availability Requirements

| ID | Requirement | Target | Measurement Period | Exclusions | Priority |
|----|------------|--------|-------------------|------------|----------|
| NFR-A01 | System uptime SLA | ≥ 99.9% | Monthly rolling | Scheduled maintenance windows | Must Have |
| NFR-A02 | Scheduled maintenance window | Max 2 hours/month | Monthly | Preferred: Sunday 02:00-04:00 CET | Must Have |
| NFR-A03 | Maintenance notification lead time | ≥ 48 hours notice | Per event | Emergency patches: 4 hours | Must Have |
| NFR-A04 | RPO (Recovery Point Objective) | Max 1 hour data loss | Per incident | N/A | Must Have |
| NFR-A05 | RTO (Recovery Time Objective) | System restored within 4 hours | Per incident | N/A | Must Have |
| NFR-A06 | Database backup frequency | Daily full + hourly transaction log | Ongoing | N/A | Must Have |

**SLA Calculation Reference:**
| Uptime % | Annual Downtime | Monthly Downtime |
|----------|----------------|-----------------|
| 99.9% | 8.7 hours | 43.8 minutes |
| 99.5% | 43.8 hours | 3.6 hours |
| 99.0% | 87.6 hours | 7.3 hours |

---

## 5. Security Requirements

| ID | Requirement | Category | Target / Standard | Measurement Method | Priority |
|----|------------|----------|------------------|-------------------|----------|
| NFR-SEC01 | Authentication | Auth | JWT (access: 15min TTL) + refresh token (30d rolling TTL); bcrypt password hashing (cost factor ≥ 12) | Code review | Must Have |
| NFR-SEC02 | Password policy | Auth | Min 8 chars, 1 uppercase, 1 number, 1 special character | Automated test | Must Have |
| NFR-SEC03 | Account lockout | Auth | 5 failed attempts → 15-min lockout; logged in LoggedAction | Automated test | Must Have |
| NFR-SEC04 | Data encryption in transit | Encryption | TLS 1.3 minimum; HTTP → HTTPS redirect enforced | SSL Labs scan (grade A+) | Must Have |
| NFR-SEC05 | Data encryption at rest | Encryption | Database encryption at rest (cloud provider); bcrypt for passwords | Infrastructure review | Must Have |
| NFR-SEC06 | Input validation | Injection Prevention | All inputs sanitized server-side with Zod; parameterized queries via Prisma | Code review + SAST | Must Have |
| NFR-SEC07 | XSS prevention | Injection Prevention | React default encoding + CSP headers; no dangerouslySetInnerHTML | OWASP ZAP / code review | Must Have |
| NFR-SEC08 | Rate limiting | DDoS/Abuse | Auth endpoints: 5 req/min; General API: 100 req/min per IP | Load test + monitoring | Must Have |
| NFR-SEC09 | Audit logging | Compliance | All auth events, financial mutations logged in LoggedAction (append-only) with user ID + timestamp | Log review | Must Have |
| NFR-SEC10 | Organization data isolation | Multi-tenancy | All database queries scoped to organizationId via middleware; no cross-tenant queries | Code review + penetration test | Must Have |
| NFR-SEC11 | Security headers | HTTP Security | HSTS, X-Frame-Options: DENY, X-Content-Type-Options: nosniff, CSP | securityheaders.com scan | Must Have |
| NFR-SEC12 | Dependency security | Supply Chain | No known critical CVEs; automated scan in CI | Snyk / npm audit in CI | Should Have |

---

## 6. Reliability Requirements

| ID | Requirement | Metric | Target | Measurement Method | Priority |
|----|------------|--------|--------|-------------------|----------|
| NFR-R01 | Application error rate | 5xx errors / total requests | < 0.1% | APM monitoring | Must Have |
| NFR-R02 | ACID compliance | Transaction integrity | 100% — all financial transactions ACID-compliant | PostgreSQL guarantees + DB tests | Must Have |
| NFR-R03 | Double-entry balance integrity | Debit = Credit for all transactions | Zero imbalance events | CI test: balance check on all transactions | Must Have |
| NFR-R04 | SEF queue reliability | Failed SEF submissions retried | Max 3 retries; success on retry > 99% for transient failures | SEF monitoring | Must Have |
| NFR-R05 | Data integrity | Zero data corruption | 0 corruption events per 12 months | Database integrity checks | Must Have |
| NFR-R06 | Health check endpoint | System health observable | /api/health returns 200 when healthy | Uptime monitoring | Must Have |

---

## 7. Usability Requirements

| ID | Requirement | Target | Measurement Method | Priority |
|----|------------|--------|-------------------|----------|
| NFR-U01 | Time to create first invoice | New user creates first invoice in < 10 minutes | Beta user testing | Must Have |
| NFR-U02 | Invoice wizard completion rate | ≥ 85% of users who start wizard complete it | Analytics (funnel) | Must Have |
| NFR-U03 | WCAG compliance | WCAG 2.1 Level AA | axe-core automated + manual | Must Have |
| NFR-U04 | Keyboard navigation | All interactive elements reachable by keyboard | Manual testing | Must Have |
| NFR-U05 | Mobile responsiveness | Fully functional on 375px–1440px viewport | Manual + Lighthouse | Must Have |
| NFR-U06 | Language: Serbian | Full UI in Serbian (Latin script) for Phase 1; Cyrillic toggle | Manual review by native speaker | Must Have |
| NFR-U07 | Error messages | All errors in Serbian language; actionable advice included | Content audit | Must Have |

---

## 8. Compatibility Requirements

| ID | Requirement | Category | Target | Priority |
|----|------------|----------|--------|----------|
| NFR-C01 | Web browsers (desktop) | Browser | Chrome 100+, Firefox 100+, Safari 16+, Edge 100+ | Must Have |
| NFR-C02 | Web browsers (mobile) | Browser | Safari iOS 15+, Chrome Android 100+ | Must Have |
| NFR-C03 | Mobile operating systems | OS | iOS 15+, Android 11+ | Must Have |
| NFR-C04 | Screen resolutions | Responsive | 375px to 2560px viewport width | Must Have |
| NFR-C05 | SEF API compatibility | External API | SEF API v1 (UBL 2.1 XML, REST) | Must Have |
| NFR-C06 | Bank CSV formats | Import | Serbian bank CSV formats: Raiffeisen, UniCredit, OTP, Banca Intesa | Should Have |

---

## 9. Maintainability Requirements

| ID | Requirement | Metric | Target | Measurement Method | Priority |
|----|------------|--------|--------|-------------------|----------|
| NFR-M01 | Test coverage (backend) | % code covered by automated tests | ≥ 80% overall; ≥ 95% for financial logic (double-entry, VAT, SEF) | CI coverage report | Must Have |
| NFR-M02 | TypeScript strict mode | Type safety | `strict: true` in tsconfig for all packages | CI type-check | Must Have |
| NFR-M03 | Deployment frequency | Time to deploy bug fix to production | < 1 hour from PR merge | CI/CD metrics | Should Have |
| NFR-M04 | Database migrations | Schema change process | All changes via Prisma migration; never edit existing migration | Code review | Must Have |
| NFR-M05 | Monorepo build time | Turborepo build | Full build < 3 minutes; incremental < 30 seconds | CI metrics | Should Have |
| NFR-M06 | Logging completeness | Log coverage | All external API calls (SEF, email, FX), all errors, all financial mutations logged | Log review | Must Have |

---

## 10. Compliance Requirements

| ID | Regulation | Applicability | Requirement | Technical Implementation | Priority |
|----|-----------|--------------|-------------|------------------------|----------|
| NFR-COMP01 | Zakon o elektronskom fakturisanju (Serbia) | Yes — mandatory B2B 2023 | Submit e-invoices to SEF in UBL 2.1; sequential numbering; digital signature | SefService module; UBL 2.1 XML generation | Must Have |
| NFR-COMP02 | Zakon o PDV (Serbia) | Yes — all VAT-registered orgs | 20% standard, 10% reduced PDV; monthly filing by 15th; PDV report format for ePorezi | PDV calculation engine; report export | Must Have |
| NFR-COMP03 | Zakon o računovodstvu (Serbia) | Yes | Double-entry; 10-year document retention; annual balance sheet; audit trail | LoggedAction (append-only); DB retention policy | Must Have |
| NFR-COMP04 | GDPR (EU / Norwegian Personvernloven) | Yes — ALAI Holding AS is Norwegian; processes EU citizen data | Lawful basis for processing; right to deletion within 30 days; DPA in place; breach notification within 72h; data export (Article 20) | User data deletion API; audit logs; DPA | Must Have |
| NFR-COMP05 | GDPR — Data minimization | Yes | Collect only data necessary for accounting function | BA review of data model; field-level PII audit | Must Have |
| NFR-COMP06 | GDPR — Cookie consent | Yes — if tracking cookies used | Explicit consent before non-essential cookies | Cookie consent banner; opt-in only analytics | Must Have |
| NFR-COMP07 | Multi-tenancy data isolation | Yes — SaaS requirement | Organization data strictly scoped; no cross-tenant access | organizationId middleware + DB constraint | Must Have |
| NFR-COMP08 | WCAG 2.1 AA | Yes — accessibility standard | Digital accessibility for all users | NFR-U03, NFR-U04 | Must Have |

---

## 11. Data Requirements

| ID | Requirement | Category | Target | Implementation | Priority |
|----|------------|----------|--------|---------------|----------|
| NFR-D01 | Monetary precision | Data type | ALL monetary fields: NUMERIC(19,4) — NEVER float, NEVER JavaScript number | Prisma schema: Decimal type enforced | Must Have |
| NFR-D02 | Data retention — financial records | Retention | 10 years minimum (Serbia); 11 years (Croatia) | Retention policy in DB; no auto-delete of financial records | Must Have |
| NFR-D03 | Data retention — logs | Retention | Application logs: 90 days; Audit logs (LoggedAction): retain permanently | Log rotation + LoggedAction never purged | Must Have |
| NFR-D04 | Database backup | Backup | Full backup daily; transaction logs every 1 hour | Automated backup schedule in cloud provider | Must Have |
| NFR-D05 | Backup encryption | Backup | Backups encrypted at rest (AES-256) | Cloud provider encryption | Must Have |
| NFR-D06 | PII identification | Privacy | All PII fields documented; user email, name, tax ID (PIB) identified | Data dictionary + Prisma annotations | Must Have |
| NFR-D07 | Data export (portability) | Portability | User can export all organization data (invoices, expenses, transactions, contacts) in JSON/CSV | Export API endpoint | Must Have |
| NFR-D08 | Exchange rate immutability | Integrity | Exchange rate locked at transaction date; cannot be retroactively edited | DB constraint + LoggedAction on change attempt | Must Have |

---

## 12. NFR Testing & Verification Plan

| NFR Category | Testing Method | Tools | Frequency | Pass Criteria |
|-------------|---------------|-------|-----------|---------------|
| Performance | Lighthouse + k6 load test | Lighthouse, k6 | Pre-launch + monthly | All NFR-P targets met at normal load |
| Scalability | k6 stress test (2× normal load) | k6 | Pre-launch | Graceful degradation; no data corruption under stress |
| Security | SAST + OWASP ZAP + manual code review | Snyk, OWASP ZAP | CI (SAST), Pre-launch (DAST) | No critical/high unresolved vulnerabilities |
| Compliance (SEF) | SEF sandbox end-to-end test | SEF sandbox API | Pre-launch | 100% invoice submission success in sandbox |
| Compliance (PDV) | Manual accounting verification + test data | Test data set | Pre-launch + each PDV change | PDV calculations match expected values for 20 test cases |
| Compliance (GDPR) | Manual review + deletion test | Manual | Pre-launch + annual | Right to deletion completes within 30 days; export works |
| Accessibility | axe-core + keyboard manual test | axe-core | Per sprint | WCAG 2.1 AA — 0 critical violations |
| Availability | Uptime monitoring + DR drill | Uptime monitor | Ongoing + quarterly | SLA ≥ 99.9% monthly |
| Data integrity | DB constraint tests + balance check in CI | Prisma + custom tests | CI (every PR) | 0 debit/credit imbalances; 0 NUMERIC precision errors |

---

## Approval

| Role | Name | Date | Signature |
|------|------|------|-----------|
| Author | John (AI Director) | 2026-02-23 | |
| Reviewer | | | |
| Tech Lead | John | 2026-02-23 | |
| Business Analyst | John | 2026-02-23 | |
| Product Owner | John | 2026-02-23 | |
| AI Director (John) | John | 2026-02-23 | |
| CEO (Alem) | Alem Bašić | | |

# User Stories

# User Stories: Bilko

> **Project:** Bilko — Balkan Accounting SaaS
> **Version:** 0.1
> **Date:** 2026-02-23
> **Author:** John (AI Director)
> **Status:** Draft
> **Reviewers:** Alem Bašić (CEO)

## Document History
| Version | Date | Author | Changes |
|---------|------|--------|---------|
| 0.1     | 2026-02-23 | John (AI Director) | Initial draft — Phase 1 Serbia MVP |

---

## 1. Epic Overview

| Epic ID | Epic Name | Business Goal | Story Count | Status | Target Release |
|---------|----------|--------------|-------------|--------|---------------|
| EP-01 | Authentication & Organization Setup | Secure multi-tenant access | 4 | Backlog | Phase 1 (Serbia) |
| EP-02 | Invoicing + SEF E-Invoicing | SEF-compliant invoice creation and submission | 6 | Backlog | Phase 1 (Serbia) |
| EP-03 | Expense Tracking | Record and categorize business expenses | 3 | Backlog | Phase 1 (Serbia) |
| EP-04 | Double-Entry Bookkeeping | Accurate accounting per Balkan GAAP | 4 | Backlog | Phase 1 (Serbia) |
| EP-05 | Bank Reconciliation | Import and match bank transactions | 3 | Backlog | Phase 1 (Serbia) |
| EP-06 | VAT/PDV Management | Auto-calculate and report PDV | 3 | Backlog | Phase 1 (Serbia) |
| EP-07 | Financial Reports | P&L, Balance Sheet, Cash Flow | 4 | Backlog | Phase 1 (Serbia) |
| EP-08 | Multi-Currency | BAM, RSD, EUR, USD support | 3 | Backlog | Phase 1 (Serbia) |

---

## 2. Epic Summaries

### Epic EP-01 — Authentication & Organization Setup

**Epic Statement:**
As an **SMB owner**, I need **to securely register, log in, and manage my team's access** so that **only authorized people can view and modify my financial data**.

**Business Goal:** BR-014 (secure multi-tenancy), BR-007 (RBAC)
**Priority:** Must Have | **Target Sprint:** Sprint 1

**Acceptance Criteria at Epic Level:**
- [ ] User can register, verify email, and log in
- [ ] Organization is created on registration with Serbian Chart of Accounts pre-populated
- [ ] Owner can invite accountant with Accountant role; accountant has full financial access but cannot manage billing

---

### Epic EP-02 — Invoicing + SEF E-Invoicing

**Epic Statement:**
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:** BR-001 (SEF), BR-002 (PDV), BR-008 (PDF delivery)
**Priority:** Must Have | **Target Sprint:** Sprint 2-3 | **Estimated Size:** 34 story points

---

### 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].
```

---

## 4. Story Backlog

### Epic EP-01: Authentication & Organization Setup

---

#### US-001: Register and Create Organization

| Attribute | Value |
|-----------|-------|
| Epic | EP-01: Authentication & Organization Setup |
| Priority | Must Have |
| Story Points | 5 |
| Sprint | Sprint 1 |
| Assigned To | builder agent |
| Status | Backlog |
| FR Reference | FR-001 |
| BR Reference | BR-014 |

**Story:**
As a **new Bilko user**,
I want **to register with my email and create my first organization**,
So that **I can start managing my business finances immediately after signing up**.

**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.

**Acceptance Criteria:**
- [ ] **Given** a valid email and strong password, **when** user submits registration form with full name and organization name, **then** account + organization created; verification email sent within 2 minutes
- [ ] **Given** user clicks verification link (valid for 48h), **when** link is valid, **then** email confirmed; user redirected to dashboard of their new organization
- [ ] **Given** duplicate email submitted, **when** user registers, **then** error "An account with this email already exists" shown; no new account created
- [ ] **Given** organization created, **when** user first views Chart of Accounts, **then** all standard Serbian Kontni Okvir accounts (Classes 0-9) are present

**Technical Notes:**
- Organization seeding: call `seedChartOfAccounts(organizationId, 'RS')` on org creation
- JWT: access token 15min TTL, refresh token 30d rolling

**UI/UX Notes:**
- Screen: `/auth/register` + email verification page
- Responsive: full-screen centered card on mobile + desktop

**Dependencies:**
- Blocked by: None
- Blocks: US-003 (invite users), US-010 (create invoice)

---

#### US-002: Login with JWT

| Attribute | Value |
|-----------|-------|
| Epic | EP-01 |
| Priority | Must Have |
| Story Points | 3 |
| Sprint | Sprint 1 |
| Assigned To | builder agent |
| Status | Backlog |
| FR Reference | FR-002 |
| BR Reference | BR-014 |

**Story:**
As a **registered Bilko user**,
I want **to log in securely and have my session persist for a reasonable time**,
So that **I don't have to re-authenticate every time I open the app**.

**Acceptance Criteria:**
- [ ] **Given** valid credentials, **when** user submits login form, **then** authenticated; access + refresh tokens set; redirected to last-used organization dashboard
- [ ] **Given** invalid credentials, **when** user submits, **then** generic error "Pogrešan email ili lozinka" (Serbian) shown; no user enumeration
- [ ] **Given** 5 failed attempts within 15 minutes, **when** another attempt made, **then** error "Nalog je privremeno zaključan. Pokušajte za 15 minuta."
- [ ] **Given** access token expires (15min idle), **when** user makes API call, **then** refresh token used to silently issue new access token; user not logged out

**Dependencies:** Blocked by: US-001

---

#### US-003: Invite Accountant to Organization

| Attribute | Value |
|-----------|-------|
| Epic | EP-01 |
| Priority | Must Have |
| Story Points | 5 |
| Sprint | Sprint 1 |
| Assigned To | builder agent |
| Status | Backlog |
| FR Reference | FR-003 |
| BR Reference | BR-007 |

**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**.

**Acceptance Criteria:**
- [ ] **Given** owner is in Settings > Team, **when** they enter accountant@email.com and select Accountant role, **then** invitation email sent with 48h-valid accept link
- [ ] **Given** invited user accepts and is already registered, **when** link clicked, **then** added to organization with Accountant role; no new registration required
- [ ] **Given** invited user is new, **when** link clicked, **then** registration flow with role pre-assigned
- [ ] **Given** Accountant logs in, **when** they navigate to organization, **then** full financial access; billing and org-deletion options hidden

**Dependencies:** Blocked by: US-001

---

#### US-004: Switch Between Organizations

| Attribute | Value |
|-----------|-------|
| Epic | EP-01 |
| Priority | Must Have |
| Story Points | 2 |
| Sprint | Sprint 1 |
| Assigned To | builder agent |
| Status | Backlog |
| FR Reference | FR-003 |
| BR Reference | BR-007 |

**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:**
- [ ] **Given** user belongs to 3 organizations, **when** they click the org switcher in the sidebar, **then** all 3 organizations shown with current one highlighted
- [ ] **Given** user selects a different organization, **when** switched, **then** all data (invoices, expenses, reports) immediately reflects the new organization; URL updates to reflect active org

**Dependencies:** Blocked by: US-001, US-003

---

### Epic EP-02: Invoicing + SEF E-Invoicing

---

#### US-010: Create Invoice with PDV Auto-Calculation

| Attribute | Value |
|-----------|-------|
| Epic | EP-02: Invoicing + SEF E-Invoicing |
| Priority | Must Have |
| Story Points | 8 |
| Sprint | Sprint 2 |
| Assigned To | builder agent |
| Status | Backlog |
| FR Reference | FR-010 |
| BR Reference | BR-001, BR-002 |

**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:**
- [ ] **Given** authenticated user, **when** they open the invoice creation wizard and complete all 6 steps, **then** invoice saved as Draft with correct PDV (20% standard or 10% reduced per item)
- [ ] **Given** line item with unit_price 1000 RSD and PDV rate 20%, **when** user views invoice, **then** PDV = 200.0000 RSD, total = 1200.0000 RSD (NUMERIC precision)
- [ ] **Given** invoice with 3 line items at different PDV rates, **when** invoice created, **then** PDV breakdown shown per rate; total PDV is sum of all line-item PDV
- [ ] **Given** invoice saved as Draft, **when** user edits a line item quantity, **then** PDV and totals immediately recalculate

**Technical Notes:**
- All amounts: NUMERIC(19,4) — Prisma Decimal type
- PDV calculation: `pdv_amount = ROUND(base_amount * pdv_rate, 4)` — server-side only

**UI/UX Notes:**
- Screen: `/invoices/create` — 6-step wizard
- Step 3: line items with inline PDV calculation
- Step 5: invoice preview with all amounts

**Dependencies:**
- Blocked by: US-001 (auth)
- Blocks: US-011 (SEF submission)

---

#### US-011: Submit Invoice to SEF (Serbia)

| Attribute | Value |
|-----------|-------|
| Epic | EP-02 |
| Priority | Must Have |
| Story Points | 8 |
| Sprint | Sprint 2-3 |
| Assigned To | builder agent |
| Status | Backlog |
| FR Reference | FR-011 |
| BR Reference | BR-001 |

**Story:**
As a **Serbian B2B business owner**,
I want **Bilko to automatically submit my invoice to SEF when I send it**,
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:**
- [ ] **Given** user clicks "Send Invoice" on a Serbian B2B invoice, **when** send action executes, **then** UBL 2.1 XML generated and submitted to SEF within 10 seconds
- [ ] **Given** SEF accepts, **when** response received, **then** invoice SEF status = "Accepted"; SEF invoice ID stored; user notified in UI
- [ ] **Given** SEF rejects, **when** rejection received, **then** user sees rejection reason in Serbian; invoice status = "SEF Rejected"; user can correct and resubmit
- [ ] **Given** SEF API returns 503, **when** submission attempted, **then** queued 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 behind `apps/api/src/services/sef.service.ts`
- SEF credentials: per-organization, stored encrypted in DB

**Dependencies:** Blocked by: US-010

---

#### US-012: Track Invoice Payment

| Attribute | Value |
|-----------|-------|
| Epic | EP-02 |
| Priority | Must Have |
| Story Points | 3 |
| Sprint | Sprint 2 |
| Assigned To | builder agent |
| Status | Backlog |
| FR Reference | FR-012 |
| BR Reference | BR-001, BR-008 |

**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**.

**Acceptance Criteria:**
- [ ] **Given** invoice is Sent, **when** user marks as Paid with payment date, **then** status = Paid; double-entry transaction created (Debit bank, Credit accounts receivable)
- [ ] **Given** invoice due_date has passed and invoice is still Sent, **when** system runs daily check, **then** status = Overdue; user notified via in-app notification
- [ ] **Given** invoice list, **when** user filters by Overdue, **then** only overdue invoices shown

**Dependencies:** Blocked by: US-010

---

### Epic EP-03: Expense Tracking

---

#### US-020: Record Business Expense

| Attribute | Value |
|-----------|-------|
| Epic | EP-03: Expense Tracking |
| Priority | Must Have |
| Story Points | 5 |
| Sprint | Sprint 2 |
| Assigned To | builder agent |
| Status | Backlog |
| FR Reference | FR-020 |
| BR Reference | BR-009 |

**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**.

**Acceptance Criteria:**
- [ ] **Given** valid expense data (vendor, amount, category, date), **when** submitted, **then** expense saved; double-entry transaction created (Debit expense account, Credit payment account)
- [ ] **Given** expense in EUR with org base currency RSD, **when** created, **then** EUR amount stored + RSD equivalent calculated at locked exchange rate
- [ ] **Given** JPEG receipt (≤10MB) attached, **when** expense saved, **then** receipt stored and accessible from expense record
- [ ] **Given** expense list, **when** filtered by category "Putni troškovi", **then** only matching expenses shown

**Dependencies:** Blocked by: US-001

---

### Epic EP-04: Double-Entry Bookkeeping

---

#### US-030: View and Navigate Chart of Accounts

| Attribute | Value |
|-----------|-------|
| Epic | EP-04: Double-Entry Bookkeeping |
| Priority | Must Have |
| Story Points | 3 |
| Sprint | Sprint 1 |
| Assigned To | builder agent |
| Status | Backlog |
| FR Reference | FR-030 |
| BR Reference | BR-003, BR-010 |

**Story:**
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:**
- [ ] **Given** new Serbian org, **when** accountant opens `/settings/accounts`, **then** all 10 account classes (0-9) with Serbian standard accounts shown in hierarchical tree
- [ ] **Given** accountant adds sub-account "4111 — Dobavljači u zemlji" under class 411, **when** saved, **then** appears in account tree and is selectable in manual journal entries
- [ ] **Given** account has posted transactions, **when** user attempts to delete it, **then** deletion blocked; message explains account has transactions

**Dependencies:** Blocked by: US-001

---

#### US-031: View General Ledger (Knjiga)

| Attribute | Value |
|-----------|-------|
| Epic | EP-04 |
| Priority | Must Have |
| Story Points | 5 |
| Sprint | Sprint 3 |
| Assigned To | builder agent |
| Status | Backlog |
| FR Reference | FR-031 |
| BR Reference | BR-003 |

**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:**
- [ ] **Given** authenticated accountant, **when** opening journal ledger, **then** all transactions shown with date, description, debit account, credit account, amount
- [ ] **Given** journal entry, **when** expanded, **then** shows audit log (LoggedAction) of who created it and when
- [ ] **Given** any filter period, **when** sum of all debits calculated, **then** exactly 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

| Attribute | Value |
|-----------|-------|
| Epic | EP-05: Bank Reconciliation |
| Priority | Must Have |
| Story Points | 5 |
| Sprint | Sprint 3 |
| Assigned To | builder agent |
| Status | Backlog |
| FR Reference | FR-040 |
| BR Reference | BR-005 |

**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:**
- [ ] **Given** valid Serbian bank CSV (Raiffeisen format), **when** uploaded, **then** all transactions parsed and listed for review with amount, date, description
- [ ] **Given** bank transaction of 1200 RSD on 2026-03-05 matches an open invoice for 1200 RSD due on 2026-03-04, **when** parsed, **then** match suggested with 90% confidence
- [ ] **Given** unmatched transaction, **when** user categorizes manually (e.g., "Kirija — account 480"), **then** double-entry transaction created

**Dependencies:** Blocked by: US-010

---

### Epic EP-06: VAT/PDV Management

---

#### US-050: Generate Monthly PDV Report

| Attribute | Value |
|-----------|-------|
| Epic | EP-06: VAT/PDV Management |
| Priority | Must Have |
| Story Points | 8 |
| Sprint | Sprint 3 |
| Assigned To | builder agent |
| Status | Backlog |
| FR Reference | FR-050 |
| BR Reference | BR-002, BR-006 |

**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:**
- [ ] **Given** January 2026 selected, **when** PDV report generated, **then** all January invoices and expenses with PDV correctly aggregated; output PDV, input PDV, and net position shown
- [ ] **Given** standard PDV period, **when** export as PDF clicked, **then** PDF generated with all required fields per Poreska Uprava format
- [ ] **Given** zero PDV period (no PDV transactions), **when** report generated, **then** zero-value report generated (still legally required)
- [ ] **Given** reminder setting enabled, **when** 14th of month arrives, **then** in-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

| Attribute | Value |
|-----------|-------|
| Epic | EP-07: Financial Reports |
| Priority | Must Have |
| Story Points | 5 |
| Sprint | Sprint 3 |
| Assigned To | builder agent |
| Status | Backlog |
| FR Reference | FR-060 |
| BR Reference | BR-006 |

**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:**
- [ ] **Given** any date range (e.g., Q1 2026), **when** P&L generated, **then** all revenue accounts summed, all expense accounts summed, net profit calculated; matches double-entry ledger totals
- [ ] **Given** multi-currency org, **when** P&L generated in RSD, **then** all EUR/BAM transactions converted using locked historical exchange rates; totals in RSD
- [ ] **Given** P&L viewed, **when** user clicks on a revenue line, **then** drill-down shows individual transactions contributing to that amount

**Dependencies:** Blocked by: US-010, US-020

---

#### US-061: View Balance Sheet

| Attribute | Value |
|-----------|-------|
| Epic | EP-07 |
| Priority | Must Have |
| Story Points | 5 |
| Sprint | Sprint 4 |
| Assigned To | builder agent |
| Status | Backlog |
| FR Reference | FR-061 |
| BR Reference | BR-006 |

**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:**
- [ ] **Given** any date (e.g., 2026-03-31), **when** Balance Sheet generated, **then** Total Assets = Total Liabilities + Total Equity (double-entry invariant)
- [ ] **Given** any imbalance detected (should never happen), **when** Balance Sheet calculated, **then** alert 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

| Attribute | Value |
|-----------|-------|
| Epic | EP-08: Multi-Currency |
| Priority | Must Have |
| Story Points | 5 |
| Sprint | Sprint 2 |
| Assigned To | builder agent |
| Status | Backlog |
| FR Reference | FR-070 |
| BR Reference | BR-004 |

**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:**
- [ ] **Given** invoice created in EUR with 1 EUR = 117.5 RSD on 2026-03-01, **when** invoice saved, **then** EUR amount and 117.5 RSD rate locked; cannot be edited retroactively
- [ ] **Given** payment received 1 month later, **when** marked paid, **then** original locked rate used for P&L; exchange gain/loss calculated if payment at different rate
- [ ] **Given** ECB rate API unavailable, **when** user creates EUR invoice, **then** prompted to enter exchange rate manually; rate stored with "manual" flag

**Dependencies:** Blocked by: US-010

---

## 5. Story Estimation Guide

| Points | Complexity | Bilko Examples |
|--------|-----------|---------|
| 1 | Trivial | Update label text in Serbian, fix CSS spacing |
| 2 | Simple | Add filter to invoice list, format currency display |
| 3 | Moderate | Invoice status state machine, email notification |
| 5 | Complex | Invoice create wizard, expense form with double-entry |
| 8 | Very Complex | SEF submission service, PDV report generation |
| 13+ | Too Large | Break into sub-stories |

---

## 6. Definition of Ready Checklist

Before a story can enter a sprint:
- [ ] Story in As a / I want / So that format
- [ ] At least 2 acceptance criteria in Given/When/Then format
- [ ] Estimated in story points
- [ ] Dependencies identified and not blocking
- [ ] FR reference documented
- [ ] Accounting logic verified (for financial stories: double-entry, PDV, SEF)
- [ ] Story size ≤ 8 points

---

## 7. Story Mapping Visualization

```
USER JOURNEY: [Register] → [Create Invoice] → [Submit to SEF] → [Track Payment] → [Monthly PDV] → [P&L Report]

Phase 1 MVP:   US-001        US-010           US-011           US-012            US-050            US-060
               US-002        US-020 (Expense)                  US-040 (Bank)

Phase 2:       US-003        Croatian          eRačun            —                 HR VAT           Analytics
               (multi-org)   eRačun invoice    auto-submit
```

---

## 8. Backlog Summary

| Epic | Total Stories | Estimated Points | In Sprint | Done | Remaining |
|------|-------------|-----------------|-----------|------|-----------|
| EP-01: Auth & Org Setup | 4 | 15 | 0 | 0 | 15 |
| EP-02: Invoicing + SEF | 3 | 19 | 0 | 0 | 19 |
| EP-03: Expense Tracking | 1 | 5 | 0 | 0 | 5 |
| EP-04: Bookkeeping | 2 | 8 | 0 | 0 | 8 |
| EP-05: Bank Reconciliation | 1 | 5 | 0 | 0 | 5 |
| EP-06: VAT/PDV | 1 | 8 | 0 | 0 | 8 |
| EP-07: Reports | 2 | 10 | 0 | 0 | 10 |
| EP-08: Multi-Currency | 1 | 5 | 0 | 0 | 5 |
| **Total** | **15** | **75** | **0** | **0** | **75** |

**Velocity target:** 20 story points/sprint
**Projected completion:** Sprint 4 (8 weeks from 2026-02-23)

---

## Approval

| Role | Name | Date | Signature |
|------|------|------|-----------|
| Author | John (AI Director) | 2026-02-23 | |
| Reviewer | | | |
| Business Analyst | John | 2026-02-23 | |
| Product Owner | John | 2026-02-23 | |
| AI Director (John) | John | 2026-02-23 | |

# Acceptance Criteria

# Acceptance Criteria: Bilko

> **Project:** Bilko — Balkan Accounting SaaS
> **Version:** 0.1
> **Date:** 2026-02-23
> **Author:** John (AI Director)
> **Status:** Draft
> **Reviewers:** Alem Bašić (CEO)

## Document History
| Version | Date | Author | Changes |
|---------|------|--------|---------|
| 0.1     | 2026-02-23 | John (AI Director) | Initial draft — Phase 1 Serbia MVP |

---

## 1. Purpose & Methodology

### 1.1 What Are Acceptance Criteria?

Acceptance criteria are the conditions that the Bilko system must satisfy to be accepted as working correctly. They answer: **"How will we know when this feature is done?"**

For financial software, acceptance criteria are especially critical because errors have direct legal and financial consequences for users (SEF fines, incorrect PDV filings, balance sheet errors).

Good acceptance criteria are:
- **Testable** — Can be verified with a specific test procedure
- **Clear** — Unambiguous; no room for interpretation
- **Complete** — Cover happy path, error paths, and edge cases
- **Financially accurate** — For accounting features: verified against Balkan GAAP and tax law

### 1.2 Format: Given / When / Then (Gherkin-Style)

```
Given [an initial context / precondition that is true]
When  [an action or event occurs]
Then  [the expected outcome is observed]
And   [additional expected outcomes, chained]
```

### 1.3 Categories of Acceptance Criteria

| Category | Description | Example |
|----------|-------------|---------|
| **Positive (Happy Path)** | System works as expected with valid inputs | Invoice submitted to SEF successfully |
| **Negative (Sad Path)** | System handles invalid inputs gracefully | SEF rejects invoice — error shown |
| **Edge Case** | Boundary conditions | Zero-PDV invoice; zero-balance period |
| **Integration** | System works with external services | SEF API, exchange rate API |
| **Financial Accuracy** | Calculations correct per tax law | PDV = base × 0.20 exact to 4 decimal places |
| **Non-Functional** | Performance, accessibility, security | Invoice creation < 5s end-to-end |

---

## 2. Feature Acceptance Criteria

---

### Module: Authentication & User Management

---

#### Feature: User Registration (FR-001)

**Feature Description:** New users register with email/password and automatically get an organization with Serbian Chart of Accounts.
**Business Requirement:** BR-014
**Linked User Stories:** US-001

**Positive Scenarios:**

| # | Scenario | Given | When | Then |
|---|----------|-------|------|------|
| AC-001 | Successful registration | A new user with valid email "marko@firma.rs" and strong password | User submits form with org name "Firma d.o.o." | Account created; org created with Kontni Okvir pre-populated; verification email sent within 2 minutes |
| AC-002 | Email verification | Account just created | User clicks verification link (valid within 48h) | Email confirmed; user redirected to organization dashboard |
| AC-003 | Chart of Accounts pre-populated | New organization created | User opens /settings/accounts | All 10 account classes (0-9) visible with standard Serbian accounts |

**Negative Scenarios:**

| # | Scenario | Given | When | Then |
|---|----------|-------|------|------|
| AC-004 | Duplicate email | Account already exists for marko@firma.rs | User submits registration with same email | Error "Nalog sa ovim emailom već postoji"; no account created |
| AC-005 | Weak password | User is on registration form | User submits password "abc123" (no uppercase/special) | Inline error shown before form submission; form not submitted |
| AC-006 | Invalid email format | User is on registration form | User submits "notanemail" as email | Inline validation error shown |

**Edge Cases:**

| # | Scenario | Given | When | Then |
|---|----------|-------|------|------|
| AC-007 | Verification link expiry | Verification link generated 49+ hours ago | User clicks expired link | Error "Link je istekao"; option to resend verification shown |
| AC-008 | Double registration attempt | User submits form twice rapidly | Two identical POST requests within 1 second | Only one account created; second returns appropriate error |

**Non-Functional Acceptance Criteria:**

| # | Category | Criterion |
|---|----------|-----------|
| AC-009 | Performance | Registration + org creation + CoA seeding completes in < 3 seconds |
| AC-010 | Security | Password stored as bcrypt hash (cost 12+); never in plaintext logs |

---

#### Feature: User Login (FR-002)

**Feature Description:** Authenticated users log in with email and password.
**Business Requirement:** BR-014
**Linked User Stories:** US-002

**Positive Scenarios:**

| # | Scenario | Given | When | Then |
|---|----------|-------|------|------|
| AC-020 | Successful login | Verified user with valid credentials | User submits login form | Authenticated; access token (15min) + refresh token (30d) set; redirected to dashboard |
| AC-021 | Silent token refresh | User's access token expired; refresh token valid | User makes API call | New access token issued silently; user not logged out; original request succeeds |

**Negative Scenarios:**

| # | Scenario | Given | When | Then |
|---|----------|-------|------|------|
| AC-022 | Wrong password | Registered user exists | User submits wrong password | Generic error "Pogrešan email ili lozinka" (no user enumeration) |
| AC-023 | Non-existent email | No account for this email | User submits login | Same generic error "Pogrešan email ili lozinka" |
| AC-024 | Account locked | 5 failed attempts within 15 minutes | 6th attempt | Error "Nalog zaključan. Pokušajte za 15 minuta." |
| AC-025 | Unverified account | Account created but email not verified | User attempts login | Error "Molimo vas potvrdite email adresu" with option to resend |

**Edge Cases:**

| # | Scenario | Given | When | Then |
|---|----------|-------|------|------|
| AC-026 | Session expiry | User idle for 30+ minutes; access token expired; refresh token also expired | User attempts action | Redirected to login; message "Vaša sesija je istekla" |

---

### Module: Invoicing

---

#### Feature: Create Invoice with PDV (FR-010)

**Feature Description:** Create invoices with auto-PDV calculation. Financial accuracy is critical — NUMERIC(19,4) precision required.
**Business Requirement:** BR-001, BR-002
**Linked User Stories:** US-010

**Positive Scenarios:**

| # | Scenario | Given | When | Then |
|---|----------|-------|------|------|
| AC-030 | Invoice with 20% PDV | Line item: 1000.0000 RSD base, 20% PDV rate | Invoice created and viewed | PDV amount = 200.0000 RSD; total = 1200.0000 RSD exactly (NUMERIC precision) |
| AC-031 | Invoice with 10% PDV | Line item: 500.0000 RSD base, 10% PDV rate | Invoice created | PDV = 50.0000 RSD; total = 550.0000 RSD |
| AC-032 | Multi-line invoice with mixed PDV rates | 3 line items: 1000 @ 20%, 500 @ 10%, 200 @ 0% | Invoice created | PDV breakdown shown per rate; total PDV = 250.0000 RSD; grand total = 1950.0000 RSD |
| AC-033 | Invoice saved as Draft | All required fields filled | User clicks "Save Draft" | Invoice in Draft status; not submitted to SEF; can be edited |
| AC-034 | Invoice number sequential | Previous invoice number: INV-2026-001 | New invoice created | Invoice number: INV-2026-002 (no gaps) |

**Negative Scenarios:**

| # | Scenario | Given | When | Then |
|---|----------|-------|------|------|
| AC-035 | Missing required field | Invoice wizard open | User tries to advance without selecting client | Inline error "Odaberite klijenta"; cannot advance to next step |
| AC-036 | Zero-amount invoice | User enters 0 for all line item prices | User tries to save | Validation error "Iznos fakture mora biti veći od 0" |
| AC-037 | Due date before invoice date | Invoice date: 2026-03-01, due date: 2026-02-28 | User saves invoice | Validation error "Rok plaćanja mora biti nakon datuma fakture" |

**Edge Cases:**

| # | Scenario | Given | When | Then |
|---|----------|-------|------|------|
| AC-038 | PDV rounding edge case | Line item: 333.3333 RSD, 20% PDV | Invoice calculated | PDV = 66.6667 RSD (ROUND to 4 decimal places, not truncate); total = 400.0000 RSD |
| AC-039 | PDV-exempt invoice (0%) | Business in PDV exemption regime | Invoice created with 0% PDV | PDV amount = 0.0000; total = base amount; PDV field shows "PDV 0%" with exemption reason |

**Financial Accuracy Criteria:**

| # | Category | Criterion |
|---|----------|-----------|
| AC-040 | NUMERIC precision | All PDV and total amounts stored as NUMERIC(19,4) — verified in DB; no floating point |
| AC-041 | PDV law compliance | PDV calculation matches Zakon o PDV Art. 17 — base × rate formula verified for 20 test cases |

---

#### Feature: SEF E-Invoice Submission (FR-011)

**Feature Description:** Automatic submission of Serbian B2B invoices to efaktura.gov.rs.
**Business Requirement:** BR-001
**Linked User Stories:** US-011

**Positive Scenarios:**

| # | Scenario | Given | When | Then |
|---|----------|-------|------|------|
| AC-050 | Successful SEF submission | Serbian B2B invoice, organization has SEF credentials | User clicks "Pošalji fakturu" | UBL 2.1 XML generated and submitted to SEF within 10 seconds; SEF status = "Prihvaćeno"; SEF invoice ID stored |
| AC-051 | SEF status visible | Invoice submitted to SEF | User views invoice detail | SEF status shown: "Prihvaćeno" + SEF invoice ID |

**Negative Scenarios:**

| # | Scenario | Given | When | Then |
|---|----------|-------|------|------|
| AC-052 | SEF rejects — missing buyer PIB | Invoice created without buyer's PIB (tax ID) | Submission attempted | SEF rejection error shown in Serbian: reason from SEF response; invoice status = "SEF Odbijeno"; user can edit and resubmit |
| AC-053 | SEF API unavailable (503) | SEF platform returns 503 | Submission attempted | Invoice queued for retry; user notified "Faktura je u redu čekanja za SEF. Prosleđivanje za max 30 minuta."; max 3 retries |

**Edge Cases:**

| # | Scenario | Given | When | Then |
|---|----------|-------|------|------|
| AC-054 | Duplicate SEF submission attempt | Invoice already submitted and Accepted | User somehow triggers send again | System detects SEF invoice ID exists; blocks resubmission; shows "Faktura je već prosleđena SEF-u" |
| AC-055 | B2C invoice (no SEF required) | Invoice for individual (no PIB) | User sends | PDF emailed; SEF submission skipped; no SEF status shown |

---

#### Feature: Invoice Payment Tracking (FR-012)

**Linked User Stories:** US-012

**Positive Scenarios:**

| # | Scenario | Given | When | Then |
|---|----------|-------|------|------|
| AC-060 | Mark invoice paid | Invoice status = Sent | User marks as paid with date 2026-03-15 and amount 1200 RSD | Status = Paid; double-entry: Debit 1200 (110 — tekući račun), Credit 1200 (200 — potraživanja); payment date recorded |
| AC-061 | Overdue detection | Invoice due 2026-03-14; today is 2026-03-15; status = Sent | System daily check runs | Status automatically changes to Overdue; in-app notification sent |

**Negative Scenarios:**

| # | Scenario | Given | When | Then |
|---|----------|-------|------|------|
| AC-062 | Mark paid with wrong amount | Invoice total = 1200 RSD | User marks paid with amount 1000 RSD | Warning: "Plaćeni iznos (1.000 RSD) je manji od iznosa fakture (1.200 RSD). Potvrdi parcijalno plaćanje." |

---

### Module: Expense Tracking

---

#### Feature: Create Expense (FR-020)

**Feature Description:** Record business expenses with double-entry auto-creation.
**Business Requirement:** BR-009
**Linked User Stories:** US-020

**Positive Scenarios:**

| # | Scenario | Given | When | Then |
|---|----------|-------|------|------|
| AC-070 | Record expense with double-entry | Expense: 5000 RSD, category "Kirija" (account 480), paid from tekući račun (110) | User submits expense | Expense saved; Transaction: Debit 5000 (480 — Expenses), Credit 5000 (110 — Bank); LoggedAction entry created |
| AC-071 | Receipt attachment | Expense saved | User attaches JPEG receipt (3MB) | Receipt stored; accessible from expense record; thumbnail shown |

**Negative Scenarios:**

| # | Scenario | Given | When | Then |
|---|----------|-------|------|------|
| AC-072 | Receipt too large | User attaches 15MB PDF | Upload attempted | Error "Dokument ne može biti veći od 10MB" |
| AC-073 | Future date expense | User enters expense date 2027-01-01 | Form submitted | Warning "Datum troška je u budućnosti. Potvrdi unos." — requires explicit confirmation |

---

### Module: VAT/PDV Management

---

#### Feature: PDV Report Generation (FR-050)

**Feature Description:** Monthly PDV report aggregating all sales and purchase PDV. Critical for legal compliance.
**Business Requirement:** BR-002, BR-006
**Linked User Stories:** US-050

**Positive Scenarios:**

| # | Scenario | Given | When | Then |
|---|----------|-------|------|------|
| AC-080 | January PDV report | January 2026: 3 invoices (PDV 600+400+200=1200 RSD), 2 expenses (input PDV 240+120=360 RSD) | User generates January PDV report | Output PDV = 1200 RSD; Input PDV = 360 RSD; Net PDV payable = 840 RSD |
| AC-081 | PDV report PDF export | PDV report generated | User clicks "Exportuj PDF" | PDF with header "PDV Prijava — Januar 2026", org name, PIB, all amounts per official format |
| AC-082 | Zero PDV period | December: no PDV transactions | User generates December PDV report | Zero-value report generated with all fields = 0; exportable (still legally required) |

**Financial Accuracy Criteria:**

| # | Category | Criterion |
|---|----------|-----------|
| AC-083 | PDV accuracy | PDV report totals verified against sum of all invoice/expense PDV fields in DB — must match to 4 decimal places |
| AC-084 | PDV law compliance | Output PDV = sum of all 20% standard + sum of all 10% reduced PDV from outgoing invoices per Zakon o PDV |

---

## 3. Integration Scenarios

| # | Integration | Scenario | Expected Behavior | Test Environment |
|---|------------|---------|------------------|-----------------|
| INT-001 | SEF API (efaktura.gov.rs) | Valid invoice submission | SEF returns invoice ID + "Accepted" status within 30s | SEF sandbox |
| INT-002 | SEF API | Invalid invoice (missing buyer PIB) | SEF returns rejection with specific reason code | SEF sandbox |
| INT-003 | SEF API | SEF unavailable (503) | Bilko queues submission; retries 3× with exponential backoff; user notified | Mocked 503 |
| INT-004 | Email provider | Invoice PDF delivery | Recipient receives PDF invoice within 2 minutes of send | Mailtrap / staging |
| INT-005 | Exchange rate API (ECB) | EUR/RSD rate fetch | Rate fetched and cached; used for multi-currency invoice | ECB test endpoint |
| INT-006 | Exchange rate API | API unavailable | Cached rate (< 24h) used; if no cache, user prompted for manual entry | Mocked timeout |
| INT-007 | SEF API | SEF credentials invalid | Error shown to user: "SEF akreditivi su nevalidni. Proveri podešavanja." | SEF sandbox |

---

## 4. Non-Functional Acceptance Criteria

### 4.1 Performance

| # | Criterion | Target | Test Method |
|---|-----------|--------|-------------|
| NF-AC-001 | Dashboard initial load | < 3 seconds (4G) | Lighthouse on staging |
| NF-AC-002 | Dashboard subsequent navigation | < 1 second | Lighthouse warm cache |
| NF-AC-003 | Invoice creation (full wizard + API save) | < 5 seconds end-to-end | Manual timing + k6 |
| NF-AC-004 | SEF submission (Bilko to SEF confirmation) | < 30 seconds | E2E test in SEF sandbox |
| NF-AC-005 | PDV report generation (1 year of data) | < 5 seconds | Load test with synthetic data |

### 4.2 Accessibility

| # | Criterion | Target | Test Method |
|---|-----------|--------|-------------|
| NF-AC-010 | No critical accessibility violations | 0 critical violations | axe-core on all pages |
| NF-AC-011 | Invoice wizard keyboard navigation | Complete wizard without mouse | Manual keyboard test |
| NF-AC-012 | Color contrast | ≥ 4.5:1 (normal text), ≥ 3:1 (large text) | Contrast checker — Bilko #00E5A0 on dark verified |

### 4.3 Security

| # | Criterion | Target | Test Method |
|---|-----------|--------|-------------|
| NF-AC-020 | Organization data isolation | User from Org A cannot access Org B data | API test: send request with Org A token for Org B resource — must return 403 |
| NF-AC-021 | No financial data in client-side logs | No amounts, invoices, or PII in browser console | Manual browser DevTools review |
| NF-AC-022 | Input injection prevention | No SQL/XSS injection vulnerabilities | OWASP ZAP + Snyk SAST |
| NF-AC-023 | SEF credentials encrypted | SEF API keys not stored in plaintext in DB | DB inspection + code review |

### 4.4 Financial Accuracy

| # | Criterion | Target | Test Method |
|---|-----------|--------|-------------|
| NF-AC-030 | Debit = Credit invariant | Sum of all debits = sum of all credits across ALL transactions | Automated DB check in CI: `SELECT SUM(debit_amount) - SUM(credit_amount) FROM transactions` must = 0 |
| NF-AC-031 | NUMERIC precision | Zero floating point errors in PDV and totals | 1000 PDV calculations with known expected values; compare to NUMERIC result |
| NF-AC-032 | Exchange rate immutability | Changing today's rate does not affect historical transactions | Create transaction, change rate, verify transaction amount unchanged |

---

## 5. UAT Scenario Mapping

| AC ID | AC Description | UAT Scenario ID | UAT Tester | Status |
|-------|---------------|-----------------|-----------|--------|
| AC-001 | Successful registration | UAT-001 | Beta SMB owner | Not Started |
| AC-030 | Invoice PDV 20% calculation | UAT-010 | Beta accountant | Not Started |
| AC-050 | SEF submission success | UAT-020 | Beta SMB owner | Not Started |
| AC-080 | PDV report generation | UAT-030 | Beta accountant | Not Started |
| NF-AC-030 | Debit = Credit invariant | UAT-ACC-001 | Beta accountant | Not Started |
| NF-AC-001 | Dashboard load < 3s | UAT-P01 | Any beta user | Not Started |

---

## 6. Traceability to Requirements

| AC ID | Acceptance Criterion | FR Reference | BR Reference | US Reference |
|-------|---------------------|-------------|-------------|-------------|
| AC-001 | Successful registration | FR-001 | BR-014 | US-001 |
| AC-020 | Successful login | FR-002 | BR-014 | US-002 |
| AC-030 | Invoice PDV 20% | FR-010 | BR-002 | US-010 |
| AC-050 | SEF submission success | FR-011 | BR-001 | US-011 |
| AC-060 | Mark invoice paid | FR-012 | BR-001 | US-012 |
| AC-070 | Record expense | FR-020 | BR-009 | US-020 |
| AC-080 | PDV report January | FR-050 | BR-002, BR-006 | US-050 |

> Full traceability: [`RTM.md`](RTM.md)

---

## Approval

| Role | Name | Date | Signature |
|------|------|------|-----------|
| Author | John (AI Director) | 2026-02-23 | |
| Reviewer | | | |
| Business Analyst | John | 2026-02-23 | |
| Product Owner | John | 2026-02-23 | |
| QA Engineer | validator agent | | |
| AI Director (John) | John | 2026-02-23 | |
| CEO (Alem) | Alem Bašić | | |

# Requirements Traceability Matrix (RTM)

# Requirements Traceability Matrix (RTM): Bilko

> **Project:** Bilko — Balkan Accounting SaaS
> **Version:** 0.1
> **Date:** 2026-02-23
> **Author:** John (AI Director)
> **Status:** Draft
> **Reviewers:** Alem Bašić (CEO)

## Document History
| Version | Date | Author | Changes |
|---------|------|--------|---------|
| 0.1     | 2026-02-23 | John (AI Director) | Initial draft — Phase 1 Serbia MVP |

---

## 1. Purpose of Traceability

The Requirements Traceability Matrix serves four functions for Bilko:

1. **Coverage Assurance** — Every business requirement (BR) has an implementation path (FR, US) and test cases (AC, TC)
2. **Change Impact** — When a regulatory requirement changes (e.g., SEF API update), quickly identify all affected code and tests
3. **Gap Detection** — Identify FRs with no tests (coverage gap) or tests with no requirement (potential scope creep)
4. **Compliance Audit** — Demonstrates to auditors that SEF, PDV, and accounting law requirements are implemented and verified

**Traceability Directions:**
- **Forward Traceability** — BR → FR → Code → Test (did we build what was required by law and stakeholders?)
- **Backward Traceability** — Test → Code → FR → BR (does everything we built have a legal or business justification?)

---

## 2. Document References

| Document | Location | Version | Last Updated |
|----------|----------|---------|-------------|
| Business Requirements Document (BRD) | [`BRD.md`](BRD.md) | 0.1 | 2026-02-23 |
| Functional Requirements Spec (FRS) | [`FUNCTIONAL-REQUIREMENTS.md`](FUNCTIONAL-REQUIREMENTS.md) | 0.1 | 2026-02-23 |
| Non-Functional Requirements | [`NON-FUNCTIONAL-REQUIREMENTS.md`](NON-FUNCTIONAL-REQUIREMENTS.md) | 0.1 | 2026-02-23 |
| User Stories | [`USER-STORIES.md`](USER-STORIES.md) | 0.1 | 2026-02-23 |
| Acceptance Criteria | [`ACCEPTANCE-CRITERIA.md`](ACCEPTANCE-CRITERIA.md) | 0.1 | 2026-02-23 |
| Risk Register | [`../governance/RISK-REGISTER.md`](../governance/RISK-REGISTER.md) | 0.1 | 2026-02-23 |
| Test Plan | [`../TEST-PLAN.md`](../TEST-PLAN.md) | 0.1 | 2026-02-23 |
| Database Schema | [`../../packages/database/prisma/schema.prisma`](../../packages/database/prisma/schema.prisma) | Current | 2026-02-20 |

---

## 3. Forward Traceability Matrix

### 3.1 Functional Requirements Traceability

| BR ID | Business Requirement | FR ID | Functional Requirement | US ID | DB Model | Code Module | Unit Test | Integration Test | AC ID | Status |
|-------|---------------------|-------|----------------------|-------|----------|-------------|-----------|-----------------|-------|--------|
| BR-001 | SEF e-invoice submission | FR-010 | Create Invoice | US-010 | Invoice, InvoiceItem | `apps/api/src/routes/invoices.ts` | ❌ | ❌ | AC-030 | ❌ Not Started |
| BR-001 | SEF e-invoice submission | FR-011 | SEF Submission | US-011 | Invoice (sef_status, sef_id) | `apps/api/src/services/sef.service.ts` | ❌ | ❌ | AC-050 | ❌ Not Started |
| BR-001 | SEF e-invoice submission | FR-012 | Invoice Status Tracking | US-012 | Invoice (status) | `apps/api/src/routes/invoices.ts` | ❌ | ❌ | AC-060 | ❌ Not Started |
| BR-002 | PDV auto-calculation | FR-010 | Create Invoice (PDV) | US-010 | InvoiceItem (vat_amount) | `apps/api/src/services/tax.service.ts` | ❌ | ❌ | AC-030, AC-038 | ❌ Not Started |
| BR-002 | PDV auto-calculation | FR-050 | PDV Report | US-050 | Invoice, Expense | `apps/api/src/routes/reports.ts` | ❌ | ❌ | AC-080, AC-083 | ❌ Not Started |
| BR-003 | Double-entry bookkeeping | FR-031 | Transaction Recording | US-031 | Transaction | `apps/api/src/services/accounting.service.ts` | ❌ | ❌ | NF-AC-030 | ❌ Not Started |
| BR-004 | Multi-currency | FR-070 | Exchange Rate Management | US-070 | Currency, ExchangeRate | `apps/api/src/services/currency.service.ts` | ❌ | ❌ | AC-032, NF-AC-032 | ❌ Not Started |
| BR-005 | Bank statement import | FR-040 | CSV Import | US-040 | BankTransaction | `apps/api/src/routes/banking.ts` | ❌ | ❌ | AC-070 (extended) | ❌ Not Started |
| BR-006 | Financial reports | FR-060 | P&L Statement | US-060 | Transaction, Account | `apps/api/src/routes/reports.ts` | ❌ | ❌ | — | ❌ Not Started |
| BR-006 | Financial reports | FR-061 | Balance Sheet | US-061 | Transaction, Account | `apps/api/src/routes/reports.ts` | ❌ | ❌ | NF-AC-030 | ❌ Not Started |
| BR-007 | Multi-user RBAC | FR-003 | Invite User | US-003, US-004 | User, Organization (RBAC) | `apps/api/src/middleware/auth.ts` | ❌ | ❌ | AC-001 (ext) | ❌ Not Started |
| BR-008 | PDF invoice + email | FR-010 | Invoice PDF delivery | US-010 | Invoice | `apps/api/src/services/email.service.ts` | ❌ | ❌ | INT-004 | ❌ Not Started |
| BR-009 | Expense tracking | FR-020 | Create Expense | US-020 | Expense | `apps/api/src/routes/expenses.ts` | ❌ | ❌ | AC-070 | ❌ Not Started |
| BR-010 | Chart of Accounts | FR-030 | Chart of Accounts | US-030 | Account, AccountType | `apps/api/src/services/accounts.service.ts` | ❌ | ❌ | AC-003, AC-039 | ❌ Not Started |
| BR-011 | Serbian language | N/A | i18n / l10n (frontend) | N/A | N/A | `apps/web/lib/i18n/` | ❌ | ❌ | — | ❌ Not Started |
| BR-012 | Immutable audit trail | FR-031 | LoggedAction (all mutations) | US-031 | LoggedAction | `apps/api/src/middleware/audit.ts` | ❌ | ❌ | — | ❌ Not Started |
| BR-013 | Data export (GDPR) | N/A | Export API endpoint | N/A | All models | `apps/api/src/routes/export.ts` | ❌ | ❌ | — | ❌ Not Started |
| BR-014 | Secure multi-tenancy | FR-001, FR-002 | Auth (register/login) | US-001, US-002 | User, Organization | `apps/api/src/routes/auth.ts` | ✅ | ✅ | AC-001, AC-020 | ✅ Complete |

> Note: BR-014 Auth endpoints are the only complete items — 4/50 auth endpoints built (2026-02-20).

### 3.2 Non-Functional Requirements Traceability

| NFR ID | Requirement | Target | Test Type | Test Case ID | Status |
|--------|------------|--------|-----------|-------------|--------|
| NFR-P01 | Dashboard load < 3s initial | < 3s (4G) | Performance | PERF-001 | ❌ Not Started |
| NFR-P02 | Dashboard < 1s subsequent | < 1s warm cache | Performance | PERF-002 | ❌ Not Started |
| NFR-P04 | API response < 300ms | p95 < 300ms | Performance | PERF-003 | ❌ Not Started |
| NFR-SEC01 | JWT authentication | 15min access + 30d refresh | Security | SEC-001 | ✅ Complete (auth built) |
| NFR-SEC06 | Input validation (Zod) | All inputs validated server-side | Security / SAST | SEC-010 | ⏳ In Progress |
| NFR-SEC10 | Org data isolation | No cross-tenant access | Security | SEC-020 | ⏳ In Progress (middleware built) |
| NFR-R02 | ACID compliance | 100% ACID transactions | Database | DB-001 | ⏳ In Progress (PostgreSQL + Prisma) |
| NFR-R03 | Double-entry balance | Debit = Credit always | Database / CI | DB-002 | ❌ Not Started |
| NFR-D01 | NUMERIC(19,4) monetary | No float for money | Database | DB-010 | ✅ Complete (schema enforced) |
| NFR-COMP01 | SEF e-invoicing compliance | 100% UBL 2.1 | Compliance | COMP-001 | ❌ Not Started |
| NFR-COMP02 | PDV compliance | Correct PDV rates | Compliance | COMP-002 | ❌ Not Started |
| NFR-COMP04 | GDPR compliance | Right to deletion; export | Compliance | COMP-010 | ❌ Not Started |
| NFR-U03 | WCAG 2.1 AA | Level AA | Accessibility | A11Y-001 | ❌ Not Started |
| NFR-A01 | Uptime ≥ 99.9% | 99.9% monthly | Operations | OPS-001 | N/A (pre-launch) |

---

## 4. Backward Traceability Matrix

| Test Case ID | Test Description | AC ID | FR ID | BR ID | Has Requirement? |
|-------------|-----------------|-------|-------|-------|-----------------|
| TC-AUTH-001 | User registration flow | AC-001 | FR-001 | BR-014 | ✅ Yes |
| TC-AUTH-002 | Login with JWT | AC-020 | FR-002 | BR-014 | ✅ Yes |
| TC-AUTH-003 | Token refresh | AC-021 | FR-002 | BR-014 | ✅ Yes |
| TC-AUTH-004 | Account lockout (5 attempts) | AC-024 | FR-002 | BR-014 | ✅ Yes |
| TC-INV-001 | Invoice PDV 20% calculation | AC-030 | FR-010 | BR-002 | ✅ Yes |
| TC-INV-002 | Invoice PDV 10% calculation | AC-031 | FR-010 | BR-002 | ✅ Yes |
| TC-INV-003 | NUMERIC precision (no float) | AC-040, NF-AC-031 | FR-010 | BR-002 | ✅ Yes |
| TC-SEF-001 | SEF UBL 2.1 submission | AC-050 | FR-011 | BR-001 | ✅ Yes |
| TC-SEF-002 | SEF rejection handling | AC-052 | FR-011 | BR-001 | ✅ Yes |
| TC-SEF-003 | SEF unavailable — queue | AC-053 | FR-011 | BR-001 | ✅ Yes |
| TC-ACC-001 | Debit = Credit balance check | NF-AC-030 | FR-031 | BR-003 | ✅ Yes |
| TC-ACC-002 | Exchange rate immutability | NF-AC-032 | FR-070 | BR-004 | ✅ Yes |
| TC-PDV-001 | Monthly PDV report accuracy | AC-080, AC-083 | FR-050 | BR-002, BR-006 | ✅ Yes |
| TC-SEC-001 | Cross-tenant data isolation | NF-AC-020 | N/A | BR-014 | ✅ Yes |

---

## 5. Coverage Analysis

### 5.1 Requirement Coverage Summary

| Category | Total Count | Fully Covered | Partially Covered | Not Covered | Coverage % |
|----------|-------------|--------------|-------------------|-------------|-----------|
| Business Requirements (BR) | 14 | 1 (BR-014 auth) | 3 (schema, middleware) | 10 | 7% |
| Functional Requirements (FR) | 14 | 2 (FR-001, FR-002) | 2 (FR-003, FR-030) | 10 | 14% |
| Non-Functional Requirements (NFR) | 30 | 5 | 4 | 21 | 17% |
| User Stories (US) | 15 | 2 (US-001, US-002) | 0 | 13 | 13% |
| Acceptance Criteria (AC) | 40+ | 0 (all Draft) | 0 | 40 | 0% |

**Overall Requirement Coverage:** ~7% (project in early development phase — backend 4/50 endpoints complete)
**Target:** ≥ 95% before UAT (estimated Sprint 4); 100% before production release

> This is expected at current stage. Backend foundation complete (auth, middleware, DB schema). 46 API endpoints remaining.

### 5.2 Test Coverage Summary

| Test Type | Total Tests | Passing | Failing | Skipped | Coverage |
|-----------|------------|---------|---------|---------|----------|
| Unit tests | 0 (not yet written) | 0 | 0 | 0 | 0% |
| Integration tests | 4 (auth endpoints) | 4 | 0 | 0 | auth only |
| E2E / UAT scenarios | 0 | 0 | 0 | 0 | 0% |
| Performance tests | 0 | — | — | — | 0% |
| Security tests | 0 | — | — | — | 0% |

> Test coverage target: ≥ 80% overall, ≥ 95% for financial logic (double-entry, PDV, SEF) before launch.

---

## 6. Gap Identification

### 6.1 Requirements Without Test Coverage (All Phase 1 Non-Auth)

| Requirement ID | Description | Gap Type | Action Required | Owner | Target Date |
|---------------|-------------|----------|----------------|-------|-------------|
| BR-001 | SEF e-invoicing | No tests for SEF integration | Create TC-SEF-001 through TC-SEF-003 | John | 2026-03-21 (SEF integration sprint) |
| BR-002 | PDV calculation | No tests for PDV accuracy | Create TC-INV-001 through TC-INV-003; verify against Zakon o PDV | John | 2026-03-14 |
| BR-003 | Double-entry | No tests for accounting balance | Create TC-ACC-001; CI balance check | John | 2026-03-07 |
| FR-050 | PDV Report | No implementation yet | Build + test in Sprint 3 | builder agent | 2026-03-21 |
| FR-060 | P&L Statement | No implementation yet | Build + test in Sprint 3 | builder agent | 2026-03-21 |
| NFR-D01 | NUMERIC precision | Schema enforced but no test | Add TC-INV-003 decimal precision test | John | 2026-03-07 |

### 6.2 Test Cases Without Requirements (Orphans)

| Test Case ID | Description | Status | Action |
|-------------|-------------|--------|--------|
| — | No orphaned tests at this stage | N/A | N/A |

### 6.3 Requirements Without Design Reference

| Requirement ID | Description | Action |
|---------------|-------------|--------|
| FR-011 | SEF Submission UI (status display) | Existing invoice detail page — update to show SEF status field |
| FR-040 | Bank CSV Import UI | New page `/banking` — existing placeholder page needs implementation |
| FR-050 | PDV Report page | Existing `/reports/vat` placeholder — needs full implementation |

---

## 7. Change Impact Tracking

| Change Request ID | Changed Requirement | Impact on FR | Impact on Code | Impact on Tests | Impact Assessment | CR Status |
|-----------------|--------------------|--------------|--------------|-----------------|--------------------|-----------|
| — | No change requests at this stage | — | — | — | — | — |

**Key anticipated change risk:**
If SEF API changes (Risk R-001 in risk register), the following would need updating:
- FR-011 (SEF submission logic)
- `apps/api/src/services/sef.service.ts`
- TC-SEF-001, TC-SEF-002, TC-SEF-003
- UBL 2.1 XML generation templates
- AC-050, AC-052, AC-054

---

## 8. Traceability Status Dashboard

**Last Updated:** 2026-02-23
**Updated By:** John (AI Director)

| Metric | Value | Target | Status |
|--------|-------|--------|--------|
| Total Business Requirements | 14 | — | |
| BRs with FR coverage | 14 / 14 | 100% | ✅ All mapped |
| FRs with test coverage | 2 / 14 | 100% | ❌ In progress |
| Test cases passing | 4 / 4 (auth only) | 100% | ✅ (auth only) |
| Open gaps | 11 FRs untested | 0 at launch | ❌ Expected at this stage |
| Change requests open | 0 | ≤ 3 at a time | ✅ |
| UAT sign-off pending | 0 (pre-launch) | 0 at launch | N/A |

**Overall RTM Health:** AMBER — Expected for current development phase. All requirements defined and mapped to code modules. Test coverage to be built alongside each feature in Sprints 2-4.

---

## Approval

| Role | Name | Date | Signature |
|------|------|------|-----------|
| Author | John (AI Director) | 2026-02-23 | |
| Reviewer | | | |
| Business Analyst | John | 2026-02-23 | |
| QA Engineer | validator agent | | |
| Tech Lead | John | 2026-02-23 | |
| AI Director (John) | John | 2026-02-23 | |