Ausgaben (Expenses)
Zweck
Expense modelliert Ausgaben mit unterschiedlicher Lebensdauer. Pro Datensatz wird über expenseType der Charakter festgelegt:
expenseType | Bedeutung | Typische Beispiele |
|---|---|---|
once | Einmal-Ausgabe an einem Datum | Buero-Moebel-Kauf, Software-Lizenz auf Dauer |
recurring | Wiederkehrende Ausgabe | Miete, Strom, Cloud-Abo |
contract | Laufzeit-Vertrag mit Kuendigungsfrist | Telekommunikations-Vertrag, Wartungs-Vertrag |
credit | Darlehen/Kredit mit Tilgungs-Computation | Annuitaeten-Darlehen, KfW, Kontokorrent-Linie |
Pro Typ werden dynamische Felder in typeConfig (JSON) gepflegt: SEPA-Mandat, Bankverbindung, Kreditparameter, Vertragsdetails. Computed Fields wie remainingPrincipal und remainingDebtTotal werden bei Krediten berechnet.
Voraussetzungen
Berechtigungen (CASL)
| Action | Subject | Wirkung | Keycloak-Rolle |
|---|---|---|---|
view | FE_Expense, Expense | Liste/Detail aufrufbar | — |
create/update/delete | Expense | Pflegen | APP_SPEAMCORE_CREATE/UPDATE/DELETE_EXPENSE |
view | Bank | Bank-Selectors für SEPA/Kredit | APP_SPEAMCORE_VIEW_BANK |
view | CostCenter | Kostenstellen-Sub-Liste | APP_SPEAMCORE_VIEW_COST_CENTER |
view | ExpenseItem | Item-Aufteilung-Sub-Liste | APP_SPEAMCORE_VIEW_EXPENSE_ITEM |
view | Document | Anhänge-Sub-Liste | APP_SPEAMCORE_VIEW_DOCUMENT |
Schritt-für-Schritt-Anleitung
Einmal-Ausgabe
- Ausgaben (
/expenses) → + Neu. expenseType = once(nicht editierbar nach Anlage).name,startDate(Buchungsdatum),amountüber Item-Aufteilung pflegen.
Wiederkehrende Ausgabe (z. B. Miete)
expenseType = recurring.startDatesetzen — optionalendDate, sonst laufend.- SEPA-Mandat aktivieren, falls Lastschrift verwendet wird → Bank wählen.
- Item-Aufteilung pflegen (z. B. Miete + Nebenkosten als zwei Items).
Vertrag mit Kuendigung
expenseType = contract.- Pflichtbereich:
cancellationNoticeInMonths,autoExtend,depositAmount. - SEPA-Block analog wie bei Recurring.
Kredit anlegen
expenseType = credit.- Grunddaten:
creditType(annuity,bullet,kfw,overdraft,shareholder),loanNumber. - Kredit-Bank über
loanBankIdwählen. - Lender / Borrower als Texte erfassen.
- Darlehenssumme:
loanAmount,disbursementDate. - Zinsen:
nominalInterestRateundfixedInterestYears. - Sondertilgung: entweder
specialRepaymentPercentoderspecialRepaymentYearly(sich gegenseitig ausschliessend). - Computed-Fields wie
paidMonths,remainingPrincipal,remainingDebtTotalwerden read-only vom Backend gepflegt.
Kostenstellen-Verteilung
Sub-Route /expenses/:id/cost-centers — die Ausgabe wird auf Kostenstellen prozentual verteilt.
Item-Aufteilung
Sub-Route /expenses/:id/expenses — eine Ausgabe kann in mehrere Items aufgeteilt werden (z. B. „Buero-Miete" 1.000 EUR aufgeteilt in „Miete" 800 + „Nebenkosten" 200).
Anhänge
Sub-Route /expenses/:id/documents — Verträge, Rechnungen, Tilgungsplaene als Dokumente.

Felder und Eingaben (Hauptfelder)
| Feldname | Pflicht | Datentyp | Wirkung beim Ausfuellen | Voraussetzung |
|---|---|---|---|---|
expenseType | ja (read-only nach Anlage) | ENUM (once, recurring, contract, credit) | Bestimmt die dynamischen Felder. | — |
name | nein | String | Anzeigename in Liste und Reports. | — |
amount | nein (read-only) | Decimal | Summen-Anzeige aus Item-Aufteilung. | — |
startDate | nein | Date | Bei once: Buchungsdatum. Bei recurring/contract/credit: Beginn. | — |
endDate | nein | Date | Bei recurring/contract/credit: Ende. | — |
cronJobId | nein | UUID | Verweist auf Cron-Job für wiederkehrende Erzeugung. | — |
parentType/parentId | nein | Polymorph | Optionale Verknuepfung mit Beleg/Vertrag. | — |
originExpenseId | nein | UUID | Bei wiederkehrenden Ausgaben: Verweis auf Original-Datensatz. | — |
typeConfig | nein | JSON | Dynamische Felder je expenseType. | — |
typeConfig-Felder (Auszug)
| Bereich | Feld | Bedeutung |
|---|---|---|
| SEPA | hasSepaMandate, sepaBankId | Lastschrift-Bank. |
| Vertrag | cancellationNoticeInMonths, autoExtend, depositAmount | Vertrags-Konditionen. |
| Kredit Grunddaten | creditType, loanNumber, loanBankId, lender, borrower | Identifikation. |
| Kredit Summe | loanAmount, disbursementDate | Auszahlung. |
| Kredit Zinsen | nominalInterestRate, fixedInterestYears | Konditionen. |
| Kredit Tilgung | specialRepaymentPercent ODER specialRepaymentYearly, repaymentAdjustable | Sondertilgungen. |
| Kredit Computed | paidMonths, remainingPrincipal, remainingDebtTotal | Berechnet, read-only. |
Toolbar (Detail-Seite)
Schlanke Toolbar oben rechts:
| Icon | Aktion (aria-label) | CASL | Wirkung |
|---|---|---|---|
| ← | Zurückgehen | — | Zurück zur Liste. |
| 🏠 | Zur Startseite gehen | — | Springt auf das Dashboard / /. |
| ⏮/◀/▶/⏭ | Pagination | — | Navigation durch die gefilterte Liste — Massen-Bearbeitung ohne Liste-Sprung. |
Globale Floating-Drawer (links)
Wie auf jeder Detail-Seite verfuegbar — siehe Floating-Quickbar:
- KAL. (Mini-Kalender)
- ZEIT (Persoenliche Wochen-Arbeitszeit)
- ARBEIT (Eigene bevorstehende Aufträge)
Wiederverwendbare Konzepte
- Buchhaltungskonten — Querschnitt zu Konto-Modellen.
- Polymorpher Parent-Pattern —
parentType/parentId. - Berechtigungen verstehen (CASL)
Verknuepfungen zu anderen Modulen
- Cron-Jobs — wiederkehrende Erzeugung neuer Buchungen aus
recurring/contract/credit-Ausgaben. - Kostenstellen — prozentuale Verteilung pro Ausgabe.
- Document-Center — Verträge, Rechnungen, Tilgungsplaene.
- Lieferanten — typischer Counterparty einer Ausgabe (über polymorph parent).
Häufige Fehler und Lösungen
| Fehler | Lösung |
|---|---|
| Felder erscheinen/verschwinden ohne Erklaerung | Form ist expenseType-getriggert. Felder mit invisible: values.expenseType !== "credit" werden ein-/ausgeblendet. |
| Sondertilgung-Felder beide gegrayt | Eines der beiden Felder ist gesetzt — das andere wird automatisch deaktiviert (Exklusion). |
| Bank-Selector leer | view:Bank-Berechtigung fehlt — Selectors haben requiredAbility: ["view", "Bank"]. |
| Kredit-Computed-Fields zeigen Null | Backend-Service hat noch keinen Zinslauf durchgeführt — typischerweise nach erstem disbursementDate-Cron. |
API/Schnittstellen
| Methode | Endpoint | Zweck | CASL |
|---|---|---|---|
GET | /api/expenses | Liste | view Expense |
POST | /api/expenses | Anlegen | create Expense |
GET | /api/expenses/:id | Detail | view Expense |
PATCH | /api/expenses/:id | Ändern | update Expense |
DELETE | /api/expenses/:id | Soft-Delete | delete Expense |
GET | /api/expense-cost-centers?filter[expenseId] | Kostenstellen-Verteilung | view ExpenseCostCenter |
GET | /api/expense-items?filter[expenseId] | Items-Aufteilung | view ExpenseItem |
GET | /api/documents?filter[parentType=Expense] | Anhänge | view Document |
Versionshinweise
- 2026-04-30: Initiale Veroeffentlichung mit FE-Tiefe (alle 4 expenseType-Varianten dokumentiert).