Database
Carplay V2 uses three MySQL tables, all created automatically on server start via oxmysql. There is no manual SQL import required — but the same schema is in the included data.sql if you prefer manual setup.
Tables
| Table | Purpose |
|---|---|
code9_carplay2 | Per-player settings, liked songs, playlist, volume |
code9_carplay2_mileage | Internal mileage tracking (per plate) |
code9_carplay2_dashcam | Uploaded dashcam / security cam recordings |
Table: code9_carplay2
Per-player profile, music preferences, and arbitrary settings.
| Column | Type | Default | Description |
|---|---|---|---|
identifier | VARCHAR(64) | (PK) | Player identifier (license, steam, discord — depends on Config.IdentifierType) |
settings | LONGTEXT | '{}' | JSON blob of settings (theme, accent, name, avatar, notes, places, …) |
liked_songs | LONGTEXT | '[]' | JSON array of liked song objects |
playlist | LONGTEXT | '[]' | JSON array of user playlists |
volume | INT | 50 | Player's last volume setting (0-100) |
created_at | TIMESTAMP | CURRENT_TIMESTAMP | Row creation timestamp |
updated_at | TIMESTAMP | CURRENT_TIMESTAMP ON UPDATE | Auto-updated on any change |
Settings JSON Shape
The settings column holds a flexible JSON object. Common keys:
{
"firstName": "John",
"lastName": "Doe",
"avatar": "12.png",
"avatarUrl": null,
"theme": "dark",
"accent": "#007AFF",
"notes": [ ... ],
"places": [
{ "name": "Home", "icon": "home", "x": 100.0, "y": 200.0 }
],
"recents": [ ... ],
"favorites": [ ... ],
"autopilotFlags": { "DF_STOP_AT_LIGHTS": true },
"speedLimiter": 80,
"suspensionPreset": "standard",
"autoLowerSpeed": 65
}
The exact shape is determined by the React app — feel free to add new keys for custom features.
Auto-Creation
When a player first opens Carplay (or first triggers any persistence write), the server runs INSERT IGNORE to ensure the row exists. Existing rows are never overwritten — only updated.
Table: code9_carplay2_mileage
Internal mileage tracking — used only when Config.MileageSystem = "internal" (or "auto" falls back to internal because no third-party provider is detected).
| Column | Type | Default | Description |
|---|---|---|---|
plate | VARCHAR(32) | (PK) | Vehicle plate text |
mileage | FLOAT | 0 | Total mileage in km |
updated_at | TIMESTAMP | CURRENT_TIMESTAMP ON UPDATE | Last update |
How Mileage Is Tracked
When MileageSystem = "internal":
- Client thread polls vehicle position every ~1 second
- Computes distance from last position, accumulates per plate
- Periodically (and on resource stop) flushes to server
- Server writes to
code9_carplay2_mileageviaINSERT … ON DUPLICATE KEY UPDATE
When MileageSystem = "jg-vehiclemileage" or "cd_garage", this table is not used — the script reads via the third-party export instead.
Table: code9_carplay2_dashcam
Stores metadata for uploaded dashcam and security camera recordings. The actual video file lives at the upload provider (Fivemanage or Discord).
| Column | Type | Default | Description |
|---|---|---|---|
id | INT (PK, AI) | Auto-increment record ID | |
identifier | VARCHAR(64) | Owner identifier (indexed) | |
video_url | VARCHAR(512) | Public URL to the uploaded video | |
duration | INT | 0 | Length in seconds |
file_size | INT | 0 | Bytes |
vehicle_plate | VARCHAR(32) | NULL | Plate the recording was made in |
camera_angle | VARCHAR(16) | 'front' | 'front' or 'rear' |
source | VARCHAR(16) | 'dashcam' | 'dashcam' or 'securitycam' |
created_at | TIMESTAMP | CURRENT_TIMESTAMP | Upload timestamp |
Index
There is an index on identifier for fast per-player recording lookups.
Cleanup
Old recordings beyond Config.DashCam.recording.maxRecordingsPerPlayer (or the security cam equivalent) are not auto-deleted from the upload provider — only from this table. If you want to enforce hard limits, add a server-side cleanup job that calls the Fivemanage delete API or unfurls the Discord message.
Database Driver
Carplay V2 uses oxmysql only — mysql-async and ghmattimysql are not supported. This was a deliberate choice for performance and modern API surface.
If you absolutely must run an older driver, you would need to rewrite the SQL calls in server/open.lua and the relevant module files.
