EU Regulation (EC) 561/2006 โ Compliance Research โ
Context: The L3 Dispatch Availability Engine implements a simplified 11h daily rest heuristic. This document prepares a proper research and brainstorming run for full 561/2006 compliance in Phase 2. Status: ๐ก RESEARCH NEEDED Date: 2026-04-10
1. Current State (Phase 1) โ
The availability engine checks:
MAX(crew_duty_log.log_time WHERE event_type = 'DRIVING') + 11h < target_startThis covers only the regular daily rest requirement. If a driver drove at midnight and 11 hours have elapsed, they're marked AVAILABLE. This is correct for the simplest case but ignores most of the regulation.
2. Full EU-561/2006 Requirements โ
The regulation defines six interlocking limits. The engine must evaluate all of them together.
2.1 Daily Driving Time โ
- Max 9 hours per day (defined as 24h after end of last daily/weekly rest).
- The driver can extend this to 10 hours up to twice per week.
- "Driving" = any time the vehicle is in motion, including slow traffic.
2.2 Continuous Driving โ
- Max 4 hours 30 minutes of continuous driving.
- Followed by a mandatory 45 minutes break.
- The break can be split: 15 min + 30 min (in that order, not reversed).
2.3 Daily Rest โ
- Regular: 11 consecutive hours within each 24h period.
- Reduced: 9 consecutive hours, the driver may use this up to 3 times per week.
- Split: 3h + 9h = 12h total (in that order). Counts as one regular rest.
- Multi-manning: reduced to 9h if two drivers present.
2.4 Weekly Driving Time โ
- Max 56 hours in any single week.
- Week = Monday 00:00 to Sunday 24:00.
2.5 Fortnightly Driving Time โ
- Max 90 hours in any two consecutive weeks.
2.6 Weekly Rest โ
- Regular: 45 consecutive hours, once per week.
- Reduced: 24 consecutive hours, the driver may take this every other week.
- Compensation: the driver must compensate a reduced weekly rest by an equivalent rest period attached to another rest of โฅ 9h, taken before the end of the third week following.
3. Research Questions โ
The team must answer these before implementation:
3.1 Data Model โ
- [ ] Can the current
crew_duty_logsmodel (singlelog_time+event_type) support all 6 rule evaluations, or do we need a duration-based model (start/end times)? - [ ] How do we model the "week" concept (Mon 00:00 โ Sun 24:00) across time zones? Are tenants always in one TZ?
- [ ] How do we track the "3 reduced rests per week" counter? Stateless (computed from logs) or stateful (a separate counter)?
- [ ] Do we need a separate
rest_periodentity to track split rests (3h + 9h) and weekly rest compensation?
3.2 Cross-Tenant / Freelancer Problem โ
- [ ] EU-561 applies per driver, not per operator. A freelance driver working for multiple tenants has a single legal rest clock. Our multi-tenant model only sees one tenant's
crew_duty_logs. How do we handle this?- Option A: Ignore (accept legal risk, document limitation)
- Option B: Driver self-declaration of external hours (manual input)
- Option C: Industry tachograph data exchange (SmartCard readout via digital tachograph API)
3.3 Tachograph Integration โ
- [ ] Digital tachographs (EU Regulation 165/2014) produce
.dddfiles with all driver activity. Is there a standard API/SDK for parsing these? - [ ] Can we ingest raw tachograph data via the existing telemetry pipeline or do we need a separate ingestion path?
- [ ] Smart tachographs (V2, mandatory since August 2023) support real-time remote download. Is this feasible for Phase 2?
3.4 Enforcement Strategy โ
- [ ] Which checks should be hard blocks (๐ด BLOCKED) vs. warnings (๐ก WARNING)?
- Continuous driving > 4.5h without break โ BLOCKED?
- Weekly driving > 56h โ BLOCKED?
- Missing reduced rest compensation โ WARNING?
- [ ] Should the system enforce compliance proactively (prevent scheduling violations) or reactively (flag violations post-hoc)?
- [ ] What is the legal liability if the system allows a dispatcher to override a 561 warning and a violation occurs?
3.5 UX Design โ
- [ ] How does the dispatch board visualize the remaining daily driving budget (e.g., "4h 23m remaining today")?
- [ ] How do we display the fortnightly rolling window without overwhelming the dispatcher?
- [ ] Do we need a dedicated "Driver Compliance Dashboard" separate from the dispatch board?
4. Penalty Context (DACH) โ
| Violation | Fine (Germany) | Fine (Austria) | Notes |
|---|---|---|---|
| Daily driving exceeded | โฌ60โ500/h | โฌ72โ726/h | Per excess hour |
| Missing break | โฌ250โ500 | โฌ300โ600 | Per missing break |
| Insufficient daily rest | โฌ500โ1,500 | โฌ726โ2,180 | Per violation |
| Insufficient weekly rest | โฌ500โ2,000 | โฌ726โ2,180 | Per violation |
| Weekly driving > 56h | โฌ120โ500 | โฌ218โ1,000 | Per excess hour |
| Fortnightly > 90h | โฌ250โ500 | โฌ218โ1,000 | Per excess hour |
| Employer liability | Up to โฌ15,000 | Up to โฌ5,000 | If systematic |
CAUTION
In Germany, both the driver (ยง 8a FPersV) and the employer (ยง 20 FPersV) are liable. The employer is specifically responsible for ensuring that work schedules make compliance possible. This gives Busflow operators a direct legal interest in automated compliance checks.
5. Next Steps โ
- Deep-dive talk with a DACH bus operator to validate which rules they actually track vs. ignore in practice
- Technical spike on
.dddtachograph file parsing (available libraries:readesm,tacholib, or commercial SDKs) - Data model proposal for duration-based activity logging that supports all 6 rule evaluations โ see ยง6 below for the
DutyActivityextraction design intent - Decision on cross-tenant freelancer handling (3.2)
- L3-level spec for Phase 2 EU-561 compliance module
6. Design Intent: DutyActivity Extraction (Phase 2) โ
Status: ๐ก DESIGN INTENT โ not yet specified, captures architectural direction to prevent Phase 1 decisions from blocking Phase 2. Date: 2026-04-15 Source: Compliance Subdomain Analysis โ original agent artifact, not tracked in
docs/.
6.1 Problem โ
CrewDutyLog is structurally coupled to ServiceLeg โ TourDeparture. EU-561 applies per driver, not per trip type. If a driver performs scheduled bus routes (Linienverkehr), chartering (Anmietverkehr), or external work for another operator, that driving time must count toward the same legal rest clock. The current model has no place to record non-tour driving.
This is the same structural problem as the cross-tenant freelancer issue (ยง3.2) โ whether the blind spot comes from a different tenant or a different business module, the result is identical: incomplete driving-hour visibility.
6.2 Proposed Entity: DutyActivity โ
A business-area-agnostic replacement for CrewDutyLog in the compliance evaluation path.
| Column | Type | Description |
|---|---|---|
id | UUID | PK |
tenant_id | UUID | Soft FK to backoffice.operators |
crew_member_id | UUID | Soft FK to backoffice.crew_members |
activity_type | VARCHAR | DRIVING, REST, WORK, AVAILABILITY, BREAK |
start_time | TIMESTAMPTZ | Activity start โ resolves the duration-based logging gap (ยง3.1) |
end_time | TIMESTAMPTZ | Activity end |
duration_minutes | INT | Computed or explicit duration |
source_type | VARCHAR | TOUR_LEG, LINE_ROUTE, CHARTER, TACHOGRAPH_IMPORT, SELF_DECLARATION |
source_ref_id | UUID | Polymorphic soft FK to the originating record (e.g., service_leg_id, future line_route_id) |
tachograph_data | JSONB | Raw/parsed IoT payload (migrated from CrewDutyLog) |
6.3 ComplianceEvaluator Domain Service โ
Stateless service consuming DutyActivity records, evaluating all 6 EU-561 rules (ยง2), and producing:
ComplianceStatusper driver per day/week (remaining driving budget, rest deficit, violation flags)DutyViolation/DutyBudgetLowdomain events โ Dispatch Board
Lives in Backoffice (aligns with existing boundary: "Operations records, Backoffice evaluates"). May be extracted to a standalone Shared Core if Linienverkehr becomes a first-class module.
6.4 Migration Path โ
| Phase | Model | Scope |
|---|---|---|
| Phase 1 (current) | CrewDutyLog with single log_time | 11h daily rest heuristic only. Sufficient for tour-only operators. |
| Phase 2 transition | DutyActivity entity created. CrewDutyLog emits DutyActivityRecorded events on write. | Backfills DutyActivity from existing logs. CrewDutyLog remains for operational correlation (which leg? which vehicle?). |
| Phase 2 steady state | ComplianceEvaluator reads from DutyActivity only. Other modules (Linienverkehr, chartering, tachograph import) write directly to DutyActivity. | Full 6-rule evaluation. CrewDutyLog becomes an operational detail, not a compliance source. |
6.5 Phase 1 Guard Rails โ
To avoid blocking this extraction, Phase 1 must not:
- Add hard business logic that assumes
service_leg_idis always present on duty records - Build compliance evaluation SQL that joins
crew_duty_logsโservice_legsโtour_departures - Store compliance outcomes (violation flags, budgets) on
CrewDutyLogrows