books/backend/BACKEND_REQUIREMENTS.md

356 lines
9.6 KiB
Markdown
Raw Permalink Normal View History

# 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<string, unknown>;
}
```
### 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*