Functional Requirements Specification (FRS): Drop — Fintech Payment App
Functional Requirements Specification (FRS): Drop — Fintech Payment App
Project: Drop — Remittance + QR Payments Version: 1.0 Date: 2026-02-23 Author: John (AI Director) Status: Approved Reviewers: Alem Bašić (CEO)
Document History
| Version | Date | Author | Changes |
|---|---|---|---|
| 0.1 | 2026-02-23 | John | Initial draft based on CLAUDE.md, API-REFERENCE.md, DATABASE-SCHEMA.md |
1. System Overview
System Name: Drop — Fintech Payment App System Purpose: Drop is a PSD2 pass-through payment app for residents of Norway/Scandinavia. It enables international remittance (PISP bank transfer at 0.5% fee) and QR-code merchant payments (PISP at 1% fee) directly from users' Norwegian bank accounts — without holding any customer funds. Users are onboarded via Norwegian BankID (18+ required).
System Context Diagram:
graph TB
subgraph "Drop Application"
UI[Next.js Web App - 10 screens]
API[Next.js API Routes - 26 endpoints]
DB[(SQLite → PostgreSQL)]
end
U1[Consumer User] -->|BankID login| UI
U2[Merchant User] -->|QR management| UI
API -->|Reads/Writes| DB
API -->|PISP payment initiation| BAAS[BaaS Provider - Swan/SpareBank1]
API -->|AISP balance read| BAAS
API -->|KYC verification| KYC[KYC Provider - Sumsub]
BAAS -->|Open Banking| BANKS[Norwegian Banks - PSD2]
BAAS -->|SCA| BANKID[BankID]
API -->|Remittance corridors| CORRIDOR[30+ countries]
2. Actors & Personas
| Actor ID | Actor Name | Type | Description | Access Level |
|---|---|---|---|---|
| ACT-01 | Consumer User | Human | Norwegian resident (18+) sending money abroad or paying merchants | Authenticated user |
| ACT-02 | Merchant User | Human | Local business owner accepting QR payments | Authenticated merchant |
| ACT-03 | BaaS Provider | System | Swan or SpareBank1 — Open Banking API (AISP/PISP) | System integration |
| ACT-04 | KYC Provider | System | Sumsub — identity verification and AML screening | System integration |
| ACT-05 | BankID | System | Norwegian strong customer authentication (SCA) | System integration |
Persona Detail
Persona: Amir (Consumer)
- Role: Software developer, immigrant from Bosnia
- Goal: Send 3,000 NOK/month to his mother in Sarajevo cheaply and reliably; also pay at Ahmet's kebab shop
- Pain Points: Western Union charges 10%; needs 2 separate apps for remittance and local payments
- Tech Savviness: High
- Frequency of Use: Weekly (remittance monthly; QR payments weekly)
Persona: Ahmet (Merchant)
- Role: Owner of kebab shop in Oslo
- Goal: Accept payments without Vipps terminal; lower fees; understand daily revenue
- Pain Points: Vipps charges 1.75-2.75%; requires hardware terminal; fees eat into margins
- Tech Savviness: Medium
- Frequency of Use: Daily (receives 20-50 QR payments/day)
3. Functional Requirements
3.1 Module: Authentication & BankID Onboarding
Module Overview
User registration and login via Norwegian BankID SCA. Age (18+) and residency (Norway, +47 phone) verified. JWT tokens issued in httpOnly cookies. 3-step onboarding: BankID verification → OTP verification → PIN setup.
FR-001: User Registration (3-step onboarding)
| Attribute | Value |
|---|---|
| Module | Authentication |
| Priority | Must Have |
| Trace | BR-001, BR-002 |
| UI Reference | mockups/figma-make-export/src/components/Onboarding.js |
Description: New users register via a 3-step flow: (1) personal details + BankID, (2) OTP verification via Norwegian phone number, (3) PIN setup. Users must be ≥18 years old (validated via BankID DOB). Norwegian phone (+47) required.
Acceptance Criteria:
- Given a valid email, password (≥8 chars), Norwegian phone (+47), and DOB ≥18 years, when user submits registration, then account is created and user proceeds to OTP step
- Given a user under 18 years old, when they submit registration, then system rejects with "Du må være minst 18 år"
- Given an already-registered email, when user tries to register, then system returns 409 "Email already in use"
- Given OTP is sent, when user enters correct 6-digit code, then user proceeds to PIN setup
- Given PIN setup, when user enters and confirms 4-digit PIN, then account is activated
- Given invalid email format, when user submits, then 422 validation error with specific field details
Data Requirements:
- Input: email (unique), password (≥8 chars), first_name, last_name, phone (+47), date_of_birth
- Output: user record (id, kyc_status=pending), JWT token in httpOnly cookie
- Validation: email format (regex), password length, phone format, DOB ≥18
Business Rules: RUL-001, RUL-002, RUL-008
Dependencies: None
FR-002: User Login
| Attribute | Value |
|---|---|
| Module | Authentication |
| Priority | Must Have |
| Trace | BR-001 |
| UI Reference | mockups/figma-make-export/src/components/Login.js |
Description: Users log in with email + password. JWT token issued in httpOnly cookie (7-day expiry). Failed logins rate-limited.
Acceptance Criteria:
- Given valid email + password, when user submits login, then JWT cookie set and user redirected to dashboard
- Given invalid credentials, when user submits, then 401 "Invalid email or password" (no user enumeration)
- Given 10+ attempts from same IP in 1 minute, when user tries again, then 429 rate limit response
- Given authenticated session idle for 7 days, when user makes request, then token expired; redirect to login
Data Requirements:
- Input: email, password
- Output: JWT in httpOnly cookie (SameSite=Strict); user object (id, email, role, kyc_status)
- Validation: email format, password non-empty
Business Rules: RUL-001, RUL-002
Dependencies: FR-001
FR-003: Session Management + Logout
| Attribute | Value |
|---|---|
| Module | Authentication |
| Priority | Must Have |
| Trace | BR-001 |
Description: Authenticated routes require valid JWT. Logout clears the cookie and revokes the session in the database. GET /api/auth/me returns current user.
Acceptance Criteria:
- Given authenticated user, when they call GET /api/auth/me, then current user object returned
- Given unauthenticated user, when they access protected route, then 401 Unauthorized
- Given authenticated user, when they POST /api/auth/logout, then cookie cleared and session revoked in DB
Business Rules: RUL-001
Dependencies: FR-002
3.2 Module: KYC Verification
Module Overview
Know-Your-Customer identity verification required before any transaction. In MVP: Sumsub integration (mocked in demo). Users with kyc_status=approved can transact; others are blocked with clear messaging.
FR-010: KYC Identity Verification
| Attribute | Value |
|---|---|
| Module | KYC |
| Priority | Must Have |
| Trace | BR-001, BR-002 |
Description: Users must complete KYC verification before initiating their first transaction. KYC status stored per user: pending → in_review → approved | rejected. In production: Sumsub document + biometric verification.
Acceptance Criteria:
- Given user with kyc_status=pending, when they attempt remittance, then 403 "KYC verification required" with link to complete
- Given approved user, when they initiate transaction, then transaction proceeds
- Given Sumsub webhook callback with approved status, when received, then user kyc_status updated to approved
- Given rejected user, when they attempt transaction, then 403 with rejection reason
Business Rules: RUL-008
Dependencies: FR-001
3.3 Module: Remittance (Send Money)
Module Overview
Core revenue stream #1. Users send money to 30+ countries at 0.5% fee via PISP. The payment is initiated directly from the user's Norwegian bank account. Recipient receives bank transfer or cash pickup within 1-2 business days.
FR-020: Send Money — Remittance Flow
| Attribute | Value |
|---|---|
| Module | Remittance |
| Priority | Must Have |
| Trace | BR-003, BR-005 |
| UI Reference | mockups/figma-make-export/src/components/SendMoney.js |
Description: Authenticated, KYC-approved users can send money to recipients in 30+ countries. Fee: 0.5% of transaction amount. Supported MVP corridors: NOK→RSD, NOK→BAM, NOK→PKR, NOK→TRY, NOK→PLN, NOK→EUR.
Acceptance Criteria:
- Given authenticated + KYC-approved user and valid recipient, when POST /api/transactions/remittance with amount 100-50,000 NOK, then 201 transaction created; fee calculated as amount × 0.005
- Given unauthenticated user, when they attempt remittance, then 401 Unauthorized
- Given user with insufficient balance, when they attempt remittance, then 402 "Insufficient balance"
- Given amount below 100 NOK or above 50,000 NOK, when user submits, then 400 validation error
- Given valid transaction, when completed, then transaction_history record created with status=completed, correct fee
Data Requirements:
- Input: recipientId, amount (100-50,000 NOK), currency (RSD/BAM/PKR/TRY/PLN/EUR), note (optional)
- Output: transaction_id, amount, fee (amount × 0.005), recipient_amount, status, created_at
- Validation: amount range, recipientId exists, KYC approved, balance sufficient
Business Rules: RUL-003, RUL-005, RUL-007, RUL-008
Dependencies: FR-002, FR-010, FR-040 (recipients)
FR-021: Exchange Rates
| Attribute | Value |
|---|---|
| Module | Remittance |
| Priority | Must Have |
| Trace | BR-003 |
Description: Current NOK exchange rates for all supported corridors. GET /api/rates returns all; GET /api/rates/[currency] returns specific rate.
Acceptance Criteria:
- Given GET /api/rates, when called, then returns all 6 NOK exchange rates (RSD, BAM, PKR, TRY, PLN, EUR)
- Given GET /api/rates/RSD, when called, then returns NOK→RSD rate
- Given GET /api/rates/XXX (invalid), when called, then 404 Not Found
- Given rate query, when currency code is lowercase, then case-insensitive match
Dependencies: None
FR-022: Recipients Management
| Attribute | Value |
|---|---|
| Module | Remittance |
| Priority | Must Have |
| Trace | BR-003 |
Description: Users can add, list, and reuse recipients for remittance. Recipients have name, country, bank account / IBAN.
Acceptance Criteria:
- Given authenticated user, when POST /api/recipients with valid data, then recipient created and associated with user
- Given authenticated user, when GET /api/recipients, then all user's recipients returned
- Given IBAN provided, when validated, then reject invalid IBAN format
- Given unauthenticated user, when accessing recipients, then 401 Unauthorized
Business Rules: RUL-003
Dependencies: FR-002
3.4 Module: QR Payments (Merchant + Consumer)
Module Overview
Core revenue stream #2. Merchants generate QR codes via Drop; consumers scan and pay. 1% merchant fee. Settlement via daily batch payout to merchant bank account.
FR-030: QR Payment — Consumer Flow
| Attribute | Value |
|---|---|
| Module | QR Payments |
| Priority | Must Have |
| Trace | BR-004, BR-005 |
| UI Reference | mockups/figma-make-export/src/components/ScanQR.js |
Description: Consumer scans merchant's QR code → enters amount → confirms → payment initiated via PISP from bank account. Fee: 1% charged to merchant. Consumer sees confirmation; merchant receives push notification.
Acceptance Criteria:
- Given authenticated + KYC-approved user, when POST /api/transactions/qr-payment with valid merchantId and amount ≥1 NOK, then 201 transaction created; merchant fee calculated as amount × 0.01
- Given invalid merchantId, when user pays, then 404 "Merchant not found"
- Given amount < 1 NOK, when submitted, then 400 validation error
- Given missing merchantId, when submitted, then 400 validation error
- Given successful payment, when completed, then both user and merchant transaction records updated
Data Requirements:
- Input: merchantId, amount (≥1 NOK), note (optional)
- Output: transaction_id, amount, merchant_fee (amount × 0.01), status, merchant details
- Validation: merchantId exists, amount ≥1, KYC approved, balance sufficient
Business Rules: RUL-003, RUL-006, RUL-008
Dependencies: FR-002, FR-010, FR-031
FR-031: Merchant Registration + QR Generation
| Attribute | Value |
|---|---|
| Module | QR Payments |
| Priority | Must Have |
| Trace | BR-004, BR-006 |
| UI Reference | mockups/figma-make-export/src/components/MerchantDashboard.js |
Description: Merchants register their business (name, address, bank account) and receive a unique QR code. Self-service onboarding < 5 minutes.
Acceptance Criteria:
- Given authenticated user, when POST /api/merchants with valid business data, then merchant record created with unique QR code value
- Given merchant, when GET /api/merchants/me, then merchant details + QR code returned
- Given QR code, when scanned by Drop consumer app, then merchant identified and payment flow initiated
Business Rules: RUL-006
Dependencies: FR-002, FR-010
FR-032: Merchant Dashboard Analytics
| Attribute | Value |
|---|---|
| Module | QR Payments |
| Priority | Should Have |
| Trace | BR-011 |
Description: Merchants view transaction volume, revenue, and fees by time period (today/week/month).
Acceptance Criteria:
- Given authenticated merchant, when GET /api/merchants/dashboard?period=week, then total transactions, gross volume, fees earned returned
- Given invalid period, when queried, then defaults to today
Dependencies: FR-031
3.5 Module: Bank Accounts (AISP)
Module Overview
Read-only view of user's linked bank account balance via AISP (Open Banking). Drop never holds funds — balance displayed for user awareness only.
FR-040: Bank Account Balance View
| Attribute | Value |
|---|---|
| Module | Bank Accounts |
| Priority | Should Have |
| Trace | BR-010 |
| UI Reference | mockups/figma-make-export/src/components/BankAccounts.js |
Description: Users view their linked bank account balance from their Norwegian bank via AISP. In MVP: mock balance from demo account. In Phase 2: real Open Banking AISP via BaaS provider.
Acceptance Criteria:
- Given authenticated user, when GET /api/bank-accounts, then linked bank account(s) with masked account number and balance returned
- Given user with no linked account, when viewing accounts, then prompt to link bank via BankID
Business Rules: RUL-003
Dependencies: FR-002, FR-010
3.6 Module: Transaction History
Module Overview
Users view all their transactions (remittance, QR payments) with filters by type, date, status.
FR-050: Transaction History
| Attribute | Value |
|---|---|
| Module | Transaction History |
| Priority | Should Have |
| Trace | BR-009 |
| UI Reference | mockups/figma-make-export/src/components/TransactionHistory.js |
Description: Authenticated users view all transactions with pagination. Filterable by type (remittance/qr_payment) and date range.
Acceptance Criteria:
- Given authenticated user, when GET /api/transactions, then all user's transactions returned (most recent first)
- Given query params, when ?type=remittance, then filtered results returned
- Given unauthenticated user, when accessing transactions, then 401 Unauthorized
Dependencies: FR-002
3.7 Module: Notifications
Module Overview
Push notifications for transaction events. Users receive alerts for incoming/outgoing transactions.
FR-060: Transaction Notifications
| Attribute | Value |
|---|---|
| Module | Notifications |
| Priority | Should Have |
| Trace | BR-008 |
| UI Reference | mockups/figma-make-export/src/components/Notifications.js |
Description: Users receive push notifications when transactions are created or completed. Notifications stored in DB and viewable in-app.
Acceptance Criteria:
- Given authenticated user, when GET /api/notifications, then all user's notifications returned (unread first)
- Given new transaction, when completed, then notification record created for relevant user(s)
- Given user marks notification as read, when PATCH /api/notifications/[id], then status updated
Dependencies: FR-020, FR-030
3.8 Module: User Profile & Settings
Module Overview
Users view and update their profile information, manage app preferences.
FR-070: User Profile
| Attribute | Value |
|---|---|
| Module | Profile |
| Priority | Should Have |
| Trace | BR-007 |
| UI Reference | mockups/figma-make-export/src/components/Profile.js |
Description: Authenticated users view their profile details, update preferences, and initiate account deletion (GDPR right to erasure).
Acceptance Criteria:
- Given authenticated user, when GET /api/auth/me, then user profile returned (no password hash)
- Given authenticated user, when DELETE /api/user/account, then account deletion initiated per GDPR
Business Rules: RUL-007 (GDPR right to deletion)
Dependencies: FR-002
3.9 Module: Feature Flags
Module Overview
Feature flag system controls access to beta/future features without code deployment.
FR-080: Feature Flag Control
| Attribute | Value |
|---|---|
| Module | Feature Flags |
| Priority | Should Have |
| Trace | BR-014 |
Description: 8 feature flags control access to Cards (feature-flagged), Top-up (removed), and other future features. Controlled via environment variables.
Acceptance Criteria:
- Given FF_CARDS_ENABLED=false, when user accesses /cards, then 404-equivalent feature gate response
- Given FF_CARDS_ENABLED=true, when user accesses /cards, then full cards feature accessible
- Given GET /api/feature-flags, when called, then all 8 flags with current values returned
Business Rules: Cards feature requires card partner agreement (RUL-010)
Dependencies: None
4. Use Case Diagrams
4.1 Consumer User Use Cases
graph LR
A1((Consumer)) --> UC1[FR-001: Register via BankID]
A1 --> UC2[FR-002: Login]
A1 --> UC3[FR-020: Send Money Remittance]
A1 --> UC4[FR-030: Pay via QR Scan]
A1 --> UC5[FR-040: View Bank Balance]
A1 --> UC6[FR-050: View Transaction History]
A1 --> UC7[FR-060: View Notifications]
4.2 Merchant User Use Cases
graph LR
A2((Merchant)) --> UC1[FR-001: Register]
A2 --> UC2[FR-031: Register Business + Get QR]
A2 --> UC3[FR-032: View Dashboard Analytics]
A2 --> UC4[FR-060: Receive Payment Notifications]
5. System Behavior Specifications
5.1 Error Handling
- All errors return
{error, message, details?}JSON format - Validation errors: 422 with
detailsarray listing per-field errors - Authentication errors: 401 (never reveal if email exists)
- Rate limit errors: 429 with Retry-After header
- No stack traces in production responses
5.2 Data Persistence
- All mutations logged with user_id, ip, timestamp
- Transaction records are immutable once created (status-only updates)
- ACID compliance required for financial transactions
5.3 Session & State
- JWT expiry: 7 days
- httpOnly cookies (SameSite=Strict) prevent XSS token theft
- CSRF protection on all state-changing endpoints (POST/PATCH/DELETE)
5.4 Notifications
- In-app: all transaction events (create, complete, fail)
- Push: Phase 2 (requires native mobile app)
- Email: account registration, security alerts
5.5 Security Headers (Required)
- HSTS, CSP, X-Frame-Options: DENY, X-Content-Type-Options: nosniff
- Referrer-Policy: strict-origin-when-cross-origin
6. Requirements Summary Table
| ID | Feature Name | Module | Priority | Status | Trace |
|---|---|---|---|---|---|
| FR-001 | User Registration (3-step onboarding) | Auth | Must Have | Implemented | BR-001, BR-002 |
| FR-002 | User Login | Auth | Must Have | Implemented | BR-001 |
| FR-003 | Session Management + Logout | Auth | Must Have | Implemented | BR-001 |
| FR-010 | KYC Identity Verification | KYC | Must Have | Mock (prod pending) | BR-001 |
| FR-020 | Send Money — Remittance | Remittance | Must Have | Implemented | BR-003, BR-005 |
| FR-021 | Exchange Rates API | Remittance | Must Have | Implemented | BR-003 |
| FR-022 | Recipients Management | Remittance | Must Have | Implemented | BR-003 |
| FR-030 | QR Payment — Consumer | QR Payments | Must Have | Implemented | BR-004, BR-005 |
| FR-031 | Merchant Registration + QR | QR Payments | Must Have | Implemented | BR-004, BR-006 |
| FR-032 | Merchant Dashboard Analytics | QR Payments | Should Have | Implemented | BR-011 |
| FR-040 | Bank Account Balance (AISP) | Bank Accounts | Should Have | Mock (AISP pending) | BR-010 |
| FR-050 | Transaction History | History | Should Have | Implemented | BR-009 |
| FR-060 | Transaction Notifications | Notifications | Should Have | Implemented | BR-008 |
| FR-070 | User Profile + GDPR deletion | Profile | Should Have | Implemented | BR-007 |
| FR-080 | Feature Flag Control | Feature Flags | Should Have | Implemented | BR-014 |
Requirements Count:
- Must Have: 7
- Should Have: 8
- Could Have: 0
- Won't Have (this release): Cards virtual/physical (BR-014), Loyalty rewards (BR-012)
7. Traceability to Business Requirements
| FR ID | Feature Name | Business Requirement (BR ID) | Business Objective (BO ID) |
|---|---|---|---|
| FR-001 | User Registration | BR-001, BR-002 | BO-02, BO-05 |
| FR-002 | User Login | BR-001 | BO-02 |
| FR-010 | KYC Verification | BR-001, BR-007 | BO-05 |
| FR-020 | Remittance | BR-003, BR-005 | BO-01, BO-02 |
| FR-030 | QR Payments | BR-004, BR-005 | BO-01, BO-03 |
| FR-031 | Merchant Registration | BR-004, BR-006 | BO-03 |
| FR-040 | Bank Balance (AISP) | BR-010 | BO-02 |
Full traceability matrix:
[requirements-traceability-matrix.md](requirements-traceability-matrix.md)
Approval
| Role | Name | Date | Signature |
|---|---|---|---|
| Author | John (AI Director) | 2026-02-23 | Approved (AI) |
| Tech Lead | John | 2026-02-23 | Approved |
| Product Owner | John | 2026-02-23 | Approved |
| AI Director (John) | John | 2026-02-23 | Approved |
| CEO (Alem) | Alem Bašić | TBD |