This document defines the target architecture for the business-critical vehicle-data acquisition pipeline.
Operational backout reference:
bnc-cpt-api.ROLLBACK-REPORTING-REFACTOR.mdIt exists because the current API has already proven the Tesla-first product flow, but the data-fetch/report core is still too tightly coupled, too Tesla-shaped, and too implicit in its failure handling.
This architecture is the source of truth for how the API must evolve from a working Tesla integration into a scalable multi-provider reporting platform.
The business depends on one question being answered correctly for each vehicle:
For this VIN, what provider data do we have, what failed, why did it fail, and is the result sufficient to produce a trustworthy report?
If the architecture cannot answer that clearly, the system is not production grade.
The current implementation has these structural issues:
As of March 13, 2026, the refactor has started and the codebase is no longer fully in the original mixed shape.
Already extracted from the old mixed service area:
provider_authprovider_acquisitionprovider_clientprovider_normalizationdrive_stateorder_session_serviceOrderSessionModuleResultVehicleSnapshotVehicleAcquisitionOutcomeStill remaining in tesla_fleet.py:
This means the architecture direction is active in code, but the top-level application boundary cleanup is not finished yet.
The current active backend flow is now:
router
-> TeslaFleetService (workflow coordinator)
-> OrderSessionService
-> TeslaProviderAuthService
-> TeslaProviderAcquisitionService
-> TeslaProviderClientService
-> TeslaProviderNormalizationService
This is important:
The system must be capability-driven, not provider-field-driven.
The API should not assume that every manufacturer exposes the same data. Instead, each provider declares which business capabilities it supports and the quality level of that support.
Canonical capability modules:
inventoryidentityvehicle_statebatterychargingservicewarrantysoftwarefactory_optionstechnical_specsEach provider supports each capability at one of these levels:
fullpartialunsupportedpremiumExample:
{
"provider": "tesla",
"capabilities": {
"inventory": "full",
"identity": "full",
"vehicle_state": "partial",
"battery": "full",
"charging": "partial",
"service": "partial",
"warranty": "partial",
"software": "full",
"factory_options": "partial",
"technical_specs": "premium"
}
}
@dataclass
class VehicleAcquisitionRequest:
session_id: str
provider: str
vehicle_id: str
vin: str
package: str
lang: str
requested_modules: list[str]
@dataclass
class ModuleResult:
module: str
status: str
source_auth: str | None
http_status: int | None
error_code: str | None
error_detail: str | None
raw_payload: dict | None
Allowed status values:
successemptyunsupportedauth_failedtransport_failedschema_failednot_requested@dataclass
class VehicleSnapshot:
provider: str
vin: str
inventory: dict
identity: dict
vehicle_state: dict
battery: dict
charging: dict
service: dict
warranty: dict
software: dict
factory_options: dict
technical_specs: dict
module_status: dict[str, ModuleResult]
@dataclass
class VehicleAcquisitionOutcome:
vin: str
provider: str
core_status: str
reportability: str
snapshot: VehicleSnapshot | None
module_results: dict[str, ModuleResult]
Allowed core_status:
completepartialfailedAllowed reportability:
billable_completebillable_partialnon_billable_failedThe business-critical data flow must be:
Provider API payloads
│
▼
Provider acquisition layer
│
▼
ModuleResult set (raw provider outcomes)
│
▼
Provider normalizer
│
▼
Canonical VehicleSnapshot
│
▼
Reportability decision
│
▼
WUI response model / PDF view model / export view model
This means:
ModuleResult objects.VehicleSnapshot.Renderers must never inspect provider-specific endpoint wrappers directly.
This is provider data in Tesla's own shape.
Example:
{
"response": {
"vin": "LRW3E7EK1RC988948",
"display_name": "JT3",
"state": "online",
"vehicle_config": {
"car_type": "model3",
"trim_badging": "long_range"
},
"charge_state": {
"battery_level": 82,
"usable_battery_level": 80,
"battery_range": 248.6,
"charge_limit_soc": 90,
"charging_state": "Complete"
},
"vehicle_state": {
"car_version": "2024.8.7",
"sentry_mode": false,
"valet_mode": true
},
"drive_state": {
"latitude": 60.1708,
"longitude": 24.9375
}
}
}
Problems with raw provider payloads:
response, nested response, data, etc.)This is the internal model the rest of the system should use.
Example:
{
"provider": "tesla",
"vin": "LRW3E7EK1RC988948",
"inventory": {
"vehicle_id": "149293992919",
"state": "online"
},
"identity": {
"display_name": "JT3",
"make": "Tesla",
"model": "Model 3",
"trim": "Long Range"
},
"vehicle_state": {
"software_version": "2024.8.7",
"sentry_mode": false,
"valet_mode": true,
"location": {
"latitude": 60.1708,
"longitude": 24.9375,
"status": "available"
}
},
"battery": {
"state_of_charge_pct": 82,
"usable_state_of_charge_pct": 80,
"rated_range_km": 400.1,
"charge_limit_pct": 90,
"charging_state": "complete"
},
"charging": {},
"service": {},
"warranty": {},
"software": {},
"factory_options": {},
"technical_specs": {},
"module_status": {
"identity": {
"module": "identity",
"status": "success"
},
"vehicle_state": {
"module": "vehicle_state",
"status": "success"
},
"battery": {
"module": "battery",
"status": "success"
}
}
}
Benefits of the canonical snapshot:
The sequence must always be:
fetch -> classify -> normalize -> assess -> render
Never:
fetch -> render directly -> patch missing fields in UI/PDF
That second pattern is what creates fragile provider-specific behavior and spreads business logic into presentation code.
Example mapping from Tesla raw payload to canonical snapshot:
| Tesla Raw Field | Canonical Snapshot Field |
|---|---|
response.vin |
vin |
response.display_name |
identity.display_name |
response.vehicle_config.car_type |
identity.model |
response.vehicle_config.trim_badging |
identity.trim |
response.charge_state.battery_level |
battery.state_of_charge_pct |
response.charge_state.usable_battery_level |
battery.usable_state_of_charge_pct |
response.charge_state.battery_range |
battery.rated_range_km |
response.charge_state.charge_limit_soc |
battery.charge_limit_pct |
response.charge_state.charging_state |
battery.charging_state |
response.vehicle_state.car_version |
vehicle_state.software_version |
response.vehicle_state.sentry_mode |
vehicle_state.sentry_mode |
response.vehicle_state.valet_mode |
vehicle_state.valet_mode |
response.drive_state.latitude |
vehicle_state.location.latitude |
response.drive_state.longitude |
vehicle_state.location.longitude |
If Tesla returns vehicle_data but omits drive_state, the canonical snapshot
must still be valid, but explicit:
{
"vehicle_state": {
"software_version": "2024.8.7",
"location": {
"latitude": null,
"longitude": null,
"status": "missing_in_payload"
}
},
"module_status": {
"vehicle_state": {
"module": "vehicle_state",
"status": "partial"
}
}
}
That is the difference between a professional acquisition model and an implicit "empty field" workaround.
Hard dependencies determine whether a vehicle is reportable at all.
Current Tesla rule:
vehicle_data is a hard dependency because it provides the minimum usable
state/identity payload for one vehicle.If a hard dependency fails:
failedSoft dependencies enrich the report but do not define basic reportability.
Current Tesla examples:
charging_historyservice_datawarrantyrelease_notesoptionsIf a soft dependency fails:
partialThese require special handling, pricing, or auth.
Current Tesla example:
vehicle_specsIf a premium module fails because partner auth fails:
partialauth_faileddrive_state Ruledrive_state is not a separate business capability.
It is a submodule inside vehicle_state.
Current Tesla rule:
vehicle_data is present but drive_state is missing, that is not
the same as total vehicle_data failurevehicle_state becomes partial, not faileddrive_state was absent
from the upstream payloadThat avoids treating a partially-populated Tesla payload as either a fake success or a total vehicle failure.
Security must be built into the architecture.
provider_authno rendering/PDF code may access token material
provider_acquisition
logs only masked identifiers
normalization
strips/avoids non-essential sensitive fields
presentation
Cross-user data flow is a business-critical failure and must be treated as a severity-one security defect.
Required rules:
session_idsession_id, provider, and vehicle scope and must
reject mismatched status/result retrievalThe architecture must explicitly defend against:
if a user can guess or obtain another user's session_id, they may access
reports, vehicles, or artifacts unless all retrieval flows treat the
session id as a protected bearer secret and enforce TTL/rotation rules
Cross-session cache contamination
if report data is cached by VIN, payment id, or task id without session scoping, one user's Tesla data can appear in another user's report flow
Async artifact mix-ups
if PDF jobs or export jobs are not bound to the originating session, a completed artifact can be downloaded by the wrong user
Payment/report mismatches
if payment verification and report generation are joined only by loose ids, a paid session could accidentally unlock the wrong acquisition outcome
Debug/log leakage
Session length must be defined as part of the API contract, not left implicit.
Recommended target policy:
Session lifecycle rules:
last_accessed_at only on user-owned retrieval actionsInside one deployable API application:
app/
├── domain/
│ ├── acquisition.py
│ ├── capabilities.py
│ ├── reportability.py
│ └── snapshot.py
├── application/
│ ├── sessions/
│ ├── acquisition/
│ └── reporting/
├── providers/
│ ├── base/
│ │ ├── auth.py
│ │ ├── capabilities.py
│ │ ├── inventory.py
│ │ ├── acquisition.py
│ │ └── normalizer.py
│ └── tesla/
│ ├── auth.py
│ ├── inventory.py
│ ├── modules.py
│ ├── acquisition.py
│ └── normalizer.py
├── presentation/
│ ├── api/
│ └── pdf/
└── core/
├── security/
├── observability/
└── resilience/
Responsible for:
Not responsible for:
Responsible for:
Not responsible for:
Responsible for:
Not responsible for:
Responsible for:
Not responsible for:
Responsible for:
Responsible for:
Must consume:
Must not consume:
The WUI should move from “a map of report blobs” to a per-vehicle acquisition result contract.
Target shape:
{
"status": "complete",
"vehicles": [
{
"vin": "LRW3E7EK1RC98****",
"provider": "tesla",
"core_status": "partial",
"reportability": "billable_partial",
"report": {},
"modules": {
"vehicle_state": {"status": "success"},
"charging": {"status": "success"},
"technical_specs": {"status": "auth_failed"}
}
}
]
}
This lets the WUI render:
without guessing from malformed report payloads.
For each vehicle acquisition, structured logs must include:
core_statusreportabilityRaw payloads are excluded by default.
The reporting core is considered working only when all of the following are true for one full end-to-end session:
complete, partial, or failed state.If any of these are false, the core is not yet production-grade.
The shortest professional path from the current implementation to a stable system is:
session_id ownership checks on every report, export, and artifact
retrieval pathsession_id + provider + vehicle scopevehicle_data as the only hard gate for a usable vehicle reportdrive_state as partial vehicle_state, not total failurevehicle_specs as premium and explicit when auth or endpoint access
failsVehicleSnapshotcore_status from reportabilityThe architecture refactor is not complete until these criteria pass:
session_idvehicle_data succeeds at least as partialvehicle_data fails deterministicallydrive_state is represented explicitly as partial datavehicle_specs is represented explicitlyModuleResult and VehicleSnapshotPotential future extraction candidates:
These are optional and should happen only after internal boundaries are stable.
The project should proceed as a secure modular monolith with a provider-agnostic core and Tesla as the first provider implementation.
Do not jump to microservices yet. Do not continue adding Tesla/report fixes inside one oversized service.
The next architectural work must be organized around: