Firestore collections, schemas, relationships, and indexes.
firestore/
├── users/ {uid}
├── customers/ {customerId}
├── routes/ {routeId} format: yyyyMMdd.sequence
├── products/ {productId}
├── vehicles/ {vehicleId}
│ └── maintenance/ {recordId}
├── app_issues/ {issueId}
├── app_status/ {logId}
└── config/
├── settings
├── counters
└── seeding
Document ID: Firebase Auth UID
| Field | Type | Description |
|---|---|---|
id |
string | Firebase Auth UID |
name |
string | Full display name |
email |
string | Login email |
phoneNumber |
string | Optional phone number |
role |
enum | ADMINISTRATOR | MANAGER | EMPLOYEE | VIEWER | PENDING |
searchKey |
string | name.toLowerCase() — used for case-insensitive prefix search |
createdAt |
Timestamp | Account creation time |
Access rules:
- Any authenticated user can read their own document
- Managers/Admins can read all users
- Users cannot modify their own
rolefield (privilege escalation prevention) - Managers/Admins can write all fields except escalating roles to ADMINISTRATOR (Manager cannot create Admin)
Document ID: auto-generated
| Field | Type | Description |
|---|---|---|
id |
string | Document ID |
name |
string | Customer/business name |
address |
string | Street address |
city |
string | City |
region |
string | Region or district |
contactName |
string | Primary contact person |
phone1 |
string | Primary phone |
phone2 |
string | Secondary phone (optional) |
phone3 |
string | Tertiary phone (optional) |
coordinates |
object | { lat: number, lng: number } |
color |
string | Hex color for map/calendar display |
searchKey |
string | name.toLowerCase() |
createdAt |
Timestamp | |
createdBy |
string | User ID who created this customer |
Access rules: Managers/Admins full access. Employees/Viewers read-only.
Document ID: yyyyMMdd.sequence (e.g., 20260415.3)
| Field | Type | Description |
|---|---|---|
id |
string | Document ID (date + sequence) |
title |
string | Display name |
description |
string | Optional notes |
assignedTo |
string | User ID of assigned employee |
createdBy |
string | User ID of creator |
dueDate |
string | ISO date string yyyy-MM-dd |
status |
enum | PENDING | COMPLETED |
priority |
enum | LOW | MEDIUM | HIGH |
createdAt |
Timestamp | |
destinations |
array | Array of DeliveryDestination objects (see below) |
Each element of the destinations array:
| Field | Type | Description |
|---|---|---|
id |
string | Unique destination ID within route |
customerId |
string | Reference to customers collection |
customerName |
string | Denormalized for display |
address |
string | Delivery address |
coordinates |
object | { lat: number, lng: number } |
status |
enum | PENDING | COMPLETED |
completedAt |
Timestamp | When marked complete |
completedBy |
string | User ID |
notes |
string | Employee comments |
photos |
string[] | Array of Storage download URLs |
items |
array | Array of { productId, productName, quantity } |
Access rules:
- Managers/Admins: full read/write
- Employees: can read all routes; can update their assigned routes but cannot change
assignedToordueDate
Indexes:
routes: assignedTo ASC, dueDate DESC → fetching a user's routes sorted by date
routes: status ASC, dueDate DESC → filtering by status
Document ID: auto-generated
| Field | Type | Description |
|---|---|---|
id |
string | Document ID |
name |
string | Product name |
sku |
string | Stock-keeping unit identifier |
category |
string | Product category |
price |
number | Unit price |
unit |
string | Unit of measure (e.g., "box", "kg") |
imageUrl |
string | Optional product image URL |
inStock |
boolean | Stock availability flag |
quantity |
number | Quantity in stock (>= 0) |
searchKey |
string | name.toLowerCase() |
createdAt |
Timestamp |
Access rules: Managers/Admins full access. Firestore rule enforces price > 0, quantity >= 0, required name, category.
Document ID: auto-generated
| Field | Type | Description |
|---|---|---|
id |
string | Document ID |
name |
string | Vehicle display name |
licensePlate |
string | License plate number |
type |
enum | TRUCK | VAN | BIKE | CAR |
status |
enum | ACTIVE | MAINTENANCE | INACTIVE |
assignedTo |
string | User ID of assigned driver (optional) |
make |
string | Manufacturer |
model |
string | Model name |
year |
number | Model year |
vin |
string | Vehicle Identification Number |
mileage |
number | Current odometer reading |
maintenanceDate |
string | Last maintenance date |
maintenanceNotes |
string | Last maintenance notes |
createdAt |
Timestamp |
Access rules: Managers/Admins full access.
| Field | Type | Description |
|---|---|---|
id |
string | Document ID |
vehicleId |
string | Parent vehicle ID |
type |
enum | OIL_CHANGE | TIRE_ROTATION | BRAKE_SERVICE | INSPECTION | BATTERY | REPAIR | OTHER |
date |
string | Service date |
cost |
number | Cost of service |
mileageAtService |
number | Odometer at time of service |
provider |
string | Service provider name |
notes |
string | Additional notes |
performedBy |
string | User ID of manager who logged the record |
createdAt |
Timestamp |
Support ticket system. Document ID: auto-generated.
| Field | Type | Description |
|---|---|---|
id |
string | Document ID |
ticketNumber |
number | Auto-incremented ticket number |
userId |
string | Reporter's user ID |
userName |
string | Reporter's display name |
reportedAt |
Timestamp | |
issueDescription |
string | Description of the issue |
severity |
enum | LOW | MEDIUM | HIGH | CRITICAL |
status |
enum | PENDING | CLOSED |
developerComment |
string | Admin/manager response |
Access rules: All approved users can create. Managers/Admins can read all and update status/comment.
Login audit log. Document ID: auto-generated.
| Field | Type | Description |
|---|---|---|
id |
string | Document ID |
userId |
string | User ID (may be unknown for failures) |
userName |
string | Display name |
userEmail |
string | Email address |
userPhone |
string | Phone number (optional) |
timestamp |
Timestamp | Server-side timestamp |
browserTime |
string | Client-reported time |
userAgent |
string | Browser user-agent string |
platform |
string | OS/platform string |
ipAddress |
string | Detected IP (via public IP APIs, may be "Unknown") |
type |
string | Always 'LOGIN' |
status |
enum | SUCCESS | FAILURE |
failureReason |
string | Error message on failure |
Access rules: Unauthenticated CREATE allowed (to capture failed logins). Admin-only READ. Schema-validated: max 20 fields, type constraints enforced.
Three fixed documents — not a dynamic collection.
| Field | Type | Description |
|---|---|---|
warehouseLocation |
object | { name, coordinates: { lat, lng }, geoLocation } |
enableCamera |
boolean | Global camera feature toggle |
blockUploads |
boolean | Block all new photo uploads |
autoCleanupDays |
number | Delete photos older than N days (0 = disabled) |
| Field | Type | Description |
|---|---|---|
currentCount |
number | Current daily route sequence number |
lastDate |
string | Date of last route created yyyyMMdd |
updatedAt |
Timestamp | Server timestamp of last update |
Updated via Firestore transaction on every new route creation.
Persisted seeding options from System Settings > Maintenance.
| Field | Type | Description |
|---|---|---|
industry |
string | general | auto | pharma | construction | qameh |
city |
string | dubai | amman | doha | riyadh |
numCustomers |
number | Target customer count |
routesPerEmployeePerDay |
number | Route density |
maxStopsPerRoute |
number | Maximum stops per route |
historyWindowDays |
number | Days of historical data to generate |
gs://{bucket}/
├── proofs/
│ └── city={cityName}/
│ └── year={YYYY}/
│ └── month={MM}/
│ └── day={DD}/
│ └── {filename}.jpg ← proof-of-delivery photos
└── backups/
└── {backupFolderName}/
└── data.json ← full Firestore JSON backup
Photo constraints: max 5MB, image content-type only, read restricted to MANAGER/ADMINISTRATOR.