Gewinnermittlung nach §4 Abs. 3 EStG für Einzelunternehmen und Freiberufler. Node/Fastify mit SQLite im Backend, React/Vite im Frontend; die Anwendung läuft lokal ohne Cloud-Anbindung. Fachlicher Kern ist eine Zeitachse der Besteuerungsform: das umsatzsteuerliche Regime wird je Buchung aus dem Leistungsdatum aufgelöst, statt aus einer globalen Ja/Nein-Flagge. Dadurch ist auch ein unterjähriger Wechsel von der Kleinunternehmerregelung zur Regelbesteuerung abbildbar, wie ihn §19 Abs. 1 Satz 3 UStG seit 2025 beim Überschreiten der 100.000-EUR-Grenze vorsieht. Enthalten: - Buchungserfassung nach dem Zu-/Abflussprinzip mit Storno statt Löschung - Anlagevermögen mit AfA (linear, GWG, Sammelposten); die Aktivierung entscheidet das Konto, die Methode der Betrag - Anlage EÜR, BWA im Aufbau der Form 01, Umsatzsteuer-Voranmeldung - ELSTER-Anbindung über ERiC mit validierendem Simulationsmodus - DATEV-Buchungsstapel (EXTF 700) und GoBD-Datenträgerüberlassung (Z3) - Kontenrahmen SKR03 und SKR04, je Mandant beim Anlegen wählbar - Mandantenfähigkeit mit einer SQLite-Datei je Mandant; Testmandanten sind von der Übermittlung ans Finanzamt ausgeschlossen Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
278 lines
12 KiB
Markdown
278 lines
12 KiB
Markdown
# open-eur-webapp
|
||
|
||
Einnahmen-Überschuss-Rechnung nach §4 Abs. 3 EStG für Einzelunternehmen und
|
||
Freiberufler – mit Kleinunternehmerregelung, Umsatzsteuer-Voranmeldung,
|
||
BWA, ELSTER-Anbindung und DATEV-/GoBD-Export.
|
||
|
||
Die Anwendung läuft lokal: ein Node-Prozess, eine SQLite-Datei, keine
|
||
Cloud-Anbindung.
|
||
|
||
```bash
|
||
npm install
|
||
npm run seed # Beispieldaten mit Regimewechsel 2025 -> 2026
|
||
npm run dev # Backend (3311) + Frontend (5173) im Entwicklungsmodus
|
||
```
|
||
|
||
Für den Dauerbetrieb:
|
||
|
||
```bash
|
||
npm run build
|
||
npm start # liefert API und Oberfläche auf http://127.0.0.1:3311
|
||
```
|
||
|
||
`npm test` prüft die Steuerlogik (Regimewechsel, EÜR, UStVA, AfA,
|
||
Steuernummernumsetzung).
|
||
|
||
`npm run seed` bricht ab, wenn bereits Buchungen vorhanden sind – sonst würden
|
||
die Beispieldaten ein zweites Mal eingespielt und alle Auswertungen verdoppeln.
|
||
`npm run seed -- reset` setzt die Bewegungsdaten zurück und legt sie neu an;
|
||
dabei gehen auch selbst erfasste Buchungen verloren.
|
||
|
||
## Mandanten
|
||
|
||
Jeder Mandant hat **eine eigene SQLite-Datei** unter `data/mandanten/`. Das ist
|
||
Absicht: bei einer gemeinsamen Datenbank mit `mandant_id`-Spalte genügt ein
|
||
einziges vergessenes `WHERE`, damit Testbuchungen in der echten EÜR oder in
|
||
einer ELSTER-Übermittlung auftauchen. Getrennte Dateien machen das strukturell
|
||
unmöglich.
|
||
|
||
Umgeschaltet wird oben in der Seitenleiste. Die Anwendung lädt dabei neu, damit
|
||
keine Formularstände des vorherigen Mandanten stehen bleiben.
|
||
|
||
**Testmandanten** sind als solche markiert, auf jeder Seite sichtbar
|
||
gekennzeichnet und **können nichts an das Finanzamt übermitteln** – es sei denn,
|
||
`ELSTER_TESTMERKER` ist gesetzt, dann sind Probeübermittlungen ohne steuerliche
|
||
Wirkung möglich.
|
||
|
||
```bash
|
||
npm run seed -- --mandant=test # legt einen Testmandanten an und befüllt ihn
|
||
```
|
||
|
||
Technisch hängt der Mandant am Request: Header `X-Mandant`, für Download-Links
|
||
(die keine Header setzen können) alternativ `?mandant=<bezeichner>`. Der Server
|
||
führt den Handler in einem AsyncLocalStorage-Kontext aus, sodass jeder
|
||
Datenbankzugriff automatisch auf der richtigen Datei landet.
|
||
|
||
Beim Entfernen eines Mandanten wird die Datei **nicht gelöscht**, sondern mit
|
||
Zeitstempel beiseitegelegt (`….sqlite.entfernt-<zeit>`).
|
||
|
||
## Kontenrahmen: SKR03 und SKR04
|
||
|
||
Beide stehen zur Wahl – **beim Anlegen eines Mandanten**, danach nicht mehr.
|
||
Kontonummern und Bezeichnungen stammen aus den amtlichen DATEV-Kontenrahmen
|
||
(Stand 2026); die Zuordnung zu EÜR-Posten, BWA-Gruppen und UStVA-Kennzahlen ist
|
||
fachliche Auslegung dieser Anwendung und gehört vor dem ersten Export mit der
|
||
Steuerkanzlei abgestimmt.
|
||
|
||
Der Wechsel ist gesperrt, weil dieselbe Kontonummer in beiden Rahmen etwas
|
||
anderes bedeutet:
|
||
|
||
| Konto | SKR03 | SKR04 |
|
||
|---|---|---|
|
||
| 1800 | Privatentnahmen allgemein | **Bank** |
|
||
| 2100 | Zinsen und ähnliche Aufwendungen | Privatentnahmen allgemein |
|
||
| 4830 | Abschreibungen auf Sachanlagen | Sonstige betriebliche Erträge |
|
||
| 4970 | Nebenkosten des Geldverkehrs | Zinserträge |
|
||
|
||
Aus demselben Grund ist das Standard-Gegenkonto rahmenabhängig (SKR03 `1200`,
|
||
SKR04 `1800`) und das Feld `kontenrahmen` in den Stammdaten schreibgeschützt –
|
||
sonst könnte der DATEV-Export einen Rahmen melden, den die Buchungszeilen nicht
|
||
verwenden.
|
||
|
||
## Anlagevermögen oder Sofortabzug
|
||
|
||
Ob eine Ausgabe abzuschreiben ist, entscheidet das **Konto** (Kontotyp `anlage`),
|
||
nicht der Betrag – eine Werbekampagne für 3.000 € bleibt sofort abziehbar, ein
|
||
Drucker für 900 € nicht. Eine Buchung auf ein Anlagekonto wird deshalb immer
|
||
aktiviert; ein stiller Vollabzug ist nicht möglich.
|
||
|
||
Der Betrag entscheidet erst über die **Methode** (bei Kleinunternehmern zählt der
|
||
Bruttobetrag, weil die Umsatzsteuer dann zu den Anschaffungskosten gehört):
|
||
|
||
| Anschaffungskosten | Behandlung |
|
||
|---|---|
|
||
| ≤ 800 € | GWG, im Anschaffungsjahr voll abgesetzt (§6 Abs. 2 EStG) |
|
||
| ≤ 1.000 € | Sammelposten, über 5 Jahre aufgelöst (§6 Abs. 2a EStG) |
|
||
| > 1.000 € | linear über die Nutzungsdauer (§7 Abs. 1 EStG) – Nutzungsdauer ist Pflichtangabe |
|
||
|
||
Buchungen auf Anlagekonten ohne hinterlegtes Anlagegut (etwa aus einer früheren
|
||
Fassung) werden in der EÜR gesondert als prüfbedürftig ausgewiesen. Die Zahlen
|
||
werden dabei bewusst *nicht* stillschweigend korrigiert.
|
||
|
||
## Konfiguration
|
||
|
||
`.env.beispiel` nach `.env` kopieren und anpassen. Die Datei wird beim Start
|
||
automatisch gelesen; bereits gesetzte Umgebungsvariablen haben Vorrang.
|
||
**Relative Pfade darin beziehen sich immer auf das Projektverzeichnis**, nicht
|
||
auf das Verzeichnis, aus dem der Prozess gestartet wurde – sonst entstünden je
|
||
nach Startort verschiedene Datenbanken.
|
||
|
||
Ohne `.env` läuft alles außer der ELSTER-Übermittlung; diese arbeitet dann im
|
||
Simulationsmodus.
|
||
|
||
## Wenn der Start fehlschlägt
|
||
|
||
**`EMFILE: too many open files, watch ...`** (Linux, betrifft `tsx watch` und
|
||
Vite gleichermaßen)
|
||
|
||
Nicht das Dateideskriptor-Limit, sondern die Zahl der erlaubten
|
||
inotify-*Instanzen* ist erschöpft – typischerweise, weil VS Code und andere
|
||
Werkzeuge sie bereits aufgebraucht haben:
|
||
|
||
```bash
|
||
cat /proc/sys/fs/inotify/max_user_instances # meist 128
|
||
find /proc/*/fd -lname anon_inode:inotify | wc -l # tatsächlich belegt
|
||
```
|
||
|
||
Dauerhafte Abhilfe:
|
||
|
||
```bash
|
||
sudo sysctl -w fs.inotify.max_user_instances=1024
|
||
echo 'fs.inotify.max_user_instances=1024' | sudo tee /etc/sysctl.d/60-inotify.conf
|
||
```
|
||
|
||
Ohne Root-Rechte stattdessen:
|
||
|
||
```bash
|
||
npm run dev:polling # Server ohne Watcher, Vite mit Polling statt inotify
|
||
```
|
||
|
||
Der Server startet dann nicht automatisch neu – nach Änderungen am Backend
|
||
manuell neu starten.
|
||
|
||
---
|
||
|
||
## Der Kern: die Zeitachse der Besteuerungsform
|
||
|
||
Der Wechsel von der Kleinunternehmerregelung zur Regelbesteuerung ist nicht als
|
||
Schalter umgesetzt, sondern als **Zeitachse**:
|
||
|
||
| Gültig ab | Besteuerungsform |
|
||
|---|---|
|
||
| 15.01.2024 | Kleinunternehmer (§19 UStG) |
|
||
| 01.01.2026 | Regelbesteuerung |
|
||
|
||
Jede Buchung wird nach dem Regime behandelt, das **zu ihrem Leistungsdatum**
|
||
galt. Daraus folgt:
|
||
|
||
- Altbuchungen bleiben unverändert, wenn ein Wechsel eingetragen wird.
|
||
- Ein **unterjähriger** Wechsel ist möglich – nötig etwa beim Überschreiten der
|
||
100.000-EUR-Grenze, seit 2025 endet die Kleinunternehmerregelung dann sofort
|
||
mit dem überschreitenden Umsatz (§19 Abs. 1 Satz 3 UStG).
|
||
- Ein Jahr mit Wechsel weist Umsätze davor und danach in der EÜR getrennt aus.
|
||
|
||
Die Umsatzgrenzen werden laufend überwacht (25.000 EUR Vorjahr / 100.000 EUR
|
||
laufendes Jahr ab 2025; 22.000 / 50.000 bis 2024) und melden sich, bevor der
|
||
Wechsel fällig wird.
|
||
|
||
Die Regeln stehen an einer Stelle: [`server/src/domain/regime.ts`](server/src/domain/regime.ts).
|
||
|
||
## Was die Anwendung kann
|
||
|
||
**Erfassung**
|
||
- Buchungen mit Beleg-, Leistungs- und Zahlungsdatum; jedes Datum hat eine
|
||
eigene steuerliche Aufgabe (Regime, Soll-Versteuerung, Zuflussprinzip).
|
||
- Live-Vorschau: das Backend entscheidet über Steuersatz, Behandlung und
|
||
Vorsteuerabzug – nicht das Formular.
|
||
- Reverse Charge (§13b), innergemeinschaftliche Erwerbe und Lieferungen,
|
||
steuerfreie und nicht steuerbare Umsätze.
|
||
- Privatanteile, Bewirtung (70 %), offene Posten.
|
||
- Anlagevermögen mit linearer AfA zeitanteilig, GWG-Sofortabschreibung und
|
||
Sammelposten; Kleinunternehmer schreiben vom Bruttobetrag ab.
|
||
- GoBD: keine Löschung, sondern Storno per Gegenbuchung; Festschreibung;
|
||
Änderungsprotokoll.
|
||
|
||
**Auswertungen**
|
||
- **EÜR** in der Gliederung der Anlage EÜR, mit Anlagenverzeichnis.
|
||
- **UStVA** mit den amtlichen Kennzahlen, Ist- oder Soll-Versteuerung,
|
||
monatlich oder vierteljährlich, mit Aufriss auf die Einzelbuchungen.
|
||
- **BWA** im Aufbau der BWA Form 01: Monat, kumuliert, Vorjahresvergleich,
|
||
Quoten – wahlweise nach Zahlungs- oder Leistungszeitpunkt.
|
||
|
||
**Ausgabe**
|
||
- **ELSTER** über ERiC (siehe unten).
|
||
- **DATEV** Buchungsstapel im EXTF-Format (Version 700, Formatversion 13) plus
|
||
Kontenbeschriftungen – das Paket für die Steuerkanzlei.
|
||
- **GoBD-Datenträgerüberlassung** (GDPdU, Format Z3) mit `index.xml` und CSV –
|
||
das Paket für die Betriebsprüfung.
|
||
- EÜR und BWA zusätzlich als CSV.
|
||
|
||
## ELSTER-Übermittlung
|
||
|
||
**Ohne ERiC ist keine Übermittlung möglich – auch nicht mit einem eigenen
|
||
XML-Versand.** ERiC ist die einzige zugelassene Schnittstelle zur
|
||
Finanzverwaltung. Die Bibliothek ist proprietär, darf nicht weitergegeben
|
||
werden und ist deshalb hier nicht enthalten.
|
||
|
||
So wird sie eingebunden:
|
||
|
||
1. Im [ELSTER-Entwicklerportal](https://www.elster.de/elsterweb/entwickler)
|
||
registrieren und ERiC für die eigene Plattform herunterladen.
|
||
2. `.env.beispiel` nach `.env` kopieren und ausfüllen:
|
||
`ERIC_LIB_PATH`, `ERIC_PLUGIN_PATH`, `ELSTER_ZERTIFIKAT`, `ELSTER_PIN`,
|
||
`ELSTER_HERSTELLER_ID`.
|
||
3. Erste Versuche mit `ELSTER_TESTMERKER=700000004` – solche Übermittlungen
|
||
haben keine steuerliche Wirkung.
|
||
|
||
Ist ERiC nicht eingerichtet, läuft die Anwendung im **Simulationsmodus**: das
|
||
XML wird erzeugt, auf Wohlgeformtheit und Vollständigkeit geprüft und unter
|
||
`data/elster-ausgang/` abgelegt. Es wird nichts gesendet, und die Oberfläche
|
||
sagt das ausdrücklich.
|
||
|
||
Die Übermittlung ist verbindlich und nicht zurückzunehmen. Der Endpunkt
|
||
verlangt deshalb `"bestaetigt": true`, die Oberfläche eine Rückfrage.
|
||
|
||
Die Steuernummer wird automatisch vom Länderformat (`123/456/78901`) in das
|
||
13-stellige Bundesschema umgesetzt, das ELSTER erwartet – für alle 16
|
||
Bundesländer, siehe [`server/src/elster/steuernummer.ts`](server/src/elster/steuernummer.ts).
|
||
|
||
## Was vor dem Produktiveinsatz zu prüfen ist
|
||
|
||
Die Rechenwege sind mit Tests abgesichert, aber einige Angaben ändern sich
|
||
jährlich und müssen gegen die amtlichen Vorgaben abgeglichen werden:
|
||
|
||
- **Zeilennummern der Anlage EÜR** – sie ändern sich fast jedes Jahr. Der
|
||
fachliche Aufbau ist stabil, nur die Nummerierung nicht. Gepflegt werden sie
|
||
in `ZEILEN_NUMMERN` in
|
||
[`server/src/domain/euerZeilen.ts`](server/src/domain/euerZeilen.ts), getrennt
|
||
von der Berechnung. Stand: an der Fassung 2024/2025 orientiert.
|
||
- **ELSTER-Schemaversion** – die Datenart-Version (`UStVA_<Jahr>`) und der
|
||
Aufbau des Nutzdatenblocks müssen zu der Version passen, die im installierten
|
||
ERiC steckt. Der erste Lauf sollte mit gesetztem Testmerker erfolgen.
|
||
- **DATEV-Formatversion** – der Export folgt Version 700 / Formatversion 13.
|
||
Vor der ersten Übergabe eine Probedatei mit der Kanzlei einlesen.
|
||
- **Kontenrahmen** – `server/src/kontenrahmen/skr04.ts` ist ein praxisnaher
|
||
Auszug aus dem SKR04, kein vollständiger Kontenrahmen. Konten lassen sich in
|
||
der Oberfläche ergänzen und umwidmen.
|
||
|
||
Die Anwendung ersetzt keine steuerliche Beratung. Für die Richtigkeit der
|
||
Erklärung bleibt die abgebende Person verantwortlich.
|
||
|
||
## Aufbau
|
||
|
||
```
|
||
server/src/
|
||
db.ts SQLite-Schema, Änderungsprotokoll
|
||
domain/
|
||
regime.ts Zeitachse der Besteuerungsform, USt-Ermittlung, §19-Grenzen
|
||
euer.ts Einnahmen-Überschuss-Rechnung
|
||
euerZeilen.ts Gliederung + Zeilennummern je Veranlagungsjahr
|
||
ustva.ts Voranmeldung, Kennzahlen, Ist/Soll
|
||
bwa.ts BWA Form 01
|
||
afa.ts lineare AfA, GWG, Sammelposten
|
||
geld.ts Cent-Arithmetik, kaufmännische Rundung
|
||
elster/
|
||
steuernummer.ts Länderformat -> Bundesschema (alle 16 Länder)
|
||
ustvaXml.ts ELSTER-Datenteil für die UStVA
|
||
eric.ts ERiC-Anbindung über koffi + Simulationsmodus
|
||
export/
|
||
datev.ts EXTF-Buchungsstapel und Kontenbeschriftungen
|
||
gdpdu.ts GoBD-Datenträgerüberlassung
|
||
zip.ts minimaler ZIP-Writer
|
||
routes/ HTTP-Schnittstelle
|
||
web/src/ Oberfläche (React, Vite)
|
||
```
|
||
|
||
Alle Beträge werden als ganzzahlige Cent geführt, Steuersätze als Basispunkte
|
||
(1900 = 19 %). Damit gibt es keine Fließkommafehler in der Steuerberechnung.
|