feat(sync): sync all FDISK members, auto-creating dashboard accounts for users not yet logged in
This commit is contained in:
186
.claude/plans/tingly-cooking-locket.md
Normal file
186
.claude/plans/tingly-cooking-locket.md
Normal file
@@ -0,0 +1,186 @@
|
||||
# Buchhaltung — Remaining Features Implementation Plan
|
||||
|
||||
## Context
|
||||
|
||||
The Buchhaltung system has core CRUD, transfers, bank statements, Haushaltsplan, and PDF export implemented. Three features from the original design doc remain:
|
||||
|
||||
1. **Budget Delegation Freigaben** — authorizes a user to spend against a budget account (distinct from the existing transaction-approval freigaben)
|
||||
2. **Split Booking Dialog** — book a pending transaction into N parts across different budget accounts
|
||||
3. **Sub-Budget Flow** — create budget delegation Freigaben from approved plan positions
|
||||
|
||||
---
|
||||
|
||||
## Task Dependency Graph
|
||||
|
||||
```
|
||||
T1: Migration 083 (budget_freigaben) T2: Migration 084 (split_gruppe_id)
|
||||
| |
|
||||
v v
|
||||
T3: Backend budget freigaben CRUD T4: Backend split booking endpoint
|
||||
| |
|
||||
+------------+ v
|
||||
| | T7: Frontend BookingDialog
|
||||
v v
|
||||
T5: Backend plan→ T6: Frontend budget
|
||||
freigabe endpoint freigaben tab + sidebar
|
||||
| |
|
||||
+-----+------+
|
||||
v
|
||||
T8: Frontend plan position → freigabe action
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tasks
|
||||
|
||||
### T1 — Migration 083: `buchhaltung_budget_freigaben` table
|
||||
**Teammate**: database | **blockedBy**: none
|
||||
|
||||
Create `backend/src/database/migrations/083_buchhaltung_budget_freigaben.sql`:
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS buchhaltung_budget_freigaben (
|
||||
id SERIAL PRIMARY KEY,
|
||||
konto_id INT NOT NULL REFERENCES buchhaltung_konten(id) ON DELETE CASCADE,
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
beschreibung TEXT,
|
||||
betrag_limit NUMERIC(12,2),
|
||||
planposition_id INT REFERENCES buchhaltung_planpositionen(id) ON DELETE SET NULL,
|
||||
aktiv BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
erstellt_von UUID REFERENCES users(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
CREATE INDEX idx_budget_freigaben_konto ON buchhaltung_budget_freigaben(konto_id);
|
||||
CREATE INDEX idx_budget_freigaben_user ON buchhaltung_budget_freigaben(user_id);
|
||||
```
|
||||
|
||||
### T2 — Migration 084: Add `split_gruppe_id` to transaktionen
|
||||
**Teammate**: database | **blockedBy**: none
|
||||
|
||||
Create `backend/src/database/migrations/084_buchhaltung_split_gruppe.sql`:
|
||||
```sql
|
||||
ALTER TABLE buchhaltung_transaktionen
|
||||
ADD COLUMN IF NOT EXISTS split_gruppe_id UUID;
|
||||
CREATE INDEX IF NOT EXISTS idx_buch_trans_split_gruppe
|
||||
ON buchhaltung_transaktionen(split_gruppe_id) WHERE split_gruppe_id IS NOT NULL;
|
||||
```
|
||||
|
||||
### T3 — Backend: Budget Freigaben CRUD
|
||||
**Teammate**: backend | **blockedBy**: T1
|
||||
|
||||
**Files**: `buchhaltung.service.ts`, `buchhaltung.controller.ts`, `buchhaltung.routes.ts`
|
||||
|
||||
Service functions (add before export block ~line 1937):
|
||||
- `listBudgetFreigaben(filters: { konto_id?, user_id? })` — JOIN users + konten for display names
|
||||
- `getMyBudgetFreigaben(userId)` — active freigaben for current user
|
||||
- `createBudgetFreigabe(data, erstelltVon)` — INSERT
|
||||
- `updateBudgetFreigabe(id, data, userId)` — UPDATE beschreibung/betrag_limit
|
||||
- `deactivateBudgetFreigabe(id, userId)` — SET aktiv=false
|
||||
|
||||
Routes (add BEFORE `/:id` catch-all routes):
|
||||
```
|
||||
GET /budget-freigaben manage_accounts listBudgetFreigaben
|
||||
GET /budget-freigaben/my buchhaltung:view getMyBudgetFreigaben
|
||||
POST /budget-freigaben manage_accounts createBudgetFreigabe
|
||||
PATCH /budget-freigaben/:id manage_accounts updateBudgetFreigabe
|
||||
DELETE /budget-freigaben/:id manage_accounts deactivateBudgetFreigabe
|
||||
```
|
||||
|
||||
### T4 — Backend: Split Booking Endpoint
|
||||
**Teammate**: backend | **blockedBy**: T2
|
||||
|
||||
**Files**: `buchhaltung.service.ts`, `buchhaltung.controller.ts`
|
||||
|
||||
Modify `bookTransaktion(id, userId, splits?)`:
|
||||
- No splits → existing behavior (unchanged)
|
||||
- With splits `Array<{ betrag, konto_id, bankkonto_id? }>`:
|
||||
1. Validate sum equals original betrag
|
||||
2. BEGIN transaction
|
||||
3. Generate UUID `split_gruppe_id`
|
||||
4. Mark original as `status='gebucht'`, set `split_gruppe_id`
|
||||
5. INSERT N new booked transactions copying fields from original but with split-specific betrag/konto_id/bankkonto_id, same `split_gruppe_id`
|
||||
6. Budget alert check per split konto
|
||||
7. Audit: `logAudit(id, 'split_gebucht', { splits, split_gruppe_id }, userId)`
|
||||
|
||||
Controller: read optional `req.body.splits`, pass to service.
|
||||
|
||||
### T5 — Backend: Plan Position → Freigabe Endpoint
|
||||
**Teammate**: backend | **blockedBy**: T3
|
||||
|
||||
**Files**: `buchhaltung.service.ts`, `buchhaltung.controller.ts`, `buchhaltung.routes.ts`
|
||||
|
||||
New function `createBudgetFreigabeFromPlanposition(posId, { user_id, betrag_limit?, beschreibung? }, erstelltVon)`:
|
||||
- Fetch planposition, verify konto_id exists
|
||||
- Default betrag_limit to sum of budget_gwg + budget_anlagen + budget_instandhaltung
|
||||
- Call `createBudgetFreigabe` with `planposition_id` set
|
||||
|
||||
Route: `POST /planung/positionen/:posId/freigabe` — manage_accounts
|
||||
|
||||
### T6 — Frontend: Budget Freigaben Tab + Sidebar
|
||||
**Teammate**: frontend | **blockedBy**: T3
|
||||
|
||||
**Files**: `buchhaltung.types.ts`, `buchhaltung.ts`, `Buchhaltung.tsx`, `Sidebar.tsx`
|
||||
|
||||
Types:
|
||||
- `BudgetFreigabe` — id, konto_id, user_id, beschreibung, betrag_limit, planposition_id, aktiv, konto_bezeichnung, user_name
|
||||
- `BudgetFreigabeFormData` — konto_id, user_id, beschreibung?, betrag_limit?
|
||||
|
||||
Service: `getBudgetFreigaben`, `getMyBudgetFreigaben`, `createBudgetFreigabe`, `updateBudgetFreigabe`, `deleteBudgetFreigabe`
|
||||
|
||||
Buchhaltung.tsx:
|
||||
- Add tab 3 "Freigaben" (visible only with `manage_accounts`)
|
||||
- Table: Konto, Benutzer, Beschreibung, Betrag-Limit, Status, Aktionen
|
||||
- Create/Edit dialog with Konto select, User select, Betrag-Limit, Beschreibung
|
||||
- Pattern: follow TransaktionenTab Table+Dialog structure
|
||||
|
||||
Sidebar.tsx (~line 155): add `{ text: 'Freigaben', path: '/buchhaltung?tab=3' }` to buchhaltung subItems
|
||||
|
||||
### T7 — Frontend: Split Booking Dialog
|
||||
**Teammate**: frontend | **blockedBy**: T4
|
||||
|
||||
**Files**: `buchhaltung.types.ts`, `buchhaltung.ts`, `Buchhaltung.tsx`
|
||||
|
||||
Types: add `SplitRow { betrag: number; konto_id: number; bankkonto_id?: number }`
|
||||
|
||||
Service: update `buchenTransaktion(id, splits?)` to POST body with optional splits array
|
||||
|
||||
Buchhaltung.tsx:
|
||||
- Add `BookingDialog` component (inline):
|
||||
- Shows transaction details (betrag, beschreibung)
|
||||
- "Einfach buchen" button for simple booking (no splits)
|
||||
- "Aufteilen" toggle reveals split rows
|
||||
- Each row: betrag input, konto select, bankkonto select, remove button
|
||||
- "Zeile hinzufuegen" button
|
||||
- Sum validation with remaining amount display
|
||||
- "Buchen" button
|
||||
- Replace buchen IconButton click: open BookingDialog instead of direct mutation
|
||||
- Update `buchenMut` to accept `{ id, splits? }`
|
||||
|
||||
### T8 — Frontend: Plan Position → Freigabe Action
|
||||
**Teammate**: frontend | **blockedBy**: T5, T6
|
||||
|
||||
**Files**: `buchhaltung.ts`, `HaushaltsplanDetail.tsx`
|
||||
|
||||
Service: add `createBudgetFreigabeFromPosition(posId, { user_id, betrag_limit?, beschreibung? })`
|
||||
|
||||
HaushaltsplanDetail.tsx:
|
||||
- Add "Freigabe erstellen" IconButton per position row (only when canManage && pos.konto_id set)
|
||||
- Dialog: User select (fetch members), Betrag-Limit (pre-filled from position total), Beschreibung (pre-filled from position name)
|
||||
- Pattern: follow existing position edit dialog
|
||||
|
||||
---
|
||||
|
||||
## Teammate Assignments
|
||||
|
||||
| Teammate | Tasks | Mode |
|
||||
|----------|-------|------|
|
||||
| database | T1, T2 | bypassPermissions |
|
||||
| backend | T3, T4, T5 | bypassPermissions |
|
||||
| frontend | T6, T7, T8 | bypassPermissions |
|
||||
|
||||
## Verification
|
||||
|
||||
1. Migration: check tables exist via backend startup logs
|
||||
2. Backend: test budget-freigaben CRUD via curl/frontend
|
||||
3. Frontend: verify Freigaben tab renders, BookingDialog opens on buchen click
|
||||
4. Split booking: create pending transaction, open dialog, add split rows, book
|
||||
5. Plan→Freigabe: open HaushaltsplanDetail, click freigabe button on position with konto_id
|
||||
Reference in New Issue
Block a user