Functional Requirements Specification
Functional Requirements Specification (FRS): Bilko
Project: Bilko — Balkan Accounting SaaS Version: 1.0 Date: 2026-02-25 Author: John (AI Director) Status: Final 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.0 | 2026-02-25 | John (AI Director) | Finalized for v1.0 release |
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:
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
⚠️ SUPERSEDED (2026-06-25). Email/password registration is RETIRED. Auth is Microsoft Entra External ID (CIAM) SSO only — the email/password endpoints return HTTP 410 (
AuthRoutes.kt~242/254). New users are provisioned via Entra JIT on first SSO login, or via the FR-003 tokenized invite flow (/accept-invite→ Entra SSO). The criteria below (password complexity, verification email) DO NOT apply. Retained for historical trace only.
| 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
⚠️ SUPERSEDED (2026-06-25). Email/password login is RETIRED (HTTP 410). Login is Microsoft Entra External ID (CIAM) SSO only —
/logintriggerssignInWithMicrosoft()→*.ciamlogin.com; backend issues the session from the Entra id_token (AuthService.createSessionFromEntraIdToken). The email/password criteria below DO NOT apply. Retained for historical trace only.
| 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 [email protected] 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
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 | SUPERSEDED — Entra SSO/JIT + FR-003 invite (email/pw retired, 410) | BR-014 |
| FR-002 | User Login | Authentication | Must Have | SUPERSEDED — Entra CIAM SSO only (email/pw retired, 410) | BR-014 |
| FR-003 | Invite User to Organization | Authentication | Must Have | Not Started | BR-007 |
| FR-010 | Create Invoice | Invoicing | Must Have | Not Started | BR-001, BR-002, BR-004, BR-008 |
| FR-011 | SEF E-Invoice Submission | Invoicing | Must Have | Not Started | BR-001 |
| FR-012 | Track Invoice Status | Invoicing | Must Have | Not Started | BR-001, BR-008 |
| FR-020 | Create Expense | Expenses | Must Have | Not Started | BR-009 |
| FR-030 | Chart of Accounts | Bookkeeping | Must Have | Not Started | BR-003, BR-010 |
| FR-031 | Double-Entry Transaction Recording | Bookkeeping | Must Have | Not Started | BR-003 |
| FR-040 | Bank Statement CSV Import | Banking | Must Have | Not Started | BR-005 |
| FR-050 | PDV Report Generation | VAT/PDV | Must Have | Not Started | BR-002, BR-006 |
| FR-060 | P&L Statement | Reports | Must Have | Not Started | BR-006 |
| FR-061 | Balance Sheet | Reports | Must Have | Not Started | BR-006 |
| FR-070 | Exchange Rate Management | Multi-Currency | Must Have | Not Started | 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
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ć |
No comments to display
No comments to display