No description
Find a file
2026-08-11 06:24:47 +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
data Fix #150: Logo-Upload repariert, Nutzdaten nach data/ getrennt, Backups vollständig 2026-07-31 16:22:09 +02:00
docs Fix #158: Kontengruppierung, Kontrastfarbe und Helper-Boilerplate in View gebündelt 2026-08-11 06:24:47 +02:00
migrations Fix #147: Benutzerverwaltung nur noch für Admins zugänglich 2026-08-09 20:21:04 +02:00
php Fix #142: Produktions-Härtung der PHP-Fehlerausgabe 2026-07-27 12:17:49 +02:00
public Fix #157: belege/detail.php in Teil-Views und externe JS-Dateien aufgeteilt 2026-08-11 06:03:55 +02:00
scripts Fix #147: Benutzerverwaltung nur noch für Admins zugänglich 2026-08-09 20:21:04 +02:00
src Fix #158: Kontengruppierung, Kontrastfarbe und Helper-Boilerplate in View gebündelt 2026-08-11 06:24:47 +02:00
tests Fix #158: Kontengruppierung, Kontrastfarbe und Helper-Boilerplate in View gebündelt 2026-08-11 06:24:47 +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 Fix #121: Session-Cookie mit HttpOnly, SameSite und Secure gehärtet 2026-07-10 14:43:30 +02:00
.gitignore Fix #150: Logo-Upload repariert, Nutzdaten nach data/ getrennt, Backups vollständig 2026-07-31 16:22:09 +02:00
activate.sh added systemd service 2026-03-25 13:31:34 +01:00
Changes.md Fix #158: Kontengruppierung, Kontrastfarbe und Helper-Boilerplate in View gebündelt 2026-08-11 06:24:47 +02:00
CLAUDE.md Fix #170: Tests laufen als www-data und räumen angelegte Dateien selbst auf 2026-08-02 16:12:47 +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 Fix #150: Logo-Upload repariert, Nutzdaten nach data/ getrennt, Backups vollständig 2026-07-31 16:22:09 +02:00
docker-entrypoint.sh Fix #belege-umzug: Übernahme aus uploads/ führt Verzeichnisse zusammen statt sie zu verschieben 2026-08-01 15:15:41 +02:00
Dockerfile Fix #150: Logo-Upload repariert, Nutzdaten nach data/ getrennt, Backups vollständig 2026-07-31 16:22:09 +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 Fix #170: Tests laufen als www-data und räumen angelegte Dateien selbst auf 2026-08-02 16:12:47 +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

Alle persistenten Nutzdaten liegen gebündelt unter ./data/ – getrennt nach Art, damit erkennbar bleibt, was wo liegt (Details: data/README.md):

Pfad Inhalt
./data/mariadb/ MariaDB-Datenbankdateien
./data/belege/ Hochgeladene Belege
./data/logo/ Firmenlogo

Diese Pfade liegen außerhalb des Containers und bleiben bei docker compose down erhalten. data/belege und data/logo liegen bewusst außerhalb des Web-Roots und werden nur über die Anwendung ausgeliefert (/belege/{id}/file, /settings/logo/file). ./data/ ist per .gitignore vom Repo ausgenommen und wird von git clean nicht angefasst.

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
E2E-Tests Browser-Tests mit Playwright über den e2e-runner

Tests

docker compose exec -u www-data web php tests/run.php   # PHP-Suite (Models, Services, Berechnungen)
tests/e2e/run.sh                                       # Browser-Tests (Routing, Views, Formular-JS)

Die PHP-Suite läuft ohne weitere Voraussetzungen. Das -u www-data gehört dazu: sonst laufen die Tests als root und hinterlassen in data/ Dateien, die Apache/PHP später nicht mehr beschreiben kann. Die E2E-Tests brauchen Docker, das e2e-runner-Projekt und einen Testnutzer (docker compose exec web php scripts/e2e-user.php); fehlt etwas davon, werden sie mit einer Warnung übersprungen. Details in tests/e2e/README.md.


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.