Node.js/Express + SQLite + Vanilla JS app for managing employee commissions on telecom activations (Telekom, Vodafone, O2, 1&1). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
9.6 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
This is a Provisions-Tracker (Commission Tracker) application for managing employee commissions on telecommunications activations ("Schaltungen"). Built as a Node.js/Express backend with SQLite database and vanilla JavaScript frontend.
Purpose: Track commissions for telecom providers (Telekom, Vodafone, O2, 1&1), including tariffs, customer data, documents, and complex commission calculations.
Development Commands
Running the Application
# Production mode
npm start
# Development mode with auto-restart
npm run dev
# Install dependencies
npm install
The application runs on http://localhost:3000 by default (configurable via PORT environment variable).
Database
- SQLite database file:
provision.db(auto-created on first run) - Database initialization happens automatically via
initDatabase()in database.js - Backup file exists:
provision.db.backup - No migrations system - uses
CREATE TABLE IF NOT EXISTSandALTER TABLEwith error handling
Architecture Overview
Three-Tier Structure
Backend (server.js - ~1987 lines)
- Express.js REST API with ~40+ endpoints
- Handles business logic, commission calculations, and database operations
- File upload handling via Multer (10MB limit)
- CORS enabled for development
Database (database.js - 288 lines)
- SQLite with 12+ tables
- Key tables:
anbieter(providers),tarife(tariffs),schaltungen(connections/commissions),dokumente(documents) - Complex commission system with multiple rule types (fixed/percentage)
- Includes soft-delete tracking (
geloeschte_schaltungen)
Frontend (public/)
- Single-page app: index.html, script.js (~4000+ lines)
- Tab-based navigation (Erfassung, Übersicht, Provisionen, Admin, Gelöschte)
- Preloading strategy for fast tab switching
- Drag-and-drop file uploads
Key Database Tables and Relationships
anbieter (providers)
├─→ tarife (tariffs) - provision_euro, mitarbeiter_provision
│ ├─→ provisionsregeln (tariff-specific commission rules)
│ └─→ tarifoptionen_tarife (M2M link to options)
├─→ anbieter_provisionsregeln (global provider commission rules)
└─→ mitarbeiter_prozentsaetze (employee percentage rates per provider)
schaltungen (main commissions table)
├─→ anbieter_id, tarif_id (foreign keys)
├─→ dokumente (uploaded documents)
├─→ schaltungen_tarifoptionen (M2M selected tariff options)
└─→ hardware_ek, kundenverkaufspreis_netto (hardware pricing)
tarifoptionen_new (tariff options - new structure)
└─→ tarifoptionen_tarife (M2M relationship to tarifs)
tarifoptionen (old structure - kept for migration compatibility)
Commission Calculation System
The app supports multiple commission calculation methods with complex fallback logic:
-
Tariff-specific rules (
provisionsregelntable)- Fixed amount or percentage
- Employee commission (verkaeufer_provision)
-
Global provider rules (
anbieter_provisionsregelntable)- Applied when no tariff-specific rule exists
-
Direct tariff amounts (fallback)
tarife.provision_euro- company commissiontarife.mitarbeiter_provision- employee commission
-
Tariff options (
tarifoptionen)- Additional commission adjustments per activation
- Can be positive or negative (e.g., rebates)
- Many-to-many relationship (options can apply to multiple tariffs)
API endpoint: GET /api/schaltungen/:id/provision - calculates total commission for a specific activation.
Migration Notes
The system includes an in-place migration from old tarifoptionen structure (one-to-many with tarifs) to new structure (many-to-many via tarifoptionen_new and tarifoptionen_tarife). Migration runs automatically on startup via migrateToNewTarifoptionen() in database.js:228-266.
API Endpoint Categories
Anbieter (Providers)
GET /api/anbieter- List all providersPOST /api/anbieter- Add providerDELETE /api/anbieter/:id- Delete provider (with dependency checks)GET /api/anbieter/:id/provisionsregeln- Get global commission rulesPOST /api/anbieter-provisionsregeln- Add global rulePUT /api/anbieter-provisionsregeln/:id- Update global rule
Tarife (Tariffs)
GET /api/tarife- List all tariffsGET /api/tarife/:anbieter_id- List tariffs for providerGET /api/tarif/:id- Get single tariffPOST /api/tarife- Add tariffPUT /api/tarife/:id- Update tariffDELETE /api/tarife/:id- Delete tariff (with dependency checks)GET /api/tarife/:id/provisionsregeln- Get tariff commission rulesPOST /api/provisionsregeln- Add tariff rulePUT /api/provisionsregeln/:id- Update tariff rulePUT /api/tarife/:id/mitarbeiter-provision- Update employee commission
Schaltungen (Commissions/Activations)
GET /api/schaltungen- List all activationsPOST /api/schaltungen- Create activationPUT /api/schaltungen/:id- Update activationDELETE /api/schaltungen/:id- Delete activation (soft delete with reason tracking)GET /api/schaltungen/:id/provision- Calculate commission for activationGET /api/provisionen- Get commission overview/reportGET /api/geloeschte-schaltungen- List deleted activations
Dokumente (Documents)
POST /api/schaltungen/:id/dokumente- Upload document (multipart/form-data)GET /api/schaltungen/:id/dokumente- List documents for activationGET /api/dokumente/:id/download- Download documentDELETE /api/dokumente/:id- Delete document (removes file from disk)
Tarifoptionen (Tariff Options)
GET /api/tarifoptionen- List all options (old structure)GET /api/tarifoptionen/multi- List all options (new structure)POST /api/tarifoptionen/multi- Add option (new structure)PUT /api/tarifoptionen/multi/:id- Update option (new structure)DELETE /api/tarifoptionen/multi/:id- Delete option (new structure)GET /api/schaltungen/:id/tarifoptionen- Get options for activationPOST /api/schaltungen/:id/tarifoptionen- Link option to activationDELETE /api/schaltungen/:schaltung_id/tarifoptionen/:tarifoption_id- Unlink option
Mitarbeiter (Employee Settings)
GET /api/anbieter/:id/mitarbeiter-prozentsaetze- Get employee percentages for providerPOST /api/mitarbeiter-prozentsaetze- Add percentage rateDELETE /api/mitarbeiter-prozentsaetze/:id- Delete percentage rate
Important Implementation Details
File Uploads
- Storage:
uploads/directory (created automatically) - Naming:
{timestamp}-{random}.{extension} - Limit: 10MB per file
- Supported types: PDF, JPG, JPEG, PNG, DOC, DOCX (enforced client-side)
- Files are physically deleted when document is removed
Frontend State Management
- Preloading: App preloads all tab data in background after 1 second delay for faster navigation
- Tab switching: Uses cached data when available (
showTab()checks if data exists) - Global variables:
currentSchaltungId,uploadedFiles - Message system: Toast notifications via
showMessage()overlay
Database Connection Pattern
Singleton Pattern - A single persistent database connection is used throughout the application lifecycle:
const db = getDatabase(); // Returns singleton instance
// ... do work ...
// NO db.close() - connection persists
- Connection is opened once on startup and reused
- Foreign keys are enabled after initialization (
PRAGMA foreign_keys = ON) - Busy timeout set to 3000ms for concurrent access handling
- Graceful shutdown closes connection on SIGINT/SIGTERM
Delete Operations
- Soft delete: Schaltungen are moved to
geloeschte_schaltungentable with reason and timestamp - CASCADE delete: Deleting a Schaltung automatically removes:
- Associated documents from database (via
ON DELETE CASCADE) - Document files from filesystem (handled in endpoint)
- Linked tarifoptionen (via
ON DELETE CASCADE)
- Associated documents from database (via
- Hard delete: Individual documents physically removed from filesystem when deleted
- Dependency checks: Providers and Tariffs check for usage before deletion
Language
- UI/Database: German (Anbieter, Tarife, Schaltungen, etc.)
- Code: Mixed German/English
- Comments: Mostly English in code, German in UI strings
Testing Data
Default data seeded on first run:
- Providers: Telekom, Vodafone, O2, 1&1
- Tariffs: 10 example tariffs with commission amounts
- Employee percentages: 8-10% per provider
- Tariff options: 5 example options including rebates
- Global rules: Example O2 (fixed 20€) and 1&1 (12% percentage) rules
Common Development Patterns
Adding a New API Endpoint
- Add route in server.js following existing patterns
- Use
getDatabase()to open connection - Always call
db.close()in callbacks - Return JSON with proper error handling
- Update frontend in script.js with corresponding API call
Adding a Database Table
- Add
CREATE TABLE IF NOT EXISTSin database.jsinitDatabase() - Add within
db.serialize()block - Consider foreign key constraints
- Add seed data with
INSERT OR IGNOREif needed
Modifying Commission Logic
- Main calculation logic is in
GET /api/schaltungen/:id/provision - Fallback order: provisionsregeln → anbieter_provisionsregeln → direct tariff amounts
- Always recalculate when tariff/provider/options change
- Employee commission calculated separately from company commission