# Backend Krav - Dansk Bogføringssystem ## Overblik Dette dokument beskriver backend-kravene for det danske bogføringssystem. Frontend er implementeret i React/TypeScript med Ant Design og Zustand state management. --- ## 1. Regnskabsår (Fiscal Years) ### 1.1 Data Model ```typescript interface FiscalYear { id: string; companyId: string; name: string; // "2025" eller "2024/2025" startDate: string; // ISO date "YYYY-MM-DD" endDate: string; // ISO date "YYYY-MM-DD" status: 'open' | 'closed' | 'locked'; openingBalancePosted: boolean; closingDate?: string; // Når året blev lukket closedBy?: string; // Bruger ID createdAt: string; updatedAt: string; } ``` ### 1.2 API Endpoints | Endpoint | Metode | Beskrivelse | |----------|--------|-------------| | `/api/fiscal-years` | GET | Hent alle regnskabsår for aktiv virksomhed | | `/api/fiscal-years` | POST | Opret nyt regnskabsår | | `/api/fiscal-years/:id` | GET | Hent specifikt regnskabsår | | `/api/fiscal-years/:id` | PATCH | Opdater regnskabsår | | `/api/fiscal-years/:id/close` | POST | Luk regnskabsår (årsafslutning) | | `/api/fiscal-years/:id/reopen` | POST | Genåbn lukket regnskabsår | | `/api/fiscal-years/:id/lock` | POST | Lås regnskabsår permanent | ### 1.3 Forretningsregler #### Oprettelse - Nye regnskabsår må IKKE overlappe med eksisterende - Regnskabsår der "rører" ved grænsen (slutter/starter samme dag) er TILLADT - Understøt både kalenderår (jan-dec) og skæve regnskabsår (fx jul-jun) - Valider at regnskabsåret er mellem 300-400 dage (advarsel, ikke fejl) #### Årsafslutning (Year-End Closing) **KRITISK**: Ved årsafslutning skal backend: 1. **Validere** at regnskabsåret kan lukkes: - Ikke allerede låst - Advar om åbne perioder (men tillad lukning) - Advar om ikke-afstemte transaktioner 2. **Oprette lukkeposter** (closing entries): - Luk alle indtægtskonti til resultatoverførselskonto - Luk alle udgiftskonti til resultatoverførselskonto - Gem som normale transaktioner med særlig markering (`isClosingEntry: true`) 3. **Generere åbningsbalancer** til næste regnskabsår: - Beregn slutsaldo for alle balancekonti (aktiver, passiver, egenkapital) - Nulstil resultatkonti (indtægter, udgifter, vareforbrug, personale, finansielle) - Opret åbningsposteringer i næste regnskabsår (`isOpeningBalance: true`) 4. **Opdatere status**: - Sæt regnskabsår status til 'closed' eller 'locked' - Luk alle tilhørende regnskabsperioder - Sæt `openingBalancePosted: true` på næste regnskabsår #### Genåbning - Kun 'closed' regnskabsår kan genåbnes (ikke 'locked') - Ved genåbning skal åbningsbalancer i næste år opdateres automatisk - Log hvem der genåbnede og hvornår ### 1.4 Dynamiske Åbningsbalancer Frontend forventer at åbningsbalancer opdateres automatisk når der bogføres i et tidligere år (som Dinero): ``` Scenarie: 1. Regnskabsår 2024 er lukket, 2025 er åbent 2. Revisor finder fejl og bogfører korrektion i 2024 3. Backend skal automatisk genberegne åbningsbalancen for 2025 ``` --- ## 2. Regnskabsperioder (Accounting Periods) ### 2.1 Data Model ```typescript interface AccountingPeriod { id: string; fiscalYearId: string; companyId: string; name: string; // "Januar 2025", "Q1 2025" periodNumber: number; // 1-12 for månedlig startDate: string; endDate: string; status: 'future' | 'open' | 'closed' | 'locked'; closedAt?: string; closedBy?: string; reopenedAt?: string; reopenedBy?: string; lockedAt?: string; lockedBy?: string; createdAt: string; updatedAt: string; } type PeriodFrequency = 'monthly' | 'quarterly' | 'half-yearly' | 'yearly'; ``` ### 2.2 API Endpoints | Endpoint | Metode | Beskrivelse | |----------|--------|-------------| | `/api/periods` | GET | Hent perioder (filtrer på fiscalYearId) | | `/api/periods/:id` | PATCH | Opdater periode | | `/api/periods/:id/close` | POST | Luk periode | | `/api/periods/:id/reopen` | POST | Genåbn periode | | `/api/periods/:id/lock` | POST | Lås periode | ### 2.3 Forretningsregler - Perioder genereres automatisk ved oprettelse af regnskabsår - Understøt: månedlig (12), kvartalsvis (4), halvårlig (2), årlig (1) - Perioder kan kun lukkes i rækkefølge (periode 2 kræver periode 1 lukket) - Låste perioder kan IKKE genåbnes --- ## 3. Transaktioner med Periode-Reference ### 3.1 Udvidet Transaction Model ```typescript interface Transaction { id: string; companyId: string; fiscalYearId: string; // PÅKRÆVET - hvilket regnskabsår periodId: string; // PÅKRÆVET - hvilken periode journalEntryNumber: number; date: string; description: string; reference?: string; lines: TransactionLine[]; isVoided: boolean; isReconciled: boolean; isClosingEntry?: boolean; // NY - markering for lukkepost isOpeningBalance?: boolean; // NY - markering for åbningsbalance createdAt: string; updatedAt: string; createdBy: string; } ``` ### 3.2 Forretningsregler for Bogføring ```typescript interface PostingValidation { allowed: boolean; reason?: string; reasonDanish?: string; } ``` Backend skal validere ved bogføring: 1. Find periode for transaktionsdato 2. Tjek om perioden er åben 3. Tjek om regnskabsåret er åbent 4. Returner fejl med dansk besked hvis ikke tilladt --- ## 4. Kontoplan (Chart of Accounts) ### 4.1 Data Model ```typescript interface Account { id: string; companyId: string; accountNumber: string; // "1000", "3900" name: string; type: AccountType; parentId?: string; description?: string; vatCodeId?: string; isActive: boolean; isSystemAccount: boolean; // Kan ikke slettes balance: number; // Beregnet felt createdAt: string; updatedAt: string; } type AccountType = | 'asset' // Aktiver | 'liability' // Passiver | 'equity' // Egenkapital | 'revenue' // Indtægter | 'cogs' // Vareforbrug | 'expense' // Udgifter | 'personnel' // Personaleomkostninger | 'financial' // Finansielle poster | 'extraordinary'; // Ekstraordinære poster ``` ### 4.2 Systemkonti Følgende konti skal oprettes automatisk: - `3900` - Overført resultat (equity) - bruges til årsafslutning - Åbningsbalancekonto for primo-posteringer --- ## 5. Moms (VAT) ### 5.1 Data Model ```typescript interface VATCode { id: string; companyId: string; code: string; // "S25", "K25" name: string; rate: number; // 0.25 for 25% type: 'sales' | 'purchase' | 'eu_sales' | 'eu_purchase' | 'reverse_charge'; accountId: string; // Momskonto isActive: boolean; } interface VATPeriod { id: string; companyId: string; startDate: string; endDate: string; dueDate: string; // Indberetningsfrist status: 'open' | 'submitted' | 'paid'; salesVAT: number; // Beregnet purchaseVAT: number; // Beregnet netVAT: number; // salesVAT - purchaseVAT submittedAt?: string; paidAt?: string; } ``` ### 5.2 SKAT Integration (Fremtidig) - Momsindberetning til SKAT via NemVirksomhed API - Kvartalsvise eller månedlige momsperioder baseret på virksomhedsstørrelse --- ## 6. Virksomhed (Company) ### 6.1 Data Model ```typescript interface Company { id: string; name: string; cvr: string; // Dansk CVR-nummer address?: string; postalCode?: string; city?: string; country: string; // Default "DK" fiscalYearStart: number; // Måned 1-12 (default 1 for januar) currency: string; // Default "DKK" vatRegistered: boolean; vatPeriodFrequency: 'monthly' | 'quarterly' | 'half-yearly'; createdAt: string; updatedAt: string; } ``` --- ## 7. Fejlhåndtering Alle fejlbeskeder skal være tilgængelige på både engelsk og dansk: ```typescript interface APIError { code: string; message: string; messageDanish: string; details?: Record; } ``` ### Eksempler på fejlkoder | Kode | Engelsk | Dansk | |------|---------|-------| | `PERIOD_LOCKED` | Period is locked | Perioden er låst | | `FISCAL_YEAR_LOCKED` | Fiscal year is locked | Regnskabsåret er låst | | `OVERLAP_EXISTS` | Overlaps with existing fiscal year | Overlapper med eksisterende regnskabsår | | `UNBALANCED_ENTRY` | Debit and credit must be equal | Debet og kredit skal være ens | | `NO_COMPANY_SELECTED` | No company selected | Ingen virksomhed valgt | --- ## 8. Prioriteret Implementeringsrækkefølge ### Fase 1: Grundlæggende (MVP) 1. Company CRUD 2. Account CRUD med standard kontoplan 3. Transaction CRUD med validering 4. FiscalYear CRUD ### Fase 2: Periode-management 1. AccountingPeriod generering og CRUD 2. Periode-validering ved bogføring 3. Periode lukning/åbning ### Fase 3: Årsafslutning 1. Closing entries generering og bogføring 2. Opening balance beregning og bogføring 3. Dynamisk åbningsbalance-opdatering ### Fase 4: Moms 1. VATCode CRUD 2. VATPeriod generering 3. Momsberegning og -rapportering --- ## 9. Tekniske Krav ### Authentication - JWT-baseret authentication - Multi-tenant support (bruger kan have adgang til flere virksomheder) ### Database - PostgreSQL anbefales - Soft delete på alle entiteter - Audit trail (createdBy, updatedBy, deletedBy) ### API Format - RESTful JSON API - GraphQL som alternativ (valgfrit) - Pagination på liste-endpoints - Filtering og sorting support ### Valuta - Alle beløb i øre/cents (integers) for at undgå floating point problemer - Frontend konverterer til/fra DKK ved visning --- *Sidst opdateret: 17. januar 2026*