Acceptance Criteria
Acceptance Criteria: 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. 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 "[email protected]" 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 [email protected] | 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
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ć |