German trade management platform built with SvelteKit, Hono, and Bun. Designed for electricians, plumbers, HVAC technicians, and other German craftsmen (Handwerker).
| Layer | Technology |
|---|---|
| Runtime | Bun |
| Frontend | SvelteKit + TailwindCSS |
| Backend API | Hono (REST, OpenAPI) |
| Database | PostgreSQL 18 (Drizzle ORM) |
| Cache/Queue | Redis (BullMQ) |
| Monorepo | Turborepo + Bun workspaces |
Tribe implements 6 critical German trade and accounting standards as first-class features:
Generates EN 16931-compliant CII XML invoices embedded in PDF/A-3 documents. Supports the Factur-X EN 16931 profile (formerly "Comfort").
- XML Generation: Cross-Industry Invoice (CII) format per UN/CEFACT D16B
- PDF/A-3 Embedding: XML attached as
factur-x.xmlwithAFRelationship.Alternativeand full XMP metadata including Factur-X extension schema - Profile:
urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:en16931 - Spec: ZUGFeRD 2.3 (FeRD) | Factur-X 1.0 (FNFE)
Exports invoice data as DATEV EXTF CSV files for direct import into DATEV accounting software used by German tax advisors (Steuerberater).
- Format: EXTF v700, semicolon-separated, Windows-1252 encoding
- Fields: Booking amount, account numbers, tax keys, cost centers, dates
- Spec: DATEV Schnittstellen-Entwicklungsleitfaden
Parses DATANORM v4 and v5 files from German wholesalers (Grosshaendler) to import article catalogs into inventory.
- Versions: DATANORM 4.0 (fixed-width) and 5.0 (semicolon-delimited)
- Encoding: CP850 (v4) and CP1252 (v5) auto-detection
- Record Types: V (articles/prices), A (long text), B (alternative articles)
- Spec: DATANORM e.V.
Implements the OCI 5.0 punchout protocol for connecting to supplier web shops. Users browse a supplier's catalog, select items, and the cart is transferred back to Tribe as a purchase order.
- Session Management: Redis-backed with atomic single-use tokens
- Flow: HOOK_URL redirect -> supplier catalog -> POST back with NEW_ITEM[] fields
- Spec: SAP OCI 5.0 Documentation
Import and export of construction bills of quantities (Leistungsverzeichnisse) in GAEB DA XML (3.2/3.3) and the legacy GAEB 90 fixed-width format.
- DA XML: Full hierarchical LV structure with lots, groups, and items
- GAEB 90: Legacy 80-column fixed-width format, auto-detected on import
- Spec: GAEB e.V. | GAEB DA XML Schema
Imports EPLAN parts lists (BOM format) and parts databases into inventory. Supports both semicolon and tab delimiters with automatic encoding detection.
- BOM Format: Columns for quantity, article number, designation, manufacturer, order number
- Parts DB Format: Extended fields including supplier, pricing, weight, mounting type
- Encoding: UTF-8 / Latin-1 / CP1252 auto-detection
- Spec: EPLAN Data Portal
The ZUGFeRD implementation was validated externally using the ecosio Document Validator, a free online tool that checks XML invoices against official European and national e-invoicing standards.
ecosio Peppol & e-Invoice Validator
- URL: https://ecosio.com/en/peppol-e-invoice-xml-document-validator/
- Free to use, no registration required
- Supports: ZUGFeRD, Factur-X, XRechnung, Peppol BIS 3.0, EN 16931
A sample invoice was generated with the following data:
| Field | Value |
|---|---|
| Invoice Number | RE-2025-001 |
| Issue Date | 2025-01-15 |
| Due Date | 2025-02-14 |
| Seller | Meister Elektrik GmbH, Berliner Str. 42, 10115 Berlin, DE |
| Seller VAT ID | DE123456789 |
| Buyer | Bauhaus Handwerk AG, Muenchner Allee 7, 80331 Muenchen, DE |
| Buyer VAT ID | DE987654321 |
| Currency | EUR |
Line Items:
| Pos | Description | Qty | Unit | Unit Price | Total |
|---|---|---|---|---|---|
| 1 | NYM-J 3x1.5 Installationskabel | 100 | MTR | 1.25 | 125.00 |
| 2 | Leitungsschutzschalter B16A | 5 | C62 | 12.50 | 62.50 |
| 3 | Abzweigdose AP 100x100mm | 10 | C62 | 13.10 | 131.00 |
| Amount | |
|---|---|
| Net Total | 318.50 EUR |
| VAT (19%) | 60.52 EUR |
| Gross Total | 379.02 EUR |
| Check | Result |
|---|---|
| XML Syntax | VALID (0 errors) |
| XSD Schema | VALID (0 errors) |
| Schematron (Business Rules) | VALID (0 warnings) |
| Overall | FULLY VALID |
The generated CII XML passes all EN 16931 validation checks with zero errors and zero warnings.
| Check | Result |
|---|---|
| XML Syntax | VALID (0 errors) |
| XSD Schema | VALID (0 errors) |
| Schematron (Profile Rules) | 1 codelist note |
| Overall | XSD VALID |
The single schematron note relates to the profile identifier codelist version. The profile ID urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:en16931 is the correct value per the Factur-X 1.0 specification. Older codelist definitions may expect urn:cen.eu:en16931:2017 without the #compliant suffix, but the full identifier is the standard-conformant value for the EN 16931 profile.
During validation, 3 element ordering issues were identified and fixed:
- TradeParty structure:
PostalTradeAddressmust precedeSpecifiedTaxRegistrationin the CII schema - Address fields:
PostcodeCodemust precedeLineOneinPostalTradeAddress(schema order: PostcodeCode -> LineOne -> CityName -> CountryID) - Profile identifier: Changed to
urn:factur-x.eu:1p0:en16931(the EN 16931 profile name in Factur-X, distinct from the older "Comfort" label)
To validate a ZUGFeRD/Factur-X XML file:
- Go to https://ecosio.com/en/peppol-e-invoice-xml-document-validator/
- Upload your CII XML file
- Select rule-set "EN 16931 CII 1.3.15" for general EN 16931 validation
- Optionally select "Factur-X 1.0.8 (EN 16931)" for Factur-X profile-specific validation
- Click "Validate" and review the results
Other validation tools:
- KOSIT Validator (German government): https://github.com/itplr-kosit/validator — local Java-based validation, used as Docker sidecar in this project
- FeRD ZUGFeRD Community: https://www.ferd-net.de/ — official ZUGFeRD resources and test files
- Mustang Project: https://www.mustangproject.org/ — Open-source Java library with validation capabilities
All integration tests cover XML/CSV generation, parsing, encoding, and round-trip consistency.
# Run all integration tests (from project root)
bun test --filter "apps/api"
# Run from the API directory
cd apps/api && bun test
# Run tests for a specific standard
bun test --filter zugferd
bun test --filter datev
bun test --filter datanorm
bun test --filter oci
bun test --filter gaeb
bun test --filter eplanTest coverage (41 tests, 97 assertions):
| Standard | Tests | Assertions |
|---|---|---|
| ZUGFeRD | 6 | 18 |
| DATEV | 7 | 16 |
| DATANORM | 7 | 17 |
| OCI | 7 | 14 |
| GAEB | 8 | 18 |
| EPLAN | 6 | 14 |
# Install dependencies
bun install
# Start infrastructure (PostgreSQL, Redis, Mailpit)
podman compose -f docker/compose.yml up -d
# Run database migrations
cd packages/db && DATABASE_URL="postgresql://app:app@localhost:5432/app" bun x drizzle-kit migrate
# Start all apps (API + Web)
bun run dev| Service | URL |
|---|---|
| Web (SvelteKit) | http://localhost:5173 |
| API (Hono) | http://localhost:3001 |
| Mailpit UI | http://localhost:8025 |
| PostgreSQL | localhost:5432 |
| Redis | localhost:6379 |
Copy .env.example to .env and fill in values. See .env.example for all required variables.
tribe/
├── apps/
│ ├── api/ # Hono REST API
│ │ ├── src/
│ │ │ ├── routes/ # HTTP route handlers
│ │ │ ├── services/ # Business logic + standard implementations
│ │ │ ├── middleware/ # Auth, validation, logging
│ │ │ └── lib/ # Shared utilities
│ │ └── package.json
│ └── web/ # SvelteKit frontend
│ ├── src/
│ │ ├── routes/ # Pages + layouts
│ │ └── lib/ # Components, utils, stores
│ └── package.json
├── packages/
│ ├── db/ # Drizzle ORM schema + migrations
│ └── shared/ # Shared types, validators, utilities
├── docker/
│ └── compose.yml # PostgreSQL, Redis, Mailpit, Validator
└── turbo.json # Turborepo pipeline config
Private - All rights reserved.