Pages
DropBilko Frontend — Pages
All pages are insrc/drop-app/src/app/usingFramework: Next.js 15 (AppRouterRouter)file-basedCurrentrouting.State: Fully implemented with mock data Future State: Will require API integration to replace mock data
PageRoute IndexArchitecture Overview
ROOT --> AUTH["(auth) group\nNo shared layout"]
ROOT --> DASH["(dashboard) group\napp/(dashboard)/layout.tsx\nSidebar + TopBar"]
AUTH --> LOGIN["/login\nLoginPage"]
AUTH --> REGISTER["/register\nRegisterPage"]
DASH --> DASHBOARD["/dashboard\nDashboard Home"]
DASH --> INVOICES["/invoices\nInvoice List"]
DASH --> INV_NEW["/invoices/new\nInvoice Wizard"]
DASH --> EXPENSES["/expenses\nExpense List"]
DASH --> EXPENSES_NEW["/expenses/new\nAdd Expense (standalone page)"]
DASH --> PURCHASES["/purchases\nPurchases (Bills + Vendors)"]
DASH --> BANKING["/banking\nBanking Hub"]
DASH --> REPORTS["/reports\nReports Hub"]
DASH --> REPORTS_PL["/reports/profit-loss\nP&L Report"]
DASH --> REPORTS_VAT["/reports/vat\nVAT Report"]
DASH --> SETTINGS["/settings\nSettings"]
LANDING --> LOGIN
LOGIN --> DASHBOARD
REGISTER --> DASHBOARD
classDef layout fill:#1e1e2e,color:#cdd6f4,stroke:#89b4fa
classDef auth fill:#313244,color:#cba6f7,stroke:#cba6f7
classDef dashboard fill:#1e1e2e,color:#a6e3a1,stroke:#a6e3a1
classDef reports fill:#313244,color:#89dceb,stroke:#89dceb
class ROOT,DASH layout
class AUTH,LOGIN,REGISTER auth
class DASHBOARD,INVOICES,INV_NEW,EXPENSES,EXPENSES_NEW,PURCHASES,BANKING,SETTINGS dashboard
class REPORTS,REPORTS_PL,REPORTS_VAT reports
| | |||
| | |||
| | |||
| | |||
| | |||
| | |||
| | |||
| | |||
| | |||
| | |||
| | |||
| | |||
| | |||
| | |||
| | |||
| | |||
| | |||
| | |||
| | |||
| |
Page DetailsLayouts
Root Layout
- Route:
/— Home / Marketing Page - File:
app/page.layout.tsx Type:Purpose:ServerRootcomponentHTML(nowrapper,"useappliesclient")Inter font, sets metadata, registers service workerAuth:Metadata:None- Title: "Bilko - Accounting Made Simple"
- Description: "Modern accounting software for Balkan businesses"
- manifest:
/manifest.json(PWA) - appleWebApp:
capable: true,statusBarStyle: "default",title: "Bilko" - icons.apple:
/icons/icon-192.png - viewport.themeColor:
#00E5A0 - html lang:
sr(Serbian)
Components used:Dependencies:DropLogoFull,InterDropAppIcon,fontLink,fromImage,GooglecustomFonts,iconsServiceWorkerRegistrar(IconSendMoney, IconQrScan, IconVirtualCard, IconShield, IconFastTransfer, IconCorridors)componentData:Current State:StaticFullyarraysimplemented,PWA-ready (features3 items) andstats(3 items) defined inlineSections:Header with DropLogoFullmanifest +navservicelinksworker(Tjenester, Priser, Om oss, Logg inn, Kom i gang)Hero with headline, subtext, CTA buttons, phone mockup placeholderFeatures grid (Send penger, Betal med QR, Virtuelt kort)Stats bar (0.5% Gebyr, <2t Leveringstid, 30+ Land)Trust section (BankID verified, Rask overføring, 30+ land)Merchant CTA sectionFooter with ALAI Holding AS credit
registration)
/loginDashboard — LoginLayout
- Route:
/(dashboard)/* - File:
app/login/page.(dashboard)/layout.tsx Type:Purpose:ClientLayoutcomponentwrapper for all authenticated pagesAuth:Key Components:None- Sidebar (
entrydesktoppoint)persistent, mobile overlay) - TopBar (header with search, notifications, user menu)
- Sidebar (
ComponentsStateused:Management:Image,LocalLink,stateButton,forMail/Lock/Eye/EyeOff/ArrowRightmobile(lucide)sidebar toggleState:Mobile Responsiveness:email,Responsivepassword,sidebarshowPassword,witherror, loadingoverlayDataCurrentfetching:State:POSTFully/api/auth/loginwith{ email, password }Validation:Email regex^[^\s@]+@[^\s@]+\.[^\s@]+$, required fields checkOn success:router.push("/dashboard")Social login buttons:BankID, Vipps (UI only, not functional)Dev mode:Shows demo credentialsimplemented[email protected] / demo1234
graph LR
DL["DashboardLayout\napp/(dashboard)/layout.tsx"]
DL --> SB["Sidebar\ncomponents/sidebar.tsx\n• Logo\n• Main nav (5 items)\n• Bottom nav (Settings)\n• Active state via usePathname"]
DL --> TB["TopBar\ncomponents/top-bar.tsx\n• Mobile menu button\n• Search (Cmd+K)\n• Notifications bell\n• User dropdown menu"]
DL --> SLOT["Page Slot\n{children}"]
SB -->|"dark sidebar #111113"| SCREEN["Rendered Screen"]
TB -->|"white top bar"| SCREEN
SLOT -->|"light content #FAFAFA"| SCREEN
Pages
/registerDashboard — Registration(Home)
- Route:
/dashboard - File:
app/register/(dashboard)/dashboard/page.tsx Type:Purpose:ClientFinancialcomponentoverview and quick actionsAuth:Key Components:None- Metric cards (Cash Balance, Revenue MTD, Unpaid Invoices)
- P&L Bar Chart (6-month trend)
- Receivables Aging (stacked bar chart)
- Expenses by Category (donut chart)
- Recent Transactions table
- Quick Actions card
ComponentsDataused:Requirements (Future API):ArrowLeft/ArrowRight/Check/Eye/EyeOff/Phone/Mail/User/Calendar/LockGET /api/metrics— cashBalance, revenueMTD, unpaidInvoices, expensesMTD, profitMTD, cashFlowChangeGET /api/pl/monthly— monthly P&L data (lucide),revenue,Buttonexpenses, profit)GET /api/receivables/aging— receivables breakdown (current, 30d, 60d, 90d+)GET /api/expenses/by-category— expenses grouped by categoryGET /api/transactions/recent?limit=5— recent transactions
- Charts: Recharts (BarChart, PieChart) with responsive containers
- Current State: Mock data from
lib/mock-data.ts - Mobile Responsive: Grid adapts 1/2/3 columns based on breakpoint
graph TD
DP["Dashboard Page\n/dashboard"]
DP --> ROW1["Row 1 — Metric Cards\ngrid-cols-1 md:grid-cols-3"]
DP --> ROW2["Row 2 — Charts\ngrid-cols-1 md:grid-cols-3"]
DP --> ROW3["Row 3 — Tables + Actions\ngrid-cols-1 lg:grid-cols-3"]
ROW1 --> MC1["Cash Balance\nwith trend arrow"]
ROW1 --> MC2["Revenue MTD\ncurrent month total"]
ROW1 --> MC3["Unpaid Invoices\nwith warning badge"]
ROW2 --> CH1["P&L Bar Chart\nRecharts BarChart\n6-month revenue/expenses/profit"]
ROW2 --> CH2["Receivables Aging\nRecharts StackedBarChart\ncurrent/30d/60d/90d+"]
ROW2 --> CH3["Expenses by Category\nRecharts PieChart (donut)\nper-category breakdown"]
ROW3 --> TBL["Recent Transactions\nRecharts Table\nlast 5 transactions"]
ROW3 --> QA["Quick Actions\nNew Invoice\nNew Expense\nImport Bank Statement"]
Invoices List
- Route:
/invoices - File:
app/(dashboard)/invoices/page.tsx - Purpose: Invoice management with search, filter, sort
- Key Features:
- Status filter (all/draft/sent/paid/overdue)
- Search by customer name or invoice number
- Date range filter (this month, last month, quarter, all)
- Sortable columns (number, customer, date, due date, amount)
- Row actions (view, edit, send, download PDF, delete)
- Summary row with totals by status
- Data Requirements (Future API):
GET /api/invoices?status=X&search=Y&dateRange=Z&sort=field&dir=asc— filtered/sorted invoice listPATCH /api/invoices/:id— update invoiceDELETE /api/invoices/:id— delete invoicePOST /api/invoices/:id/send— send invoice via emailGET /api/invoices/:id/pdf— generate PDF
- Current State: Mock data, client-side filtering/sorting
- Mobile Responsive: Table scrolls horizontally, filters stack vertically
Invoice Creation Wizard
- Route:
/invoices/new - File:
app/(dashboard)/invoices/new/page.tsx - Purpose: 6-step
(1-4),wizardformtofields,createotp,andpin,senderrorsinvoices - Steps:
InfoCustomer Selection —firstName,SelectlastName,existingemail,customerphoneor add new (+47 prefix), dateOfBirth, passworddialog)VerifyInvoice Details —6-digitInvoiceOTPnumber,inputissue/due(MVP:dates,anynet6terms,digits accepted)currencyPINLine Items —4-digitAdd/removePINitemswith(description,customqty,numpadunitUIprice, VAT rate), auto-calculate totalsSuccessCustomization —WelcomeOptional notes and payment terms- Preview — Visual preview of generated invoice
- Send — Email form (to, subject, message,
redirectcopy to/dashboardself) + save/download options
- Data Requirements (Future API):
GET /api/customers— customer list for dropdownPOST /api/customers— create new customerPOST /api/invoices— create invoice (draft)POST /api/invoices/:id/send— send invoice via emailGET /api/invoices/:id/pdf— download PDF
- Form Validation:
AgeStep>=1:18Customer(calculated from dateOfBirth)requiredXSSStepprotection:3:namesAtrejectleast one line item with description required- Step 6: Email address required
- Current State: Mock data, local state, no persistence
- Mobile Responsive: Wizard steps adapt, form fields stack on mobile
Expenses List
- Route:
< > " ' & ; ( ) { } [ ]/expenses Password:File:min 8 chars, must contain letters AND numbersapp/(dashboard)/expenses/page.tsxPhone:Purpose:mustExpensebetracking8withdigitscategorization and approval workflow- Key Features:
- Period filter (
Norwegianthisformat)month, last month, quarter, year) - Category filter (Office, Travel, Meals, Utilities, Marketing, Infrastructure, Software, Professional Services)
- Search by description or vendor
- Status badges (pending, approved, paid)
- Receipt attachment indicator
- Add Expense dialog (with upload placeholder)
- Summary stats (total, pending, approved, paid counts)
- Period filter (
- Data
fetching:Requirements (Future API):GET /api/expenses?period=X&category=Y&search=Z— filtered expense listPOST/api/— create expenseauth/registerexpensesPATCH /api/expenses/:id— update expense statusPOST /api/expenses/:id/receipt— upload receipt (multipart)GET /api/expenses/:id/receipt— download receipt
- Form Fields:
- Amount + currency (EUR, RSD, BAM)
- Category (dropdown)
- Date
- Vendor (searchable input)
- Payment method (Cash, Card, Bank Transfer)
- Receipt upload (placeholder UI)
- Description (optional)
- Current State: Mock data, form submits to console
- Mobile Responsive: Filters stack, table scrolls
/dashboardAdd —Expense Main(Dedicated DashboardPage)
- Route:
/expenses/new - File:
app/dashboard/(dashboard)/expenses/new/page.tsx Type:Purpose:ClientStandalonecomponentadd-expense page (mobile-friendly, separate from the dialog on /expenses)Auth:Key Features:Yes- "Scan Receipt" prominent CTA button (
Camera icon, no backend yet)useAuth() - Amount field with
redirect)currency symbol prefix ComponentsCategoryused:DropLogo, BottomNav, ScrollArea, Bell/LogOutselect (lucide)Office Supplies, Travel, Software, Infrastructure, Professional Services, Marketing, Utilities, Other)State:Datetransactions,pickerloading(defaults to today)- Vendor input (optional)
- Payment Method select (Bank Transfer, Credit/Debit Card, Cash, PayPal)
- Receipt attachment button (Paperclip icon, no upload yet)
- Description textarea (optional)
- Back arrow to
/expenses
- "Scan Receipt" prominent CTA button (
- Data
fetching:Requirements (Future API):GETPOST /api/expenses— create expense via/api/transactions?limit=10useExpenseStore.createExpense()
Interfaces:Current State: CallsTransactionuseExpenseStore.createExpense(){withid,mocktype,fallback;status,redirectsamount,tocurrency,/expensesrecipientName,oncreatedAt }successLayout:Mobile Responsive:- Single
Header:columnDropLogolayout,+max-w-lgnotification bell + logout + avatar initialsBalance card: primary account balance, formatted NOKAction buttons: Send penger (→ /send), Skann QR (→ /scan)Recent transactions list in ScrollAreaBottomNav
centered
/accounts — Bank AccountsPurchases
- Route:
/purchases - File:
app/accounts/(dashboard)/purchases/page.tsx Type:Purpose:ClientBillscomponentand vendor management (NOT a simple alias to /expenses — fully independent page)Auth:Key Features:Yes- Summary Cards (
3): Total Unpaid, Overdue, Due This WeekuseAuth() - Two Tabs: Bills (table of expenses mapped as bills) | Vendors (table from contacts where type='vendor')
Components used:Filters:BottomNav, Card, ArrowLeft/Landmark/Plus/ChevronRightStatus (lucide)All/Unpaid/Overdue/Paid), Vendor (from contacts), Period (This Month/Last Month/This Quarter)- Uses
useExpenseStore+useContactStorefrom Zustand - Loading states with Skeleton components
- Summary Cards (
Data:Data Requirements (Future API):ReadsGET /api/expenses— fetched viauser.bankAccountsuseExpenseStore.fetchExpenses()GET /api/contacts?type=vendorfrom—authfetchedhookvia(nouseContactStore.fetchContacts()
separatefetch)Layout:Current State:- Mock
PSD2/OpendataBankingfallbackinfoviabannerZustand(blue)stores; bills derived from expenses, vendors derived from contacts of type 'vendor'AccountMobilecards:Responsive:bankName,CardsmaskedandaccountNumber,filtersbalance,stackcurrency,onisPrimary badgeTotal balance summary"Legg til bankkonto" button (BankID connection note)
mobile
/transactions — Transaction HistoryBanking
- Route:
/banking - File:
app/transactions/(dashboard)/banking/page.tsx Type:Purpose:ClientBankcomponentaccount management and reconciliationAuth:Key Features:Yes- 3 tabs: Accounts, Reconcile, Transactions
ComponentsAccountsused:Tab:BottomNav,ListTabs/TabsList/TabsTrigger,ofArrowLeft/Clockbank accounts with balances (lucide)multiple currencies)State:Reconcile Tab:transactions,Unreconciledfilter,transactionsloadingwith match confidence, period selector- Transactions Tab: All bank transactions (chronological)
- Import Transactions button (placeholder)
- Match actions (approve, link, create new)
(useAuth())- Data
fetching:Requirements (Future API):GET/api/bank-accounts— list accountsPOST /api/bank-accounts— add accountGET /api/bank-accounts/:id/transactions?— unreconciled transactionstype={filter}&limit=50reconciled=falsePOST /api/bank-accounts/:id/import— CSV importPOST /api/bank-accounts/:id/transactions/:txId/reconcile— mark reconciledPOST /api/bank-accounts/:id/transactions/:txId/link?invoiceId=X— link to invoice/expense
Filters:Match Confidence Logic:AlleVisual(all)indicators for 0%,Overforinger (remittance)<50%,QR-betalinger50-89%,(qr_payment)90%+Grouping:Current State:MockgroupByDate()functiondata,groupsnointo:reconciliationI dag, I gar, Denne uken, EldrelogicDisplay:Mobile Responsive:AmountTabswithstack,+/-tablesprefix and color coding (green for received, red for sent)scroll
/scanReports — QR ScannerHub
- Route:
/reports - File:
app/scan/(dashboard)/reports/page.tsx Type:Purpose:ClientFinancialcomponentreport selection and P&L previewAuth:Report Cards:Yes- Profit & Loss (implemented at
)useAuth()/reports/profit-loss ComponentsBalanceused:BottomNav, Button, ArrowLeft/Camera/Check/X/StoreSheet (lucide)coming soon)- Cash Flow Statement (coming soon)
- VAT/PDV Report (live at
/reports/vat) - Trial Balance (coming soon)
- General Ledger (coming soon)
- Profit & Loss (implemented at
State:P&L Preview:scanState- Expandable
|Revenue/Expensespayment | paying | success), scannedMerchant, amount, paymentResultsections Interfaces:CurrentScannedMerchantmonth{detailedid, name, category },breakdownPaymentResult { id, status, amount, fee, merchant }Flow:Export- buttons
Scanning(PDF, Excel) —Camera viewfinder UI with scan frame, "Simuler skanning" button (demo)placeholdersPayment— Shows merchant info, amount input, 1% fee calculationPaying— Loading spinnerSuccess— Confirmation with transaction details
(scanning- Expandable
- Data
fetching:Requirements (Future API):POSTGET /api/transactions/qr-paymentreports/pl?month=YYYY-MMwith— P&L report data{GETmerchantId,/api/reports/balance-sheet?date=YYYY-MM-DDamount—}balance sheetGET /api/reports/cash-flow?period=X— cash flow statement
DemoCurrentmerchant:State:"AhmetovOnlyKebab"P&L(id:and VAT reports implemented, others show "merchant_001",Comingcategory:Soon""Restaurant")badge- Mobile Responsive: Report cards grid adapts
/sendgraph TD
RH["Reports Hub\n/reports"]
RH --> PL["Profit & Loss\n/reports/profit-loss\nLIVE — Sendexpandable Moneyrevenue/expenses\nfetches (Remittance)from API with mock fallback"]
RH --> BS["Balance Sheet\nCOMING SOON"]
RH --> CF["Cash Flow Statement\nCOMING SOON"]
RH --> VAT["VAT/PDV Report\n/reports/vat\nLIVE — 3-step wizard"]
RH --> TB["Trial Balance\nCOMING SOON"]
RH --> GL["General Ledger\nCOMING SOON"]
PL --> PL_R["Revenue Section\n(expandable, breakdown by category)"]
PL --> PL_E["Expenses Section\n(expandable, breakdown by category)"]
PL --> PL_NP["Net Profit + Margin"]
PL --> PL_EX["Export PDF / Export Excel"]
VAT --> VAT_S1["Step 1: Reconciliation Check\n(warn if unreconciled transactions)"]
VAT --> VAT_S2["Step 2: VAT Audit\n(all VAT transactions table)"]
VAT --> VAT_S3["Step 3: Return Summary\nBox 1 / Box 2 / Box 3"]
classDef live fill:#1e3a2f,color:#a6e3a1,stroke:#a6e3a1
classDef soon fill:#2a1e2e,color:#888,stroke:#555
class PL,VAT live
class BS,CF,TB,GL soon
VAT Report
- Route:
/reports/vat
- File:
app/send/(dashboard)/reports/vat/page.tsx
Type:Purpose: Client component
Auth: Yes (useAuth())
Components used: Button, ArrowLeft/ArrowRight/Check/ChevronDown/Globe/User (lucide)
State: 3-step (1-4),VAT selectedRecipient,return amount, recipients, rates, sending, txResultpreparation
- Steps:
SelectReconciliation RecipientCheck — ListWarns fromif GETunreconciled /api/recipients,bank showstransactions name + country flagexist
EnterVAT AmountAudit — NOKTable input,of real-timeall conversionVAT transactions (invoices + expenses) with exchangenet/VAT rate, 0.5% fee displayamounts
ReviewReturn Summary — SummaryVAT ofreturn recipient,boxes amount,(Box rate,1: fee,collected, total Box Success2: —paid, ConfirmationBox with3: referencenet numberdue)
- Data
fetching:Requirements (Future API):
GET /api/recipientsbank-accounts/unreconciled-count (on— mount)reconciliation status
GET /api/ratesvat/transactions?period=YYYY-MM (on— mount)all VAT transactions
GET /api/vat/return?period=YYYY-MM — calculated VAT return data
POST /api/transactions/remittancevat/submit with— e-filing (Phase 2)
{GET recipientId,/api/vat/export/pdf amountNOK,— targetCurrencyPDF }export
GET /api/vat/export/xml — XML for e-filing
Country flags:Calculations: RSAssumes (Serbia),20% BAstandard (Bosnia),VAT TRrate, (Turkey),converts PKall (Pakistan),currencies PLto (Poland)EUR equivalent
Interface:Current State: TxResultMock {data, id,no status,submission, amount,export fee,placeholders
rate,- Mobile
recipientName,Responsive: targetAmount,Tabs targetCurrencyadapt, }tables scroll, boxes stack
/profile — User ProfileSettings
- Route:
/settings
- File:
app/profile/(dashboard)/settings/page.tsx
Type: Client component
Auth: Yes (useAuth())
Components used: BottomNav, ArrowLeft/ChevronRight/LogOut/Settings/Shield/HelpCircle/Bell/CreditCard/Landmark (lucide)
Data: Reads user from auth hook
Layout:
User info card with initials avatar (green bg), full name, email
Menu items: Mine kontoer (→ /accounts), Varsler, Innstillinger, Sikkerhet, Hjelp og stotte
Logout button with confirmation
Version: "Drop v0.1.0 · ALAI Holding AS"
/withdrawal — Angrerett (Right of Withdrawal)
File: app/withdrawal/page.tsx
Type: Client component
Auth: No
Components used: ChevronLeft, RotateCcw, CheckCircle (lucide)
State: submitted, loading
Purpose: Norwegian angrerettloven compliance — 14-day right of withdrawal form
Layout:
Info section explaining angrerett (right to cancel service agreement within 14 days)
Warning banner: Angrerett does not apply to completed payment transactions, only to the service agreement itself
Form with optional reason dropdown (not_needed, alternative, not_satisfied, other) and comment textarea
Submit button (red) with AML retention notice (data kept for 5 years per hvitvaskingsloven)
Success screen with confirmation message (14-day processing time)
/complaints — Send Complaint
File: app/complaints/page.tsx
Type: Client component
Auth: Yes (useAuth())
Components used: MessageSquare, CheckCircle, ChevronLeft, ExternalLink (lucide)
State: submitted, loading, formData (category, subject, description)
Data fetching: POST /api/complaints with { category, subject, description }
- Purpose:
FinansavtalelovenMulti-section §3-53 compliance — formal complaint submission with 15 business day response requirement
Layout:
Info text: All complaints taken seriously, up to 15 business days processing time
Form with required fields:
Category dropdown: transaction, fees, service, privacy, other
Subject text input (max 200 chars)
Description textarea (max 2000 chars)
Submit button with POST to /api/complaints
External complaint authority section: Finansklagenemnda (FinKN) contact info with link to finansklagenemnda.no
Success screen: Complaint received, 15 business day review commitment
/privacy — Privacy Policy
File: app/privacy/page.tsx
Type: Client component
Auth: None
Components used: ChevronLeft, Shield (lucide)
Purpose: GDPR-compliant privacy policysettings page (Norwegian language)
- Sections:
Behandlingsansvarlig:Company ALAI— HoldingCompany ASprofile as(name, datalegal controllerform, address, tax ID, currency, fiscal year)
Hvilke opplysninger vi samler inn:Users Identification— User management table (name, email, phone,role, BankID)status), Financialinvite data (bank accounts via Open Banking, transaction history), Technical data (IP, device, app version)button
FormaalTax med& behandlingen:Compliance Transaction— processingCountry, (PSD2/PISP),VAT KYC/AMLregistration, compliance,VAT AML/terrorismnumber/rate, prevention,compliance service improvementreminders
Rettslig grunnlag:Integrations Contract— Connected integrations (GDPRIntesa 6(1)(b))Bank CSV, Email SMTP), Legalavailable obligationintegrations (6(1)(c))Stripe, forFiken, AML/KYC,Google LegitimateSheets, interestSlack, (6(1)(f)) for service improvementDocuSeal)
Dine rettigheter:Notifications Innsyn— (access),Email Rettingand (rectification),in-app Slettingnotification (erasure with 5-year AML retention), Dataportabilitet (portability)preferences
Oppbevaring:Security Minimum— 52FA, yearssession pertimeout, hvitvaskingsloven,password anonymizationpolicy, onaudit account deletion but AMLlog, data retained export, Kontakt:delete [email protected], complaint to Datatilsynetcompany
/sendgraph TD
RH["Reports Hub\n/reports"]
RH --> PL["Profit & Loss\n/reports/profit-loss\nLIVE — /reports/vatapp/send/(dashboard)/reports/vat/page.tsxuseAuth()SelectReconciliationRecipientCheck —ListWarnsfromifGETunreconciled/api/recipients,bankshowstransactionsname + country flagexistEnterVATAmountAudit —NOKTableinput,ofreal-timeallconversionVAT transactions (invoices + expenses) withexchangenet/VATrate, 0.5% fee displayamountsReviewReturn Summary —SummaryVATofreturnrecipient,boxesamount,(Boxrate,1:fee,collected,totalBox Success2:—paid,ConfirmationBoxwith3:referencenetnumberdue)
GET/api/recipientsbank-accounts/unreconciled-count(on—mount)reconciliation statusGET/api/ratesvat/transactions?period=YYYY-MM(on—mount)all VAT transactionsGET /api/vat/return?period=YYYY-MM— calculated VAT return dataPOST/api/transactions/remittancevat/submitwith— e-filing (Phase 2){GETrecipientId,/api/vat/export/pdfamountNOK,—targetCurrencyPDF}exportGET /api/vat/export/xml— XML for e-filing
TxResultMock {data, id,no status,submission, amount,export fee,placeholders/profile/settingsapp/profile/(dashboard)/settings/page.tsxuseAuth()userUser info card with initials avatar (green bg), full name, emailMenu items: Mine kontoer (→ /accounts), Varsler, Innstillinger, Sikkerhet, Hjelp og stotteLogout button with confirmationVersion: "Drop v0.1.0 · ALAI Holding AS"
/withdrawalapp/withdrawal/page.tsxInfo section explaining angrerett (right to cancel service agreement within 14 days)Warning banner: Angrerett does not apply to completed payment transactions, only to the service agreement itselfForm with optional reason dropdown (not_needed, alternative, not_satisfied, other) and comment textareaSubmit button (red) with AML retention notice (data kept for 5 years per hvitvaskingsloven)Success screen with confirmation message (14-day processing time)
/complaintsapp/complaints/page.tsxuseAuth()/api/complaints{ category, subject, description }Info text: All complaints taken seriously, up to 15 business days processing timeForm with required fields:Category dropdown: transaction, fees, service, privacy, otherSubject text input (max 200 chars)Description textarea (max 2000 chars)
Submit button with POST to/api/complaintsExternal complaint authority section: Finansklagenemnda (FinKN) contact info with link to finansklagenemnda.noSuccess screen: Complaint received, 15 business day review commitment
/privacyapp/privacy/page.tsxBehandlingsansvarlig:CompanyALAI—HoldingCompanyASprofileas(name,datalegalcontrollerform, address, tax ID, currency, fiscal year)Hvilke opplysninger vi samler inn:UsersIdentification— User management table (name, email,phone,role,BankID)status),Financialinvitedata (bank accounts via Open Banking, transaction history), Technical data (IP, device, app version)buttonFormaalTaxmed&behandlingen:ComplianceTransaction—processingCountry,(PSD2/PISP),VATKYC/AMLregistration,compliance,VATAML/terrorismnumber/rate,prevention,complianceservice improvementremindersRettslig grunnlag:IntegrationsContract— Connected integrations (GDPRIntesa6(1)(b))Bank CSV, Email SMTP),Legalavailableobligationintegrations (6(1)(c))Stripe,forFiken,AML/KYC,GoogleLegitimateSheets,interestSlack,(6(1)(f)) for service improvementDocuSeal)Dine rettigheter:NotificationsInnsyn—(access),EmailRettingand(rectification),in-appSlettingnotification(erasure with 5-year AML retention), Dataportabilitet (portability)preferencesOppbevaring:SecurityMinimum—52FA,yearssessionpertimeout,hvitvaskingsloven,passwordanonymizationpolicy,onauditaccount deletion but AMLlog, dataretainedexport, Kontakt:delete[email protected], complaint to Datatilsynetcompany
Requirements
(Future API):
GET /—termsapi/settings/companyTermscompanyof ServiceFile:dataapp/terms/page.tsxType:PATCHClient/api/settings/companycomponent— update companyAuth:GETNone/api/users Components—used:ChevronLeft, FileText (lucide)Purpose:Legal terms of service (Norwegian language)Sections:Om tjenesten:Drop as PISP/AISP under PSD2, provided by ALAI Holding ASKrav til brukere:18+ age, Norwegian residency with BankID, KYC required, Norwegian phone (+47)Betalingsmodell:Drop never holds customer money, pass-through model via Open BankingGebyrer:All fees shown before transaction confirmation, see fees page for fulluser listAnsvar:POSTDrop responsible for correct payment execution per betalingstjenesteloven, refund rights per law, not liable for bank/recipient delaysMisbruk og sperring:Right to block accounts for suspected AML/fraud, mandatory STR reporting to Økokrim/EFEAngrerett:14-day withdrawal right per angrerettloven (does not apply to completed transactions)Tvister:Norwegian law, Oslo tingrett jurisdiction, complaint to Finansklagenemnda
/—feesapi/users/inviteFeeinviteOverviewFile:userapp/fees/page.tsxType:GETClient/api/settings/taxcomponent— tax settingsAuth:PATCH— update tax settingsNone/api/settings/taxComponentsGETused:/api/integrationsChevronLeft,—Receiptintegration(lucide)listPurpose:POSTTransparent/api/integrations/:id/connectfee—disclosureconnectpage (Norwegian language)integrationSections:GET- /api/settings/notifications
Overføring—tilnotificationutlandet:Transaction fee: 1.5% per transferpreferencesCurrencyPATCHmarkup:/api/settings/notifications0.5%—onupdatemid-market ratepreferencesTypicalGETtotal:/api/security/audit-log~2%—(compareauditwithlogPOSTat/api/security/data-export3-7%)— request data exportDELETE /api/company— delete company
banksQR-betalingCurrenti butikk:State:- Mock
Fordata,customer:formFree (no chargesubmits topayer)For merchant: 0.5% (lower than card terminals)
consoleKontotjenester:Mobile Responsive:- Sidebar
Accountnavcreation:stacks,Freeforms Monthly fee: FreeBank account linking (AISP): Free
Viktig informasjon:Fees can change with 30-day noticeExchange rates updated in real-time from marketAlways see final amount before confirming
adapt
Authentication Flow
sequenceDiagram participant U as User participant AP as AuthProvider participant AS as useAuthStore participant R as Router participant API as Backend API U->>AP: Navigate to /dashboard AP->>AS: checkAuth() AS->>API: GET /api/auth/me (Bearer token) alt API not configured (demo mode) AP-->>U: Render page directly (demoFallback=true) else Token valid API-->>AS: 200 OK —profile/personalPersonaluserInformationdata AS-->>AP: isAuthenticated=true AP-->>U: Render protected page else Token invalid / no token API-->>AS: 401 Unauthorized AS-->>AP: isAuthenticated=false AP->>R: router.replace('/login') R-->>U: Redirect to /login U->>U: Enter email + password U->>AS: login(email, password) AS->>API: POST /api/auth/login API-->>AS: 200 OK — JWT token AS->>R: router.push('/dashboard') R-->>U: Redirect to /dashboard end
Screenshot Descriptions
Dashboard
User sees:
File:3metric cards at top (cash balance with green arrow, revenue MTD, unpaid invoices with warning badge)app/profile/personal/page.tsxType:3Clientchartscomponentin row below (P&L bar chart, receivables aging stacked bar, expenses donut)Auth:BottomYesrow: recent transactions table on left, quick action buttons on right
Invoices List
User sees:
- Header with "Invoices" title and "New Invoice" button
- Filter row (
status dropdown, search input, date range dropdown)useAuth() - Table with all invoices (sortable columns, status badges, action menu per row)
- Summary bar at bottom showing totals by status
Invoice Wizard
User sees:
- Progress bar with 6 steps at top
- Current step content in card below
- Back/Next buttons at bottom (Send on final step)
- Step 3 shows line items with add/remove, running total calculation
- Step 5 shows formatted invoice preview
Expenses
User sees:
- "Expenses" header with "Add Expense" button
- Filters (period, category, search)
- Table with date, description, category, amount, vendor, status badge, receipt icon
- Summary bar with totals (total €, pending count, approved count, paid count)
- Add dialog: form with amount+currency, category, date, vendor, payment method, receipt upload, description
Banking
User sees:
- 3 tabs: Accounts, Reconcile, Transactions
- Accounts tab: table of bank accounts with type, currency, balance
- Reconcile tab: account selector, period, unreconciled transaction table with match confidence indicators, action buttons (✓ approve, link, create)
- Transactions tab: full transaction history with reconciled status
VAT Report
User sees:
- 3-step tabs at top
- Step 1: Warning card if unreconciled transactions exist, "Reconcile Now" and "Continue" buttons
- Step 2: VAT transaction table (type badge, net amount, VAT rate, VAT amount), summary boxes (collected, paid, net due)
- Step 3: VAT return boxes (Box 1, Box 2, Box 3 highlighted), export buttons (PDF, XML), submit button (disabled, "Coming in Phase 2")
Settings
User sees:
Note:All fields are disabled (cannot edit) — verified via BankIDborder)
/profile/security — Security Settings
Notes
File:All pages use mock data fromapp/profile/security/page.tsxlib/mock-data.tsType:AuthenticationClientimplementedcomponentviaAuthProvider+useAuthStore— demo mode active whenNEXT_PUBLIC_API_URLnot setAuth:No persistenceYes—(useAuth())refreshing page loses all changesComponentsMobile-firstused:designChevronLeft, ChevronRight, Lock, Smartphone, Laptop (lucide), BottomNavSections:Passord:Change password button (shows "Sist endret: Aldri")To-faktor autentisering:BankID verification: Active (green badge)Vipps verification: Not activated (gray badge)
Aktive enheter:iPhone 15 Pro: Oslo, Norge — Aktiv nå (green dot indicator)MacBook Pro: Oslo, Norge — I går kl. 18:45
Footer: Support contact ([email protected])
Note:UI only, no actual functionality connected
/profile/notifications — Notification Settings
File:app/profile/notifications/page.tsxType:Client componentAuth:Yes (useAuth())Components used:ChevronLeft, Bell, Mail (lucide), BottomNavState:pushEnabled, emailEnabled, settingsLoadedData fetching:GET/api/settings(on mount)PATCH/api/settingswith{ pushEnabled: boolean }or{ emailEnabled: boolean }(on toggle)
Layout:Push-varsler toggle switch (Bell icon)E-postvarsler toggle switch (Mail icon)
Behavior:Toggles immediately update state and send PATCH request, revert on failure
/profile/language — Language Settings
File:app/profile/language/page.tsxType:Client componentAuth:Yes (useAuth())Components used:ChevronLeft, Check (lucide), BottomNavState:selected, savingData fetching:GET/api/settings(on mount)PATCH/api/settingswith{ language: string }(on save)
Languages:nb (Norsk Bokmål), en (English), bs (Bosanski), sq (Shqip)Layout:Language list with radio selection (green checkmark for selected)"Lagre" button (green) to save selection
Behavior:Selection updates local state, user must click "Lagre" to persist
/notifications — Notifications Center
File:app/notifications/page.tsxType:Client componentAuth:Yes (useAuth())Components used:BottomNav, ArrowLeft, Bell, ArrowUpRight, ScanLine, Smartphone, TrendingUp (lucide)State:notifications, fetchingData fetching:GET/api/notifications(on mount)PATCH/api/notificationswith{ notificationIds: [ids] }(mark read, fire-and-forget)
Interface:Notification { id, type, title, body, read, createdAt }Layout:Header with back button + "Varsler" titleEmpty state: Bell icon + "Ingen varsler enna" messageGrouped notifications: I DAG / I GÅR / date groupsNotification cards: icon based on type, title, body, timestamp, unread dot indicatorBottomNav
Notification types:transaction_complete (green), qr_payment (yellow), security (blue), rate_update (yellow), default (gray)Auto-read:Automatically marks all unread notifications as read on page loadTime formatting:"I dag kl. HH:MM", "I går kl. HH:MM", or "DD.MM.YYYY kl. HH:MM"
/cards — Card Management (FUTURE — feature-flagged)
Note:Cards are a FUTURE feature, gated behind feature flags (all default tofalse). Requires a card issuing partner before activation.
File:app/cards/page.tsxType:Client componentAuth:Yes (useAuth())Feature flags:virtualCards(gate),physicalCards,cardPin,— allspendingLimitsdefaultpagestotestedat mobile/tablet/desktop breakpointsfalseComponentsDarkused:Button, Dialog, various lucide icons (CreditCard, Plus, ArrowLeft, Smartphone, Eye, EyeOff, Lock, X, Check, Copy, RefreshCw)State:cards, selectedCard, showDetails, showOrderForm, orderForm, loadingData fetching:GET/api/cards(list)POST/api/cards(create virtual)POST/api/cardswith type "physical"sidebar +addresslight(ordercontentphysical)area PATCH—consistent/api/cards/{id}withlayout{status:across"frozen"all| "active"}DELETEpages/api/cards/{id}
Card visual:Green gradient background, masked card number (•••• •••• •••• 4242), expiry, cardholder name