Skip to content

IT Entwicklung

IT-Master Heizmann edited this page Sep 18, 2026 · 2 revisions

Entwicklung

Caution

Diese Seite richtet sich ausschliesslich an Informatikerinnen und Informatiker. Nicht für Laien geeignet: Sie beschreibt Quellcode, Build und Tests. Ein selbst gebautes Paket ersetzt keine geprüfte Version des Herstellers. Ohne Fachkenntnisse bitte Installation Schritt für Schritt verwenden.

Für wen ist diese Seite? Für Entwicklerinnen und Entwickler, die am Quellcode von SmallTime 2027 arbeiten, Tests ausführen oder ein Betriebspaket bauen.

Inhalt

  1. Voraussetzungen
  2. Repository-Aufbau
  3. Backend
  4. Frontend
  5. Scripts
  6. Entwicklung starten
  7. Tests
  8. Release-Paket bauen
  9. Versionsnummer
  10. Konventionen

Voraussetzungen

  • Node.js 26.9.0 (.nvmrc und .node-version im Repository-Stamm), engines: >=26.9.0 <27; npm 11.19.1 (packageManager).
  • Getrennte Pakete backend/ und frontend/ mit je eigener package-lock.json; kein Workspace im Stamm.
  • VS Code: .vscode/settings.json konfiguriert die Erweiterung «Node.js Test Runner» für backend/ (Loader backend/node_modules/tsx/dist/loader.mjs); Vitest findet frontend/vite.config.ts selbst.

Repository-Aufbau

SmallTime_2027.01/
├── backend/
│   ├── src/
│   │   ├── index.ts              Einstieg (dotenv, createServer, start)
│   │   ├── server.ts             Express-App, Middleware, Routen, Auslieferung des Frontends
│   │   ├── migrate.ts            Migrationen separat
│   │   ├── cli/convert.ts        Konverter SmallTime PHP (npm run convert)
│   │   ├── lib/                  config, auth/JWT, csrf, cookies, security, network, rate-limit, logger, live-updates …
│   │   ├── middleware/           common (Helmet, CORS, Rate-Limit, Filter), csrf, auth, error-handler
│   │   ├── models/               Sequelize-Modelle, store.ts, migrations/
│   │   ├── modules/<feature>/    fachliche Module
│   │   └── types/
│   ├── tests/                    node:test (*.test.ts), helpers/http-harness.ts, postman/
│   ├── scripts/build.mjs         esbuild
│   ├── config/                   backend.json, security.json
│   ├── docs/migrate.md           Anleitung Migrationen/neue Tabellen
│   ├── Dockerfile, docker-entrypoint.sh
│   └── .env.example
├── frontend/
│   ├── src/
│   │   ├── main.tsx, App.tsx     Einstieg, Routing
│   │   ├── pages/                Admin, Home, Login, Time, Terminal, Security, …
│   │   ├── components/           gemeinsame Komponenten (Layout, LicenseBanner, PasswordChangeGate, …)
│   │   ├── api/                  auth-context, auth-api-client, use-api (useApi, useLoad), live-updates
│   │   ├── i18n/locales/{de,en,fr,it}/*.json
│   │   ├── lib/, models/, styles/, test/
│   ├── config/frontend.json
│   ├── vite.config.ts
│   ├── Dockerfile, nginx.conf
├── scripts/package-dist.mjs      Betriebspaket zusammenstellen
├── scripts/sync-release.mjs      dist/ in den Git-Ordner release/ spiegeln
├── scripts/third-party-licenses.mjs  THIRD-PARTY-LICENSES.md erzeugen
├── scripts/dist-files/           LICENSE und README.md für das Paket
├── dev.cmd, prod.cmd, release.cmd
├── _Doku - 2027/                 Fachkonzept (Datenmodell, Berechnungslogik, Konvertierung, Sicherheit, API)
└── convert/                      Quelldaten SmallTime PHP (nicht in Git)

Backend

Module (src/modules/<feature>/): auth, catalog, closings, content, documents, employees, files, groups, legacyConversion, license, notes, presence, reports, security, settings, setup, shared, system, terminals, timeEngine, timesheet.

Aufbau pro Modul:

Datei Inhalt
<feature>.routes.ts Express-Router, Middleware (requireAuth, requireRole), Registrierung in server.ts
<feature>.service.ts Geschäftslogik, SQL
<feature>.schemas.ts zod-Schemas (.strict()) für Eingaben
<feature>.controller.ts optional
  • timeEngine ist rein: keine Datenbank, kein HTTP, keine Uhr. Eingaben rein, Ergebnis raus (Paarung Kommen/Gehen, Monats- und Saldoberechnung, Feiertage, Regeln). Dadurch direkt testbar.
  • shared/: Datenbank-Helfer (Database), Datumsfunktionen (Temporal), Einstellungen, Audit, Berechtigungen.
  • Persistenz: Sequelize mit SQLite; Schemaänderungen nur über neue Migrationen in src/models/migrations/ (bestehende nie ändern), siehe backend/docs/migrate.md.
  • Fehler: HttpError mit Codes aus lib/message-codes.ts (Sxxxx/Exxxx), zentraler error-handler.
  • Build: scripts/build.mjs bündelt src/index.ts → dist/server.js und src/migrate.ts → dist/migrate.js (ESM, platform: node, target: node26, packages: external, Source-Maps, minifiziert; --dev ohne Minify) und bettet __APP_VERSION__ ein.

Frontend

  • React 19, React Router 7, MUI 9 (inkl. X Data Grid), i18next (de, en, fr, it), TipTap, Mermaid.
  • src/pages/…: Seiten; src/components/…: wiederverwendbare Komponenten.
  • src/api/use-api.ts:
    • useApi() – HTTP-Client mit Cookie-Session und CSRF-Header.
    • useLoad(loader, key) – lädt Daten für einen Schlüssel. Jede Anfrage erhält ein AbortController-Signal; bei Schlüsselwechsel oder Unmount wird die alte Anfrage abgebrochen und ihr Ergebnis verworfen (keine Race Conditions). Liefert data, error, loading, reload() (Promise, löst nach dem Neuladen auf) und setData().
  • src/api/live-updates.ts: WebSocket auf /api/live (gleicher Host), löst reload() betroffener Ansichten aus.
  • /custom.css wird in main.tsx nach den App-Styles eingebunden.
  • Build: tsc -b && vite build → frontend/dist. vite.config.ts liest Ports und Upload-Endungen aus backend/config/backend.json und frontend/config/frontend.json.

Scripts

Backend (backend/package.json):

Script Befehl Zweck
dev tsx watch src/index.ts Entwicklungsserver mit Reload (Port 55000)
build node scripts/build.mjs Produktions-Build nach dist/
build:dev node scripts/build.mjs --dev Build ohne Minify
start node dist/server.js gebautes Backend starten
migrate tsx src/migrate.ts Migrationen (Quellcode)
migrate:prod node dist/migrate.js Migrationen (Build)
convert tsx src/cli/convert.ts Konverter SmallTime PHP, Optionen --dry-run, --replace, --start, --source, …
test tsx --test tests/**/*.test.ts Tests (node:test)
lint / lint:fix eslint src tests --ext .ts Lint
format / format:check Prettier über src, tests, *.json, *.md Formatierung
typecheck tsc -p tsconfig.json --noEmit Typprüfung
audit npm audit --audit-level=high Abhängigkeiten prüfen

Frontend (frontend/package.json):

Script Befehl Zweck
dev vite Dev-Server Port 55001, Proxy /api (inkl. WS) und /custom.css → 55000
build tsc -b && vite build Typprüfung und Build nach dist/
preview vite preview Build lokal ansehen (ohne Backend-Proxy-Garantie)
test vitest run Tests (jsdom)
test:watch / test:coverage vitest watch / vitest run --coverage
lint / lint:fix eslint src --ext .ts,.tsx Lint (inkl. jsx-a11y, react-hooks)
format / format:check Prettier Formatierung
audit npm audit --audit-level=high

Entwicklung starten

Windows: dev.cmd im Repository-Stamm (installiert fehlende node_modules, erzeugt backend/.env aus .env.example, startet beide Server in eigenen Fenstern).

Manuell (alle Plattformen):

cd backend  && npm ci && cp .env.example .env && npm run dev
cd frontend && npm ci && npm run dev

Mit NODE_ENV=development liefert das Backend kein Frontend aus. Datenbank und Uploads liegen in backend/data/ und backend/uploads/, der Importordner in convert/ im Repository-Stamm. Erster Login: admin / admin1234, sofern kein Import lief.


Tests

Backend – Node-Test-Runner (node:test) über tsx:

cd backend
npm test
npx tsx --test tests/time-engine.test.ts      # einzelne Datei
  • Unit-Tests für lib/ und Services (*.lib.test.ts, *.service.test.ts, time-engine.test.ts, legacy-conversion.test.ts, license.test.ts, database-backup.test.ts, …).
  • HTTP-Tests (http-*.test.ts) über tests/helpers/http-harness.ts: startTestServer(security?) startet ein echtes ExpressBackend auf einem freien Port mit eigener temporärer Datenbank (Migrationen, Initial-Admin admin/admin1234), TestClient verwaltet Cookies und CSRF. nodeEnv: 'test', trustProxy: false, hohes API-Limit; Sicherheitsregeln pro Test überschreibbar.
  • Postman-Sammlung: tests/postman/postman-collection.json.

Frontend – Vitest mit jsdom (src/test/setup.ts, Helfer src/test/render.tsx, time-fixtures.ts):

cd frontend
npm test
npm run test:coverage

Vor einem Commit: npm run lint, npm run typecheck (Backend), npm run format:check und npm test in beiden Paketen.


Release-Paket bauen

Windows: prod.cmd im Repository-Stamm. Manuell:

cd frontend && npm ci && npm run build
cd ../backend && npm ci && npm run build
cd .. && SMALLTIME_ORIGIN=https://zeit.example.ch node scripts/package-dist.mjs

scripts/package-dist.mjs:

  1. Prüft, dass frontend/dist und backend/dist existieren und dass dist/ kein Git-Repository ist (sonst Abbruch).
  2. Leert dist/ im Repository-Stamm (nur den Inhalt, damit ein geöffneter Ordner unter Windows nicht stört).
  3. Kopiert backend/dist → dist/dist, frontend/dist → dist/public (jeweils ohne Source-Maps, sie enthielten den vollständigen Quellcode), backend/config → dist/config, backend/package-lock.json.
  4. Passt dist/config/security.json für Hosting ohne Länder-Header an: allowedCountries: [], allowLocalhost: false.
  5. Schreibt dist/package.json (Name smalltime, Version aus backend/package.json, nur dependencies, engines, overrides; Scripts start: node app.cjs, migrate: node dist/migrate.js).
  6. Schreibt dist/app.cjs (CommonJS, lädt ./dist/server.js per import(), für Plesk/Passenger).
  7. Schreibt LICENSE und README.md (aus scripts/dist-files/, Version eingesetzt), THIRD-PARTY-LICENSES.md (alle Laufzeit-Abhängigkeiten von Backend und Frontend mit Lizenztexten), .node-version und eine .gitignore (.env, data/, uploads/, convert/, node_modules/, *.sqlite).
  8. Schreibt dist/.env.example (ohne Secret) und dist/.env mit NODE_ENV=production, FRONTEND_ORIGIN aus SMALLTIME_ORIGIN (sonst Platzhalter https://smalltime.example.ch mit Warnung), neuem zufälligem SESSION_SECRET (48 Byte), SECURE_COOKIE=true, TRUST_PROXY=true, ENABLE_COMPRESSION=true, BCRYPT_COST=12.

Nicht im Paket: node_modules/ (native Module müssen auf dem Zielsystem installiert werden), data/, uploads/, convert/. Auf dem Zielsystem: npm install --omit=dev, npm start.

Warning

  • Jeder Lauf erzeugt ein neues SESSION_SECRET. Die dist/.env beim Verteilen eines Updates nicht mitliefern bzw. nicht überschreiben lassen.
  • Die Liste der Laufzeitabhängigkeiten stammt aus backend/package.json → dependencies. Wird dort eine Abhängigkeit ergänzt, muss das Paket neu gebaut werden (esbuild bündelt Abhängigkeiten nicht).
  • Das Paket liefert eine package-lock.json des Backends mit, die auch Dev-Abhängigkeiten beschreibt. Auf dem Zielsystem deshalb npm install --omit=dev verwenden.

Veröffentlichen auf GitHub (release/)

dist/ ist reine Build-Ausgabe und wird bei jedem Lauf komplett ersetzt – es ist nie selbst ein Git-Repository. Veröffentlicht wird aus dem separaten Ordner release/, einem Klon von github.com/it-m-h/SmallTime-27:

Vor jeder Version: version in backend/package.json erhöhen und die Änderungen in scripts/dist-files/CHANGELOG.md eintragen (neueste Version zuoberst). Das Build-Skript kopiert CHANGELOG.md, LICENSE, README.md und images/ aus scripts/dist-files/ ins Paket.

rem einmalig
git clone https://github.com/it-m-h/SmallTime-27.git release

rem für jede Version: bauen + spiegeln
release.cmd
cd release
git status
git add -A
git commit -m "Version 1.0.0"
git tag v1.0.0
git push --follow-tags

Danach auf GitHub unter Releases → Draft a new release den Tag wählen, als Text den Abschnitt der Version aus CHANGELOG.md einfügen und bei -beta-Versionen Set as a pre-release anhaken.

scripts/sync-release.mjs lässt .git/.github im Release-Ordner unangetastet, löscht dort entfernte Dateien und kopiert nie .env, data/, uploads/, convert/ oder node_modules/. release/ steht in der .gitignore des Quellcode-Repositorys.


Versionsnummer

Die Version wird nur in backend/package.json → version gepflegt (src/lib/app-version.ts):

  • Beim Build bettet esbuild sie als __APP_VERSION__ ein; in der Entwicklung wird package.json im Arbeitsverzeichnis gelesen.
  • package-dist.mjs übernimmt sie in dist/package.json.
  • Anzeige: Administration, unten im Menü (V1.0 für 1.0.0; .0 als Patch wird weggelassen; Vorab-Versionen nach SemVer, z. B. 0.9.5-beta → V0.9.5 Beta), zusammen mit Node-Version und Betriebssystem (GET /api/admin/settings/system).
  • frontend/package.json → version wird nicht angezeigt.

Konventionen

  • Eingaben immer mit zod validieren; Benutzerkontext nur aus der Session (/api/me ohne ID).
  • Neue Tabellen/Spalten ausschliesslich per neuer Migration.
  • Zeitlogik in timeEngine halten und dort testen; Services orchestrieren nur.
  • Texte im Frontend über i18n (alle vier Sprachen pflegen).
  • Personendaten (convert/, Konvertierungsberichte, echte Datenbanken) nie committen.

Weiter mit: Übersicht · Konfiguration · Docker

Clone this wiki locally