No description
Find a file
2026-06-11 20:11:10 +02:00
.gitea/ISSUE_TEMPLATE minor changes 2026-03-25 14:35:29 +01:00
apache Fix: Cache-Control-Header für PHP (no-cache) und Assets (immutable) 2026-04-27 13:11:57 +02:00
docs fix: CSV-Importformat in Direktverbindungs-Dialog ergänzen (closes #102) 2026-06-11 19:03:43 +02:00
migrations Feature: E-Mail-Betreff und -Text pro Kunde statt global 2026-05-30 14:22:57 +02:00
php Fix: Timezone Europe/Berlin für Container und PHP gesetzt 2026-05-16 08:30:59 +02:00
public Fix #55: LLM-Verbindungstest mit Diagnoseausgabe 2026-06-08 21:03:54 +02:00
scripts Feature: FinTS-Direktverbindung und vereinheitlichte Importquellen 2026-05-22 07:17:00 +02:00
src Merge main in feature/buchungsvorlagen (Changes.md-Konflikt aufgelöst) 2026-06-11 20:11:10 +02:00
tests Merge main in automate/issue-103 (Changes.md-Konflikt aufgelöst) 2026-06-11 20:07:00 +02:00
.dockerignore 30% Eigenanteil für Telefon und Internet + Tests mit KI Beleg-Erkennung 2026-03-30 16:53:47 +02:00
.env.example Anlagevermögen überarbeitet, AFA 2026-05-24 12:56:21 +02:00
.gitignore Docs: berechnungslogik.md und funktionen.md aktualisiert (UStVA-Abschnitt ausgebaut, ElsterXmlService ergaenzt, Funktionsliste ergaenzt) 2026-05-03 18:48:40 +02:00
activate.sh added systemd service 2026-03-25 13:31:34 +01:00
Changes.md Merge main in feature/buchungsvorlagen (Changes.md-Konflikt aufgelöst) 2026-06-11 20:11:10 +02:00
CLAUDE.md Docs: README verschlankt, docs/-Verzeichnis mit Unterseiten je Bereich 2026-04-12 19:20:25 +02:00
composer.json Feature: FinTS-Direktverbindung und vereinheitlichte Importquellen 2026-05-22 07:17:00 +02:00
composer.lock Feature: FinTS-Direktverbindung und vereinheitlichte Importquellen 2026-05-22 07:17:00 +02:00
docker-compose.yml Anlagevermögen überarbeitet, AFA 2026-05-24 12:56:21 +02:00
docker-entrypoint.sh Automatische DB-Migrationen beim Container-Start 2026-03-29 13:19:15 +02:00
Dockerfile Fix: horstoeko/zugferd in composer.json + composer.lock versionieren, Dockerfile-Composer-Fehler nicht mehr verschlucken 2026-05-03 18:17:19 +02:00
install.sh Changes.md erstellt, README.md und install.sh aktualisiert 2026-03-25 16:00:29 +01:00
LICENSE.md added LICENSE.md 2026-03-25 00:44:02 +01:00
README.md Merge main: Konflikte aufgelöst (OCR entfernt, Anlagevermögen behalten) 2026-04-15 20:35:18 +02:00
steuerkram.service minor changes 2026-03-25 14:35:29 +01:00

Steuerkram

Self-hosted Buchhaltungs- und Steueranwendung für deutsche Freiberufler und Kleinunternehmer. Entwickelt als datensouveräne Alternative zu SaaS-Diensten – mit Unterstützung von Claude Code.

PHP MariaDB Docker License: MIT


Funktionsumfang

Bereich Beschreibung
Kontenrahmen SKR03 DATEV-konform, 157 Konten, mit UStVA-Kennzahlen und EÜR-Zeilennummern
Belegverwaltung PDF, PNG, TIFF, ZUGFeRD-XML; SHA-256 Integritätsprüfung; optionale KI-Kontierung
Buchungen EÜR-Modell (Einnahme/Ausgabe); GoBD-konforme Trigger; Stornobuchungen; Journal
Anlagevermögen Anlagenspiegel; automatische Anlagen-Nummerierung; Buchungsworkflow mit Asset-Verknüpfung
Ausgangsrechnungen DIN 5008, PDF-Export via mPDF
UStVA Kennzahlen-Berechnung, ELSTER XML-Export, Drill-down
EÜR Jahresauswertung, PDF-Export, Drill-down
Kundenverwaltung CRUD
Einstellungen Firmendaten, Logo, ELSTER-Steuernummer, Nummernkreise
Benutzerverwaltung Mehrbenutzer, Session-Auth mit 24 h Timeout

Schnellstart

curl -fsSL https://codeberg.org/fds2610/Steuerkram/raw/branch/main/install.sh -o install.sh
sudo bash install.sh
cd /opt/Steuerkram
docker compose up -d

Manuelle Installation

1. Repository klonen

git clone <repository-url> steuerkram
cd steuerkram

2. Konfiguration anpassen

Kopiere .env.example nach .env und passe die Werte an:

cp .env.example .env
DB_PASS=sicheres-passwort        # Datenbankpasswort – in docker-compose.yml spiegeln
APP_SECRET=zufaelliger-string    # Zufälligen langen String eintragen (für Sessions)

Außerdem in docker-compose.yml das MARIADB_PASSWORD im db-Service auf denselben Wert wie DB_PASS setzen.

3. Container starten

docker compose up -d

Beim ersten Start werden automatisch:

  • die Datenbank initialisiert (migrations/001_initial_schema.sql)
  • der SKR03-Kontenrahmen eingespielt (migrations/002_seed_skr03.sql)
  • das Docker-Image mit PHP-Abhängigkeiten (mPDF) gebaut

4. Anwendung aufrufen

http://localhost:8080

Beim ersten Aufruf erscheint die Ersteinrichtung: dort den ersten Benutzer-Account anlegen. Danach ist die Anwendung passwortgeschützt.

Weitere Benutzer können nach dem Login unter Benutzer in der Seitenleiste verwaltet werden.

5. KI-Beleganalyse einrichten (optional)

Die KI-gestützte Belegerkennung ist standardmäßig deaktiviert. Sie kann unter Einstellungen → KI-Kontierungsvorschlag aktiviert werden, sobald ein LLM erreichbar ist.

Option A – Lokales Ollama (kein API-Schlüssel nötig, aber hoher Ressourcenbedarf):

ollama pull mistral   # oder llama3.2 etc.

In .env ist keine weitere Konfiguration nötig – die App erkennt Ollama auf localhost:11434 automatisch. Modell und URL können optional überschrieben werden:

OLLAMA_URL=http://localhost:11434
OLLAMA_MODEL=mistral

Option B – Remote-API (OpenAI-kompatibel, z. B. OpenAI, OpenRouter, LM Studio):

LLM_API_URL=https://api.openai.com/v1
LLM_API_KEY=sk-...
LLM_MODEL=gpt-4o-mini

Hinweis: Die Ergebnisqualität hängt stark vom gewählten Modell ab. Tests mit mistral (lokal via Ollama) lieferten bisher mäßige Ergebnisse.

6. Firmendaten hinterlegen

Nach dem ersten Login unter Einstellungen Firmendaten, Logo und ELSTER-Steuernummer eintragen. Diese Angaben erscheinen auf Ausgangsrechnungen und im EÜR-Export.

Port ändern

Der Standard-Port ist 8080. Um ihn zu ändern, passe in docker-compose.yml die ports-Zeile an:

ports:
  - "9090:80"   # Beispiel: Port 9090 auf dem Host

Upload-Limit anpassen

Die maximale Dateigröße für Beleganhänge ist auf 20 MB voreingestellt (php/uploads.ini). Um das Limit zu ändern, die Werte in dieser Datei anpassen und den Container neu bauen:

upload_max_filesize = 20M
post_max_size = 20M
docker compose up -d --build

Belege automatisch aus Nextcloud importieren

Belege können automatisch aus einem Nextcloud-Ordner via WebDAV importiert werden. Das CLI-Skript scripts/nextcloud-import.php liest alle unterstützten Dateien (PDF, JPEG, PNG, TIFF, XML) aus dem konfigurierten Ordner, legt sie als Belege an und verschiebt sie anschließend in einen Erledigte-Ordner (oder löscht sie, wenn kein Ziel-Ordner konfiguriert ist).

Konfiguration

Die Zugangsdaten werden in der Steuerkram-UI gepflegt: Einstellungen → Nextcloud-Belegimport.

Empfehlung: Ein Nextcloud-App-Passwort verwenden (Nextcloud → Einstellungen → Sicherheit → App-Passwörter).

Manueller Aufruf

docker compose exec web php scripts/nextcloud-import.php

Automatisch per Cron (auf dem Host)

Für den automatischen Abruf muss ein Cron-Eintrag auf dem Host angelegt werden. Dabei gibt es zwei Varianten:

Option 1: Root-Crontab (sudo crontab -e)

*/15 * * * * docker compose -f /opt/steuerkram/docker-compose.yml exec -T web \
    php scripts/nextcloud-import.php >> /var/log/steuerkram-import.log 2>&1

Kein sudo im Befehl nötig. Nachteil: Root-Crons sind schwerer zu überblicken.

Option 2: User-Crontab (crontab -e) – empfohlen

Damit docker compose exec ohne sudo funktioniert, muss der User in der Docker-Gruppe sein:

sudo usermod -aG docker $USER
# Danach neu einloggen

Anschließend in der User-Crontab (ohne sudo):

*/15 * * * * docker compose -f /home/fds/projects/Steuerkram/docker-compose.yml exec -T web \
    php scripts/nextcloud-import.php >> /var/log/steuerkram-import.log 2>&1

Hinweis: Das -T-Flag ist bei Cron zwingend erforderlich – ohne TTY schlägt docker compose exec sonst still fehl.

Empfehlung: User-Crontab + Docker-Gruppe. Das ist konsistent mit dem bestehenden Setup (alle anderen Jobs laufen ebenfalls in der User-Crontab).

Das Skript gibt beim Start eine Zusammenfassung aus (importiert / übersprungen / Fehler) und beendet sich mit Exit-Code 1 bei Fehlern.

Datenpersistenz

Pfad Inhalt
./data/mariadb/ MariaDB-Datenbankdateien
Docker Volume uploads Hochgeladene Belege

Beide Pfade liegen außerhalb des Containers und bleiben bei docker compose down erhalten.

Systemd-Service einrichten

Damit Steuerkram automatisch beim Systemstart startet und als Dienst verwaltet werden kann, liegt im Repository die Datei steuerkram.service.

1. Service-Datei installieren

sudo cp steuerkram.service /etc/systemd/system/steuerkram.service

Die Datei setzt WorkingDirectory=/opt/Steuerkram voraus. Falls das Repository in ein anderes Verzeichnis geklont wurde, den Pfad in der Service-Datei anpassen:

sudo nano /etc/systemd/system/steuerkram.service
# WorkingDirectory= auf das tatsächliche Installationsverzeichnis setzen

2. Service aktivieren und starten

sudo systemctl daemon-reload
sudo systemctl enable steuerkram   # automatisch beim Systemstart
sudo systemctl start steuerkram

3. Status prüfen

sudo systemctl status steuerkram
journalctl -u steuerkram -f        # Live-Log inkl. Migrations-Ausgabe

Wichtige Service-Befehle

Befehl Wirkung
sudo systemctl start steuerkram Container starten
sudo systemctl stop steuerkram Container stoppen
sudo systemctl restart steuerkram Neustart (z.B. nach Update)
sudo systemctl status steuerkram Aktueller Status

Backup

bash scripts/backup.sh

Das Skript erstellt ein Dump der Datenbank sowie ein Archiv der Uploads im Verzeichnis backups/.

Update

Seit dem 11.04.2026 bin ich mit meiner Software für mich selber produktiv. Ab diesem Zeitpunkt sollten keine breaking changes mehr vorkommen.

Datenbankmigrationen werden automatisch beim nächsten Container-Start eingespielt – kein manueller Eingriff nötig. Das Script scripts/migrate.php prüft beim Start, welche Migrations-Dateien noch nicht angewendet wurden, und führt sie der Reihe nach aus.

Vollständige Update-Anleitung

Die folgenden Schritte sichern einen vollständigen und sicheren Update-Ablauf. Alle Befehle im Steuerkram-Verzeichnis ausführen.

Schritt 1 – Datenbank sichern

Vor jedem Update ein Backup erstellen:

bash scripts/backup.sh

Das Backup landet in backups/. Alternativ manuell:

docker compose exec db mariadb-dump -u steuerkram -psteuerkram steuerkram \
  > ~/steuerkram_backup_$(date +%Y%m%d_%H%M).sql

Schritt 2 – Aktuellen Code holen

git pull

Prüfen, ob neue Migrations-Dateien enthalten sind:

git log --oneline -5

Schritt 3 – Container neu bauen und starten

docker compose up -d --build

Dieser Befehl baut das PHP-Image neu (falls sich Dockerfile oder composer.json geändert haben) und startet alle Container. Der Web-Container führt beim Start automatisch scripts/migrate.php aus.

Schritt 4 – Migrationen prüfen

docker compose logs web | grep migrate

Erwartete Ausgabe bei erfolgreicher Migration:

[migrate] Starte Migrations-Prüfung...
[migrate] Führe aus: NNN_beschreibung.sql
[migrate] N Migration(en) erfolgreich angewendet.

Oder wenn alles bereits aktuell ist:

[migrate] Datenbank ist aktuell – keine Migrationen notwendig.

Falls die Ausgabe einen Fehler enthält, das Backup aus Schritt 1 einspielen:

docker compose exec -T db mariadb -u steuerkram -psteuerkram steuerkram \
  < ~/steuerkram_backup_YYYYMMDD_HHMM.sql

Schritt 5 – Anwendung prüfen

docker compose ps        # alle Container müssen "running" sein
docker compose logs web  # keine PHP-Fehler oder Exceptions

Anschließend im Browser unter http://localhost:8080 (oder dem konfigurierten Port) einloggen und stichprobenartig Belege und Buchungen prüfen.


Dokumentation

Dokument Inhalt
Installation Docker-Setup, Systemd-Service, Port, Upload-Limit
Konfiguration Firmendaten, Nummernkreise, KI-Beleganalyse, Nextcloud-Import
Funktionen Alle Features im Detail
Anlagevermögen Anlagenspiegel, Buchungsworkflow, Nummernkreis
Update & Backup Update-Anleitung, Backup, Datenpersistenz
Automatisierung Automatisierungsagent, Ideenagent, Support
Datenbankstruktur Tabellen, Spalten, Fremdschlüssel, GoBD-Mechanismen
Berechnungslogik UStVA-Kennzahlen und EÜR-Zuordnungsregeln
Kontenrahmen Vollständige SKR03-Kontenliste

GoBD-Hinweise

  • Gebuchte Sätze können nicht geändert oder gelöscht werden (MariaDB BEFORE UPDATE/DELETE Trigger).
  • Korrekturen erfolgen ausschließlich über Stornobuchungen.
  • Jeder hochgeladene Beleg erhält einen SHA-256 Hash zur Integritätsprüfung.