Docs: Datenbankstruktur dokumentiert

This commit is contained in:
fds2610-bot 2026-04-12 19:55:51 +02:00
parent adaf39ebbc
commit 7e2af89748
2 changed files with 285 additions and 0 deletions

View file

@ -49,6 +49,7 @@ Anwendung aufrufen: `http://localhost:8080`
| [Anlagevermögen](docs/anlagevermögen.md) | Anlagenspiegel, Buchungsworkflow, Nummernkreis | | [Anlagevermögen](docs/anlagevermögen.md) | Anlagenspiegel, Buchungsworkflow, Nummernkreis |
| [Update & Backup](docs/update-backup.md) | Update-Anleitung, Backup, Datenpersistenz | | [Update & Backup](docs/update-backup.md) | Update-Anleitung, Backup, Datenpersistenz |
| [Automatisierung](docs/automatisierung.md) | Automatisierungsagent, Ideenagent, Support | | [Automatisierung](docs/automatisierung.md) | Automatisierungsagent, Ideenagent, Support |
| [Datenbankstruktur](docs/datenbankstruktur.md) | Tabellen, Spalten, Fremdschlüssel, GoBD-Mechanismen |
| [Berechnungslogik](docs/berechnungslogik.md) | UStVA-Kennzahlen und EÜR-Zuordnungsregeln | | [Berechnungslogik](docs/berechnungslogik.md) | UStVA-Kennzahlen und EÜR-Zuordnungsregeln |
| [Kontenrahmen](docs/kontenrahmen.md) | Vollständige SKR03-Kontenliste | | [Kontenrahmen](docs/kontenrahmen.md) | Vollständige SKR03-Kontenliste |

284
docs/datenbankstruktur.md Normal file
View file

@ -0,0 +1,284 @@
# Datenbankstruktur
MariaDB 11, Engine InnoDB, Zeichensatz `utf8mb4_unicode_ci`. Das Schema wird durch nummerierte Migrations-Dateien in `migrations/` verwaltet und beim Container-Start automatisch eingespielt.
---
## Übersicht
| Tabelle | Zweck |
|---|---|
| `fiscal_years` | Geschäftsjahre |
| `accounts` | Kontenrahmen SKR03 |
| `company_settings` | Firmendaten und Einstellungen (Singleton) |
| `customers` | Kundenstammdaten |
| `belege` | Belegdokumente |
| `bookings` | Buchungszeilen (EÜR-Journal) |
| `invoices` | Ausgangsrechnungen |
| `invoice_lines` | Rechnungspositionen |
| `users` | Benutzerkonten |
| `ustva_submissions` | UStVA-Einreichungen |
| `audit_log` | GoBD-Audit-Log |
| `schema_migrations` | Protokoll angewendeter Migrationen |
---
## Tabellen im Detail
### `fiscal_years` – Geschäftsjahre
| Spalte | Typ | Beschreibung |
|---|---|---|
| `id` | INT UNSIGNED PK | |
| `year` | SMALLINT UNSIGNED UNIQUE | Jahreszahl (z.B. 2026) |
| `start_date` | DATE | Beginn des Geschäftsjahres |
| `end_date` | DATE | Ende des Geschäftsjahres |
| `locked` | TINYINT(1) | `1` = Jahr abgeschlossen, keine neuen Buchungen möglich |
| `created_at` | DATETIME | |
---
### `accounts` – Kontenrahmen SKR03
| Spalte | Typ | Beschreibung |
|---|---|---|
| `id` | INT UNSIGNED PK | |
| `kontonummer` | VARCHAR(10) UNIQUE | DATEV-Kontonummer |
| `bezeichnung` | VARCHAR(255) | Kontobezeichnung |
| `kontenart` | ENUM | `Betriebseinnahme`, `Betriebsausgabe`, `Anlagevermögen`, `Zahlungskonto`, `Verbindlichkeit`, `Privat` |
| `beschreibung` | TEXT | Erläuterungstext |
| `steuercode` | VARCHAR(20) | `USt19`, `USt7`, `VSt19`, `VSt7` oder leer |
| `ustva_kz` | VARCHAR(10) | ELSTER-Kennzahl (z.B. `81`, `35`) |
| `euer_zeile` | VARCHAR(5) | Zeilennummer Anlage EÜR (z.B. `14`, `51`) |
| `is_system` | TINYINT(1) | `1` = SKR03-Standardkonto |
| `aktiv` | TINYINT(1) | `0` = deaktiviert |
| `created_at` / `updated_at` | DATETIME | |
---
### `company_settings` – Firmendaten (Singleton, id=1)
| Spalte | Typ | Beschreibung |
|---|---|---|
| `id` | INT UNSIGNED PK | Immer `1` |
| `firma` | VARCHAR(255) | Firmenname |
| `inhaber` | VARCHAR(255) | Inhabername |
| `strasse`, `plz`, `ort` | VARCHAR | Adresse |
| `telefon`, `email`, `website` | VARCHAR | Kontaktdaten |
| `ust_id` | VARCHAR(20) | Umsatzsteuer-ID (DE...) |
| `steuernummer` | VARCHAR(30) | Steuernummer beim Finanzamt |
| `finanzamt` | VARCHAR(255) | Zuständiges Finanzamt |
| `iban`, `bic`, `bank_name` | VARCHAR | Bankverbindung |
| `logo_path` | VARCHAR(500) | Pfad zum Logo-PNG |
| `ustva_steuernummer` | VARCHAR(20) | ELSTER-Format: `FFFBBBBBBUUUUP` |
| `ustva_bundesland` | VARCHAR(2) | Bundesland-Kürzel (z.B. `BY`) |
| `invoice_nr_prefix` | VARCHAR(10) | Präfix Rechnungsnummer (Standard: `AR`) |
| `invoice_nr_next` | INT UNSIGNED | Nächste Rechnungsnummer |
| `invoice_nr_year` | SMALLINT UNSIGNED | Jahresstand des Rechnungszählers |
| `beleg_nr_prefix` | VARCHAR(10) | Präfix Belegnummer (Standard: `BLG`) |
| `beleg_nr_next` | INT UNSIGNED | Nächste Belegnummer |
| `anlage_nr_prefix` | VARCHAR(10) | Präfix Anlagen-Nummer (Standard: `ANL`) |
| `anlage_nr_next` | INT UNSIGNED | Nächste Anlagen-Nummer |
| `payment_days_default` | INT UNSIGNED | Standard-Zahlungsziel in Tagen |
| `ki_vorschlag_aktiv` | TINYINT(1) | KI-Kontierungsvorschlag aktiviert |
| `nextcloud_url` | VARCHAR(500) | WebDAV-URL der Nextcloud-Instanz |
| `nextcloud_user` | VARCHAR(255) | Nextcloud-Benutzername |
| `nextcloud_pass` | VARCHAR(500) | Nextcloud-Passwort / App-Passwort |
| `nextcloud_folder` | VARCHAR(500) | Import-Quellordner (Standard: `/Belege/Import`) |
| `nextcloud_done` | VARCHAR(500) | Zielordner nach erfolgreichem Import |
| `updated_at` | DATETIME | |
---
### `customers` – Kundenstammdaten
| Spalte | Typ | Beschreibung |
|---|---|---|
| `id` | INT UNSIGNED PK | |
| `kundennummer` | VARCHAR(20) UNIQUE | |
| `firma` | VARCHAR(255) | Firmenname (optional) |
| `anrede`, `vorname`, `nachname` | VARCHAR | Ansprechpartner |
| `strasse`, `plz`, `ort`, `land` | VARCHAR | Adresse |
| `email`, `telefon` | VARCHAR | Kontakt |
| `ust_id` | VARCHAR(20) | USt-ID des Kunden (B2B) |
| `steuernummer` | VARCHAR(30) | |
| `payment_days` | INT UNSIGNED | Zahlungsziel in Tagen |
| `notes` | TEXT | Interne Notizen |
| `archived` | TINYINT(1) | `1` = archiviert |
| `created_at` / `updated_at` | DATETIME | |
---
### `belege` – Belegdokumente
| Spalte | Typ | Beschreibung |
|---|---|---|
| `id` | INT UNSIGNED PK | |
| `beleg_nr` | VARCHAR(30) UNIQUE | Automatisch vergeben (z.B. `BLG-2026-0001`) |
| `filename` | VARCHAR(500) | Originaldateiname |
| `storage_path` | VARCHAR(500) | Pfad unter `public/static/uploads/` |
| `mime_type` | VARCHAR(100) | MIME-Typ der Datei |
| `file_hash` | VARCHAR(64) | SHA-256 für GoBD-Integritätsprüfung |
| `beleg_datum` | DATE | Datum auf dem Dokument |
| `rechnungs_nr` | VARCHAR(100) | Rechnungsnummer des Lieferanten |
| `betrag_brutto` | DECIMAL(12,2) | Bruttobetrag laut Dokument |
| `belegtyp` | ENUM | `Eingangsrechnung`, `Ausgangsrechnung`, `Quittung`, `Kontoauszug`, `Sonstiges` |
| `notes` | TEXT | Interne Notizen |
| `bewirtungsgrund` | TEXT | Anlass der Bewirtung (§ 4 Abs. 5 Nr. 2 EStG) |
| `teilnehmerliste` | TEXT | Teilnehmer der Bewirtung |
| `eigenanteil_30` | TINYINT(1) | `1` = 30%-Eigenanteil beim Buchen markiert |
| `ki_vorschlag` | JSON | KI-Kontierungsvorschlag |
| `ki_vorschlag_at` | TIMESTAMP | Zeitpunkt der KI-Analyse |
| `beleg_text` | MEDIUMTEXT | Extrahierter OCR-Text |
| `locked` | TINYINT(1) | GoBD: mit Geschäftsjahr gesperrt |
| `fiscal_year_id` | INT UNSIGNED FK | → `fiscal_years.id` |
| `created_at` / `updated_at` | DATETIME | |
---
### `bookings` – Buchungszeilen (EÜR-Journal)
GoBD-gesichert: MariaDB-Trigger verhindern Änderungen und Löschungen gesperrter Buchungen.
| Spalte | Typ | Beschreibung |
|---|---|---|
| `id` | INT UNSIGNED PK | |
| `buchungs_nr` | VARCHAR(30) UNIQUE | Automatisch vergeben |
| `beleg_id` | INT UNSIGNED FK | → `belege.id` |
| `asset_id` | INT UNSIGNED FK | → `assets.id` (nur bei Anlagevermögen-Buchungen) |
| `buchungs_datum` | DATE | |
| `buchungstyp` | ENUM | `Einnahme`, `Ausgabe` |
| `kategorie_konto_id` | INT UNSIGNED FK | → `accounts.id` (Was?) |
| `zahlungskonto_id` | INT UNSIGNED FK | → `accounts.id` (Wie bezahlt?) |
| `betrag_netto` | DECIMAL(12,2) | |
| `ust_satz` | DECIMAL(5,2) | Steuersatz in % (0, 7, 19) |
| `steuerart` | ENUM | `normal`, `ig_lieferung`, `export`, `ig_erwerb_19`, `ig_erwerb_7` |
| `betrag_ust` | DECIMAL(12,2) | |
| `betrag_brutto` | DECIMAL(12,2) | |
| `buchungstext` | VARCHAR(500) | |
| `is_reversal` | TINYINT(1) | `1` = Stornobuchung |
| `reversed_by` | INT UNSIGNED | ID der zugehörigen Stornobuchung |
| `locked` | TINYINT(1) | GoBD: unveränderlich |
| `fiscal_year_id` | INT UNSIGNED FK | → `fiscal_years.id` |
| `created_at` | DATETIME | |
> **Hinweis:** Die Spalte `asset_id` existiert nur nach Migration 030 (Feature-Branch `Betriebsvermögen`).
---
### `assets` – Anlagegüter (Wirtschaftsgüter)
> Diese Tabelle existiert nur nach Migration 028 (Feature-Branch `Betriebsvermögen`).
| Spalte | Typ | Beschreibung |
|---|---|---|
| `id` | INT UNSIGNED PK | |
| `lfd_nr` | INT UNSIGNED | Laufende Nummer |
| `anlage_nr` | VARCHAR(30) | Anlagen-Nummer (z.B. `ANL-2026-0001`) |
| `bezeichnung` | VARCHAR(255) | Bezeichnung des Wirtschaftsguts |
| `account_id` | INT UNSIGNED FK | → `accounts.id` (Anlageart) |
| `anschaffungsdatum` | DATE | |
| `anschaffungskosten` | DECIMAL(12,2) | Netto-Anschaffungskosten |
| `zugaenge` | DECIMAL(12,2) | Nachträgliche Anschaffungskosten |
| `abgaenge` | DECIMAL(12,2) | Wertminderungen |
| `abschreibung_jahr` | DECIMAL(12,2) | AfA laufendes Wirtschaftsjahr |
| `nutzungsdauer` | INT UNSIGNED | Nutzungsdauer in Jahren |
| `notizen` | TEXT | |
| `fiscal_year_id` | INT UNSIGNED FK | → `fiscal_years.id` |
| `created_at` / `updated_at` | DATETIME | |
---
### `invoices` – Ausgangsrechnungen
| Spalte | Typ | Beschreibung |
|---|---|---|
| `id` | INT UNSIGNED PK | |
| `rechnungs_nr` | VARCHAR(30) UNIQUE | `NULL` solange Entwurf |
| `customer_id` | INT UNSIGNED FK | → `customers.id` |
| `betreff` | VARCHAR(500) | |
| `leistungszeitraum_von` / `_bis` | DATE | |
| `rechnungs_datum` | DATE | |
| `faellig_datum` | DATE | |
| `status` | ENUM | `Entwurf`, `Gesendet`, `Bezahlt`, `Storniert` |
| `betrag_netto` / `_ust` / `_brutto` | DECIMAL(12,2) | Summenspalten |
| `beleg_id` | INT UNSIGNED FK | → `belege.id` |
| `notes` | TEXT | |
| `fiscal_year_id` | INT UNSIGNED FK | → `fiscal_years.id` |
| `created_at` / `updated_at` | DATETIME | |
---
### `invoice_lines` – Rechnungspositionen
| Spalte | Typ | Beschreibung |
|---|---|---|
| `id` | INT UNSIGNED PK | |
| `invoice_id` | INT UNSIGNED FK | → `invoices.id` (CASCADE DELETE) |
| `position` | SMALLINT UNSIGNED | Positionsnummer |
| `bezeichnung` | VARCHAR(500) | |
| `menge` | DECIMAL(10,3) | |
| `einheit` | VARCHAR(20) | z.B. `Stk.`, `h` |
| `einzelpreis` | DECIMAL(12,2) | Netto-Einzelpreis |
| `ust_satz` | DECIMAL(5,2) | |
| `betrag_netto` / `_ust` / `_brutto` | DECIMAL(12,2) | |
---
### `users` – Benutzerkonten
| Spalte | Typ | Beschreibung |
|---|---|---|
| `id` | INT UNSIGNED PK | |
| `username` | VARCHAR(64) UNIQUE | |
| `password_hash` | VARCHAR(255) | bcrypt |
| `active` | TINYINT(1) | `0` = deaktiviert |
| `created_at` | DATETIME | |
---
### `ustva_submissions` – UStVA-Einreichungen
| Spalte | Typ | Beschreibung |
|---|---|---|
| `id` | INT UNSIGNED PK | |
| `year` | SMALLINT UNSIGNED | Meldejahr |
| `month` | TINYINT UNSIGNED | Meldemonat (1–12) |
| `xml_content` | MEDIUMTEXT | Generiertes ELSTER-XML |
| `field_values` | JSON | Kennzahlen als JSON |
| `submitted_at` | DATETIME | `NULL` = noch nicht eingereicht |
| `status` | ENUM | `Erstellt`, `Eingereicht` |
| `created_at` | DATETIME | |
UNIQUE KEY auf `(year, month)`.
---
### `audit_log` – GoBD-Audit-Log
| Spalte | Typ | Beschreibung |
|---|---|---|
| `id` | BIGINT UNSIGNED PK | |
| `timestamp` | DATETIME | |
| `table_name` | VARCHAR(50) | Betroffene Tabelle |
| `record_id` | INT UNSIGNED | Betroffener Datensatz |
| `action` | ENUM | `INSERT`, `UPDATE`, `DELETE`, `LOCK` |
| `old_values` | JSON | Werte vor der Änderung |
| `new_values` | JSON | Werte nach der Änderung |
| `ip_address` | VARCHAR(45) | |
| `user_agent` | VARCHAR(500) | |
---
## GoBD-Mechanismen
- **Trigger `bookings_before_update` / `bookings_before_delete`**: Jeder Versuch, eine gesperrte Buchung (`locked = 1`) zu ändern oder zu löschen, wird mit einem SQL-Fehler abgewiesen.
- **`file_hash` in `belege`**: SHA-256-Prüfsumme jedes Belegdokuments; erlaubt nachträgliche Integritätsprüfung.
- **`audit_log`**: Protokolliert alle Datenbankänderungen mit alten und neuen Werten.
- **Stornobuchungen** statt Löschungen: Korrekturen erzeugen eine Gegenbuchung, die ursprüngliche Buchung bleibt erhalten.
---
## Migrationen
Schemaänderungen kommen ausschließlich als nummerierte SQL-Dateien in `migrations/` und werden vom Script `scripts/migrate.php` beim Container-Start automatisch eingespielt. Die Tabelle `schema_migrations` protokolliert, welche Dateien bereits angewendet wurden.