Pitstop is the garage’s operational brain: it synchronizes planning, creates/updates work orders, and keeps the admin overview and workshop view consistent in near real-time.
Most garages use a planning tool for appointments and a separate admin/workshop system for execution. When jobs change (delay, extra work, parts missing), updates are handled manually, causing schedule drift, wrong customer expectations, and inefficient workshop utilization.
Pitstop solves this by providing a single operational source of truth for work orders and status, and synchronizing planning + workshop execution.
The most important requirements:
- Import appointments from one or more Planning Services.
- Convert appointments into Work Orders (jobs/tasks, estimates, required skills, bay assignment).
- Provide an Admin Overview (today’s workload, lateness, bay utilization, priorities).
- Provide a Workshop View (per bay/technician task list with fast status updates and notes).
- Push status changes back to planning (delays, ready-for-pickup, reschedule proposals).
- Track parts dependency (e.g., “Waiting for Parts”) and use it to block/advance work.
Explicit non-goals:
- Pitstop is not the planning product.
- Pitstop is not inventory management (it references parts status, doesn’t manage stock).
- Pitstop is not billing/accounting (it can export outcomes, doesn’t own invoicing).
Top quality goals (measurable):
| Priority | Quality | Scenario (short) | Acceptance criteria (example) |
|---|---|---|---|
| 1 | Consistency | Admin + Workshop must show the same job state | Status updates visible in all UIs within ≤ 2 seconds |
| 2 | Availability | Workshop continues during flaky internet | Workshop View works in degraded mode; updates sync when online |
| 3 | Modifiability | Add a new planning integration | New integration in ≤ 2 days without changing core domain logic |
| 4 | Auditability | Resolve disputes and analyze throughput | Every change includes who/when/why, immutable history |
| 5 | Usability | Workshop updates must be fast | “Glove-friendly” UX: minimal steps, optimized for speed |
| Stakeholder | Expectations |
|---|---|
| Garage Owner / Manager | Throughput, predictable planning, fewer no-shows, visibility |
| Service Advisor (front desk) | Reliable customer promises, quick rescheduling |
| Workshop Foreman | Clear priorities, balanced bays, fewer interruptions |
| Mechanics | Simple task list, fast updates, less admin burden |
| Customer | Accurate ETA, proactive updates on delays |
| Planning Vendor(s) | Stable API usage, predictable traffic, clean sync semantics |
| IT/Ops | Deployable, monitorable, secure, low maintenance |
Non-negotiables that shape the design space:
| Constraint | Type | Rationale | Impact |
|---|---|---|---|
| Must integrate with Planning Service(s) | Integration | Existing ecosystem reality | API contracts, sync strategy, mapping rules |
| Near real-time UI updates | UX/Operational | Workshop coordination | Push updates (WebSocket) or efficient polling |
| Degraded-mode operation | Operational | Garage networks can be unreliable | Local cache/queue, retry, conflict handling |
| Containerized deployment | Platform | Standard ops model | Registry, base images, runtime policy |
| Automated CI + tests | Process | Fast feedback & reliability | Pipeline ownership + test environments |
| GDPR / minimal personal data | Compliance | Customer data | Data minimization, retention rules, audit controls |
| Deviations recorded as ADRs | Governance | Prevent silent divergence | ADR workflow (see Chapter 9) |
Pitstop sits between:
- Planning (appointments and promises),
- Admin (coordination and customer communication),
- Workshop execution (reality: progress, delays, extra work), and keeps them synchronized.
@startuml
skinparam shadowing false
skinparam componentStyle rectangle
actor "Service Advisor" as Advisor
actor "Workshop Foreman" as Foreman
actor Mechanic
actor Customer
rectangle "Planning Service" as Planning
rectangle Pitstop as "Pitstop" #OrangeRed
rectangle "Admin Overview" as AdminUI
rectangle "Workshop View" as WorkshopUI
rectangle "Notification Service\n(optional)" as Notify
Customer -> Advisor : appointment\nquestions/updates
Advisor --> Planning : create/adjust\nappointment
Planning --> Pitstop : appointments\n(+changes)
Pitstop --> Planning : status updates\n(reschedule proposals)
Advisor --> AdminUI : coordinate\ncommunicate
Foreman --> AdminUI : priorities\nbay allocation
Mechanic --> WorkshopUI : progress\nnotes
AdminUI --> Pitstop : assign/prioritize\nwork orders
WorkshopUI --> Pitstop : status updates\n(findings, parts)
Pitstop --> Notify : send customer\nnotifications
Notify -> Customer : SMS/email
@enduml| Actor/System | Responsibility | Exchanges with Pitstop |
|---|---|---|
| Customer | Brings car, receives updates | ETA updates (via advisor/portal) |
| Service Advisor | Manages appointment & expectations | Priority changes, notes, customer communication |
| Workshop Foreman | Orchestrates execution | Assignments, reprioritization |
| Mechanic | Performs work | Status updates, findings, time spent |
| Planning Service | Owns schedule/time slots | Appointment import, reschedule suggestions |
| Notifications (optional) | Contact customers | SMS/email updates |
Pitstop exposes UIs and integrates with planning via APIs and/or events.
@startuml
skinparam shadowing false
skinparam componentStyle rectangle
rectangle "Planning Service" as Planning
rectangle "Pitstop Backend" as Backend #orangered
rectangle "Admin Overview UI" as AdminUI
rectangle "Workshop View UI" as WorkshopUI
rectangle "Notification Service\n(optional)" as Notify
Planning --> Backend : REST: Appointments\n(+ optional Webhooks)
Backend --> Planning : REST: Status Updates\n(Delay, Ready, Reschedule)
AdminUI --> Backend : HTTPS: Work Orders,\nAssignments, Priorities
Backend --> AdminUI : HTTPS: Dashboard Data
WorkshopUI <--> Backend : WebSocket: Live board\nStatus + Notes
Backend --> Notify : REST: Send SMS/email
@enduml| Peer | Interface | Direction | Protocol/Format | Notes |
|---|---|---|---|---|
| Planning Service | Appointments API | Inbound | REST/JSON | Full import + incremental sync |
| Planning Service (optional) | Webhooks | Inbound | HTTP/JSON | Push appointment changes |
| Pitstop → Planning | Status updates | Outbound | REST/JSON | Delay, ready, reschedule proposal |
| Admin Overview UI | Work Orders API | Bidirectional | HTTPS/JSON | RBAC, dashboards |
| Workshop View UI | Live Updates | Bidirectional | WebSocket/JSON | Low latency, optimized payloads |
| Notification Service (optional) | Notifications API | Outbound | REST/JSON | Customer updates |
Appointment imported from planning:
{
"appointmentId": "A-10293",
"plate": "12-AB-34",
"start": "2026-01-12T09:00:00+01:00",
"service": "OilChange",
"customerRef": "C-4451"
}Workshop update from a mechanic:
{
"workOrderId": "WO-7781",
"status": "WaitingForParts",
"note": "Brake pads not in stock",
"updatedBy": "mechanic-17",
"updatedAt": "2026-01-12T10:41:00+01:00"
}@startuml
skinparam shadowing false
skinparam componentStyle rectangle
rectangle "Outside Pitstop" {
rectangle "Planning Service"
rectangle "Notification Service\n(optional)"
rectangle "Inventory/Parts System\n(optional)"
}
rectangle "Pitstop (inside boundary)" {
rectangle "Work Order Domain"
rectangle "Sync & Integration Layer"
rectangle "Admin Overview UI"
rectangle "Workshop View UI"
}
"Planning Service" --> "Sync & Integration Layer" : appointments
"Sync & Integration Layer" --> "Planning Service" : status updates
"Work Order Domain" --> "Admin Overview UI" : dashboards
"Work Order Domain" --> "Workshop View UI" : task board
"Sync & Integration Layer" --> "Notification Service\n(optional)" : notify
"Work Order Domain" --> "Inventory/Parts System\n(optional)" : parts status reference
@endumlPitstop is designed as an operational “source of truth” for work orders and status, with near real-time synchronization between planning and workshop execution.
-
Modular monolith backend (initially)
Keep deployment simple and change-friendly while the domain stabilizes.
Modules are strict (no “grab-bag services”) and communicate via explicit interfaces. -
Adapter-based integrations (Planning, Notifications, Parts status)
Each external system sits behind a port/adapter boundary to protect domain logic and keep new integrations fast (Quality goal: ≤ 2 days). -
Near real-time updates via push
Workshop and admin need shared truth quickly (≤ 2 seconds).
Use WebSocket/SSE where possible; fall back to efficient polling. -
Degraded-mode workshop operation
Workshop UI supports local queueing and later sync when connectivity returns. -
Audit-first changes for work order state
Every status change and important edits record who/when/why (immutable history), enabling dispute resolution and throughput analysis.
Overview (Level 1) — main building blocks and dependencies.
@startuml
skinparam shadowing false
skinparam componentStyle rectangle
rectangle "Planning Service(s)" as Planning
rectangle "Notification Service\n(optional)" as Notify
rectangle "Parts Status Source\n(optional)" as Parts
package "Pitstop (overall system)" #orangered {
rectangle "Admin Overview UI" as AdminUI
rectangle "Workshop View UI\n(degraded mode capable)" as WorkshopUI
rectangle "Pitstop Backend" as Backend
rectangle "Sync & Integration Layer" as Sync
rectangle "Audit/Event Log" as Audit
database "Pitstop DB" as DB
}
Planning --> Sync : appointments\n(+changes)
Sync --> Planning : status updates\n(reschedule proposals)
AdminUI --> Backend : HTTPS/JSON\nwork orders, planning views
WorkshopUI --> Backend : WebSocket/JSON\nlive board + updates
Backend --> DB : read/write
Backend --> Audit : append events
Sync --> Backend : mapped changes\n(commands/events)
Backend --> Sync : integration events
Backend --> Parts : query parts status\n(reference only)
Backend --> Notify : send updates\n(optional)
Notify --> AdminUI : delivery status\n(optional)
@endumlBlack-boxes (Level 1)
| Block | Responsibility | Key Interfaces |
|---|---|---|
| Admin Overview UI | Dashboard, coordination, customer comms support | HTTPS/JSON to Backend |
| Workshop View UI | Bay/task board, fast updates, degraded mode | WebSocket/JSON to Backend |
| Backend | Core domain + APIs + orchestration | HTTPS/JSON + WS + internal module interfaces |
| Sync & Integration | Mapping + sync strategy per planning vendor | REST/JSON, webhooks, retry |
| Audit/Event Log | Immutable history for accountability + analytics | Append/read APIs |
| DB | Operational persistence | SQL (implementation-specific) |
@startuml
skinparam shadowing false
skinparam componentStyle rectangle
package "Pitstop Backend (white-box)" {
rectangle "API Layer\n(REST + WS)" as Api
rectangle "AuthN/AuthZ\n(RBAC)" as Auth
package "Modules (black-boxes)" {
rectangle "Work Order Module" as WorkOrders
rectangle "Workshop Module" as Workshop
rectangle "Admin Module" as Admin
rectangle "Customer/Vehicle Module" as Customer
rectangle "Reporting Read Models" as Reporting
}
package "Integration Ports" {
rectangle "Planning Port" as PlanningPort
rectangle "Notification Port" as NotifyPort
rectangle "Parts Status Port" as PartsPort
}
rectangle "Audit Writer" as AuditWriter
database "Pitstop DB" as DB
}
Api --> Auth
Api --> WorkOrders
Api --> Workshop
Api --> Admin
Api --> Customer
Api --> Reporting
WorkOrders --> AuditWriter
Workshop --> AuditWriter
Admin --> AuditWriter
AuditWriter --> DB
WorkOrders --> PlanningPort
Workshop --> PlanningPort
Admin --> NotifyPort
WorkOrders --> PartsPort
@endumlNotes
- Modules contain domain rules; ports isolate vendor protocols/mapping.
- Reporting read models can be optimized independently (avoid OLTP pain).
Why this scenario matters
- It hits the core value: planning ↔ execution sync.
- It exercises consistency, auditability, and integration boundaries.
@startuml
hide footbox
skinparam shadowing false
participant "Planning Service" as Planning
participant "Sync Adapter" as Sync
participant "Backend API" as Api
participant "Work Order Module" as WOD
database "Pitstop DB" as DB
participant "Audit/Event Log" as Audit
participant "Workshop View UI" as UI
== Import appointment ==
Planning -> Sync ++ : appointmentChanged(appointment)
Sync -> Api --++ : upsertAppointment(mapped)
Api -> WOD --++ : UpsertWorkOrderFromAppointment(cmd)
WOD -> DB : load/update work order
WOD -> Audit : appendEvent(WorkOrderUpserted)
WOD --> Api --++ : result(workOrderId, state)
Api -> UI -- : pushUpdate(workOrder summary)\n(WS ≤ 2s)
== Workshop progress ==
UI -> Api ++ : updateStatus(WO-7781, WaitingForParts, note)
Api -> WOD --++ : ChangeStatus(cmd)
WOD -> DB : persist new state
WOD -> Audit : appendEvent(StatusChanged)
WOD -> Sync --++ : integrationEvent(StatusChanged)
Sync -> Planning -- : statusUpdate(delay/ready/reschedule)
@endumlFailure / exception notes
- Planning API unavailable → Sync queues outbound updates with retry + backoff.
- Duplicate appointment updates → idempotency key (appointmentId + version/timestamp).
- Conflicting edits → “last-write-wins” only for safe fields; status changes may require rules (e.g., foreman override).
Intent
- Mechanic keeps working even if Wi-Fi is spotty.
- Updates are queued locally and reconciled when online.
@startuml
skinparam shadowing false
|Workshop View UI|
start
:Mechanic updates status + note;
:Store update in local queue;
if (Online?) then (yes)
:Send update to Backend;
else (no)
:Show "Queued" indicator;
endif
|Backend|
if (Update received?) then (yes)
:Validate permissions + state rules;
:Persist + append audit event;
:Broadcast to other clients;
endif
|Workshop View UI|
if (Connection restored?) then (yes)
:Replay queued updates;
:Handle conflicts (merge rules);
endif
stop
@endumlConflict handling rule of thumb
- Notes append (safe).
- Status changes validate allowed transitions; reject invalid transitions with a clear “needs foreman review” message.
Pitstop behavior differs per garage/network reliability. These settings are owned by Ops and are part of the deployment definition.
Key setting: ConnectivityMode
OnlineFirst(default): normal operation, real-time updates preferredOfflineFirst: prioritize local queueing + aggressive retries (workshop-heavy garages / flaky Wi-Fi)
Where configured
- Container env var
Pitstop__ConnectivityModeorappsettings.{Environment}.json
// appsettings.Production.json
{
"Pitstop": {
"ConnectivityMode": "OfflineFirst",
"Realtime": {
"Transport": "WebSocket",
"FallbackToPollingSeconds": 5
},
"Sync": {
"RetryPolicy": "ExponentialBackoff",
"MaxRetries": 10
}
}
}@startuml
skinparam shadowing false
node "On-prem Host" #lightgreen {
node "Container Runtime" #white {
artifact "Admin UI\n(container)" as AdminUI
artifact "Workshop UI\n(container)" as WorkshopUI
artifact "Pitstop Backend\n(container)" as Backend
}
database "Pitstop DB" as DB
}
cloud "External Systems" #lightblue {
node "Planning Service(s)" as Planning
node "Notification Service\n(optional)" as Notify
}
AdminUI --> Backend : HTTPS
WorkshopUI --> Backend : WebSocket/HTTPS
Backend --> DB : SQL
Backend --> Planning : REST/webhooks
Backend --> Notify : REST
@enduml- Central DB + audit store; site-level caches for workshop responsiveness.
- Reporting can run off read replicas.
Operational notes
- Monitoring: request latency, WS connection health, sync queue depth, retry rate.
- Backups: DB daily + audit log retention policy.
- Security: network segmentation; outbound allowlist to planning/PSP endpoints.
Implementation
- Auth: JWT bearer tokens.
- Authorization: policy-based checks, mapped from roles/claims.
Claims (example)
role:Mechanic,Foreman,ServiceAdvisorgarageId: used for tenant/site scopingpermissions: optional fine-grained list for exceptions (e.g. discount approval)
Enforcement
-
API endpoints require policies like:
WorkOrders.Read,WorkOrders.UpdateStatus,Planning.Sync.Write
-
Workshop actions use server-side authorization too (don’t trust the UI).
Example policy mapping
Mechanic→ can update status for assigned work ordersForeman→ can override conflicts + reprioritize bays
Implementation
- Workshop UI uses WebSocket (or SignalR-like hub semantics).
- Admin UI typically uses HTTPS + incremental refresh (lighter).
- Both consume the same “work order changed” message format.
Config-driven behavior
- Controlled by
Pitstop:Realtime:TransportandFallbackToPollingSeconds. - If WS fails: client polls every N seconds and shows a small “reconnecting” banner.
Payload shape (example)
{
"type": "WorkOrderChanged",
"workOrderId": "WO-7781",
"version": 42,
"changedFields": ["status", "notePreview", "updatedAt"],
"status": "WaitingForParts",
"updatedAt": "2026-01-12T10:41:00+01:00"
}Implementation
- Workshop UI stores updates in a local outbox queue (IndexedDB / local storage abstraction).
- Each queued item includes an idempotency key to avoid double-apply.
Queue item (example)
{
"idempotencyKey": "WO-7781:42:mechanic-17:10:41:12",
"workOrderId": "WO-7781",
"command": "ChangeStatus",
"payload": { "status": "WaitingForParts", "note": "Brake pads not in stock" },
"queuedAt": "2026-01-12T10:41:00+01:00"
}Replay rules
- On reconnect: replay in order, stop on hard conflicts, show resolution UI.
- Notes are append-only → safe merge.
- Status changes validated by state machine → reject invalid transitions.
Config hook
- If
Pitstop:ConnectivityMode = OfflineFirst, the UI always queues first and sends async. - If
OnlineFirst, UI sends immediately and only queues on failure.
Implementation
- Every significant change writes an audit event (append-only table or event store).
- Read model derived for dashboards/analytics.
Audit event schema (example)
{
"eventId": "evt-9b1c",
"aggregateType": "WorkOrder",
"aggregateId": "WO-7781",
"eventType": "StatusChanged",
"occurredAt": "2026-01-12T10:41:00+01:00",
"actor": { "userId": "mechanic-17", "role": "Mechanic" },
"reason": "WaitingForParts",
"data": {
"from": "InProgress",
"to": "WaitingForParts",
"note": "Brake pads not in stock"
},
"correlationId": "corr-2f8d"
}Why this feels “real”
- This supports: disputes, compliance export, and throughput analysis without guessing.
Implementation
- Sync adapter uses:
- retry with exponential backoff (
MaxRetries) - circuit breaker when vendor returns repeated 5xx/timeout
- dead-letter queue after retry budget exhausted
- retry with exponential backoff (
User-facing behavior
- Admin UI shows: “Planning sync delayed (vendor outage). Updates queued.”
Config
{
"Pitstop": {
"Sync": {
"MaxRetries": 10,
"InitialBackoffSeconds": 2,
"CircuitBreaker": { "FailureThreshold": 5, "OpenSeconds": 30 }
}
}
}Implementation
- Structured logs with
correlationId,workOrderId,garageId. - Metrics:
sync_queue_depthws_connected_clientsstatus_update_latency_ms(p95)integration_failures_total
Alert example
sync_queue_depth > 100 for 10 minutes→ vendor down or credentials broken.
- Status: Accepted
- Date: 2026-01-24
Pitstop needs to ship quickly, integrate with multiple planning vendors, and evolve domain rules fast. The system must remain easy to deploy for small garages and still be maintainable for larger chains.
Build the backend as a modular monolith:
- One deployable backend
- Clear internal module boundaries (Work Orders, Workshop, Scheduling Sync, Audit)
- Integrations behind ports/adapters
- ✅ Easier deployment and debugging (one runtime)
- ✅ Faster iteration while domain is still moving
- ✅ Module boundaries prepare for future extraction if needed
⚠️ Requires discipline to prevent “big ball of mud” (enforce boundaries, tests, and ADRs)
- Correct state transitions for work orders (no impossible statuses).
- Planning sync semantics: appointment changes map predictably to work order updates.
- Fast dashboards and workshop board (see 10.2 targets).
- Efficient payloads for real-time updates (send deltas, not full objects).
- Interoperability with multiple Planning Service vendors via adapters.
- Nice-to-have: support both pull (poll/import) and push (webhooks) sync modes per vendor.
- “Glove-friendly” workshop UX: minimal taps and readable UI in harsh environments.
- Nice-to-have: accessibility baseline (keyboard navigation for Admin UI, readable contrast modes).
- Degraded-mode operation for workshop during flaky internet.
- Sync backlog does not break core operations; queued updates recover after outage.
- Nice-to-have: multi-node backend option for chains (active/passive or rolling update strategy).
- Role-based access control (RBAC) with site scoping (
garageId). - Secure audit trail; prevent tampering with history.
- Nice-to-have: step-up auth for finance-sensitive actions (discounts, write-offs).
- New planning integration without changing core work order rules (adapter boundary).
- Clear module ownership (Work Orders vs Workshop vs Integration vs Reporting).
- Nice-to-have: automated contract tests for vendor APIs + recorded fixtures.
- Containerized deployment (on-prem friendly).
- Config-driven behavior per garage (e.g.,
ConnectivityModein Chapter 7). - Nice-to-have: “single-host installer” packaging for small garages.
- Every significant change records who/when/why and is immutable.
- Support export of work order timelines for disputes and compliance.
- Store only necessary customer data; define retention + deletion policy.
- Nice-to-have: pseudonymized analytics view for reporting.
Scenario-based, testable requirements. Use these as acceptance criteria and monitoring targets.
| Scenario | Stimulus | Response | Metric/Target |
|---|---|---|---|
| Wi-Fi outage | 15 min disconnect | Workshop continues; updates queued | ≥ 99% actions succeed offline |
| Reconnect | Network returns | Queue replays + sync completes | drained within ≤ 60s |
| Planning outage | Vendor down | Outbound updates queued + retried | workshop not blocked |
| Scenario | Stimulus | Response | Metric/Target |
|---|---|---|---|
| Add new planning vendor | New API/mapping | Add adapter; domain unchanged | ≤ 2 days, core untouched |
| Add new status | ReadyForPickup |
Update state machine + UI mapping | localized change + tests |
| Change KPI definition | “lateness” formula changes | Update read model only | no write-path impact |
| Scenario | Stimulus | Response | Metric/Target |
|---|---|---|---|
| Status update appears everywhere | Mechanic sets WaitingForParts |
Admin + Workshop UIs converge | ≤ 2s end-to-end (p95) |
| Duplicate planning updates | Planning sends same appointment twice | System processes once (idempotent) | 0 duplicate work orders |
| Conflict edit | Foreman reprioritizes while mechanic updates | Deterministic resolution + visible warning | Conflict surfaced; no silent loss |
| Scenario | Stimulus | Response | Metric/Target |
|---|---|---|---|
| Customer dispute | “You promised 16:00” | Export full timeline | ≤ 60s export |
| Sensitive change | discount/write-off | Stored with reason + actor | 100% completeness |
| Throughput analysis | cycle time per bay | derive from events | no manual stitching |
| Scenario | Stimulus | Response | Metric/Target |
|---|---|---|---|
| Glove-friendly update | mechanic changes status | minimal interactions | ≤ 3 taps, ≤ 5s |
| Foreman reprioritizes | drag/drop | visible everywhere | reflected in ≤ 2s |
| Advisor handles reschedule | planning change arrives | clear delta shown | “what changed” view |
| Scenario | Stimulus | Response | Metric/Target |
|---|---|---|---|
| Cross-garage access attempt | user tries other garageId |
denied | 100% blocked |
| Token leaked | token reuse from unknown device | revoke/expire quickly | short TTL + refresh |
| Audit tampering attempt | try to edit history | prevented + logged | immutable storage |
| Scenario | Stimulus | Response | Metric/Target |
|---|---|---|---|
| Sync backlog grows | vendor slow/down | alert + diagnosis signal | sync_queue_depth alert |
| WS instability | disconnect spike | fallback works + alert | no data loss |
| Latency regression | new release | p95 tracked | thresholds + release marker |
Risks are phrased as “what could hurt us” + “what we’ll do about it”.
| Risk / debt item | Why it matters | Mitigation / decision |
|---|---|---|
| Integration ambiguity per Planning Vendor | Each vendor has different semantics (cancellations, reschedules, no-shows), causing inconsistent work orders | Define a vendor mapping spec + contract tests; keep vendor-specific logic in adapters |
| Offline sync conflicts | Workshop can update while foreman/admin also edits → conflict resolution can become messy | Keep conflict rules simple (append notes; validate status transitions); provide “needs foreman review” path |
| Backlog growth in sync queue | Vendor outage or slow API can pile up updates, delaying customer comms | Monitor sync_queue_depth; circuit breaker; dead-letter queue + ops playbook |
| WebSocket instability in harsh networks | Real-time UX can degrade unpredictably in garages | Configurable fallback to polling (Realtime:FallbackToPollingSeconds); reconnect UX; track disconnect rates |
| Audit log volume / reporting load | Auditability creates data; dashboards can overload OLTP queries | Use read models; partition audit table; retention policies; optional replica for reporting |
Known technical debt (intentional for v1)
- Single backend instance per garage (no HA) → acceptable for v1; revisit for chains.
- Minimal conflict resolution UI → acceptable initially; prioritize based on observed conflicts.
| Term | Meaning |
|---|---|
| Appointment | A planned time slot in the Planning Service |
| Work Order (WO) | The operational “job” in Pitstop: tasks, status, notes, parts dependency, assignment |
| Task / Job | A unit of work within a work order (e.g., Oil change, Replace pads) |
| Bay | Physical workplace in the workshop (where cars are worked on) |
| Foreman | Workshop lead responsible for prioritization and bay allocation |
| Degraded mode | Workshop continues with limited connectivity (local queue + later sync) |
| Outbox (local) | Client-side queue storing commands while offline to replay later |
| Idempotency key | A unique key to ensure repeated messages are processed only once |
| Audit event | Immutable record of a meaningful change (who/when/why/what) |
| Read model | Projection optimized for dashboards/reporting (separate from write model) |
| Planning Vendor | External planning system providing appointments and receiving status updates |
| ConnectivityMode | Deployment setting that tunes online-first vs offline-first behavior |
