{ "components": { "schemas": { "AlertCode": { "description": "Machine-readable reason code for an import alert.", "enum": [ "MISSING_ADDRESS", "INVALID_ADDRESS", "MISSING_PHONE_NUMBER", "INVALID_PHONE_NUMBER", "INVALID_SECONDARY_PHONE_NUMBER", "MISSING_NAME", "INVALID_NAME", "MISSING_DELIVERY_GROUP", "LOCAL_DUPLICATE" ], "title": "AlertCode", "type": "string" }, "AnnouncementCreate": { "description": "Announcement creation request", "properties": { "attachments": { "items": { "type": "string" }, "title": "Attachments", "type": "array" }, "message": { "title": "Message", "type": "string" }, "subject": { "maxLength": 255, "minLength": 1, "title": "Subject", "type": "string" } }, "required": [ "subject", "message" ], "title": "AnnouncementCreate", "type": "object" }, "AnnouncementLastReadResponse": { "description": "Response model for announcement last read", "properties": { "announcement_last_read_id": { "format": "uuid", "title": "Announcement Last Read Id", "type": "string" }, "last_read_at": { "format": "date-time", "title": "Last Read At", "type": "string" }, "user_id": { "format": "uuid", "title": "User Id", "type": "string" } }, "required": [ "announcement_last_read_id", "user_id", "last_read_at" ], "title": "AnnouncementLastReadResponse", "type": "object" }, "AnnouncementRead": { "description": "Announcement response model", "properties": { "announcement_id": { "format": "uuid", "title": "Announcement Id", "type": "string" }, "attachments": { "items": { "type": "string" }, "title": "Attachments", "type": "array" }, "author_name": { "title": "Author Name", "type": "string" }, "author_role": { "title": "Author Role", "type": "string" }, "created_at": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "Created At" }, "is_read": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Is Read" }, "message": { "title": "Message", "type": "string" }, "subject": { "maxLength": 255, "minLength": 1, "title": "Subject", "type": "string" }, "updated_at": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "Updated At" }, "user_id": { "format": "uuid", "title": "User Id", "type": "string" } }, "required": [ "subject", "message", "announcement_id", "user_id", "author_name", "author_role", "attachments", "created_at", "updated_at" ], "title": "AnnouncementRead", "type": "object" }, "AnnouncementUpdate": { "description": "Announcement update request - all optional", "properties": { "attachments": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "title": "Attachments" }, "message": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Message" }, "subject": { "anyOf": [ { "maxLength": 255, "minLength": 1, "type": "string" }, { "type": "null" } ], "title": "Subject" } }, "title": "AnnouncementUpdate", "type": "object" }, "Attachment": { "description": "Attachment with filename and URL", "properties": { "filename": { "title": "Filename", "type": "string" }, "url": { "title": "Url", "type": "string" } }, "required": [ "filename", "url" ], "title": "Attachment", "type": "object" }, "AuthResponse": { "description": "Authentication response", "properties": { "access_token": { "title": "Access Token", "type": "string" }, "admin_id": { "anyOf": [ { "format": "uuid", "type": "string" }, { "type": "null" } ], "title": "Admin Id" }, "driver_id": { "anyOf": [ { "format": "uuid", "type": "string" }, { "type": "null" } ], "title": "Driver Id" }, "email": { "format": "email", "title": "Email", "type": "string" }, "first_name": { "title": "First Name", "type": "string" }, "full_name": { "readOnly": true, "title": "Full Name", "type": "string" }, "id": { "format": "uuid", "title": "Id", "type": "string" }, "last_name": { "title": "Last Name", "type": "string" }, "remember_me": { "title": "Remember Me", "type": "boolean" }, "role": { "title": "Role", "type": "string" } }, "required": [ "access_token", "id", "first_name", "last_name", "email", "role", "remember_me", "full_name" ], "title": "AuthResponse", "type": "object" }, "BillingCostsResponse": { "properties": { "budget_amount": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Budget Amount" }, "budget_currency": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Budget Currency" }, "budget_display_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Budget Display Name" }, "budget_scope": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Budget Scope" }, "credits": { "title": "Credits", "type": "number" }, "currency": { "title": "Currency", "type": "string" }, "data_as_of": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "Data As Of" }, "gross_cost": { "title": "Gross Cost", "type": "number" }, "invoice_month": { "title": "Invoice Month", "type": "string" }, "month_to_date_cost": { "title": "Month To Date Cost", "type": "number" }, "project_id": { "title": "Project Id", "type": "string" } }, "required": [ "project_id", "invoice_month", "currency", "month_to_date_cost", "gross_cost", "credits", "budget_amount", "budget_currency", "budget_display_name", "budget_scope", "data_as_of" ], "title": "BillingCostsResponse", "type": "object" }, "Body_apply_location_import": { "properties": { "column_map": { "title": "Column Map", "type": "string" }, "delivery_type": { "title": "Delivery Type", "type": "string" }, "file": { "contentMediaType": "application/octet-stream", "title": "File", "type": "string" } }, "required": [ "file", "column_map", "delivery_type" ], "title": "Body_apply_location_import", "type": "object" }, "Body_preview_location_import": { "properties": { "column_map": { "title": "Column Map", "type": "string" }, "delivery_type": { "title": "Delivery Type", "type": "string" }, "file": { "contentMediaType": "application/octet-stream", "title": "File", "type": "string" } }, "required": [ "file", "column_map", "delivery_type" ], "title": "Body_preview_location_import", "type": "object" }, "Body_upload_image": { "properties": { "file": { "contentMediaType": "application/octet-stream", "title": "File", "type": "string" } }, "required": [ "file" ], "title": "Body_upload_image", "type": "object" }, "ChangedEntry": { "description": "An existing location whose fields differ from the import row.\n\nEach field is either the plain new value (unchanged) or a ChangedField object\ncarrying both new and old values.", "properties": { "address": { "anyOf": [ { "type": "string" }, { "$ref": "#/components/schemas/ChangedFieldStr" } ], "title": "Address" }, "contact_name": { "title": "Contact Name", "type": "string" }, "delivery_group": { "anyOf": [ { "type": "string" }, { "$ref": "#/components/schemas/ChangedFieldOptStr" }, { "type": "null" } ], "title": "Delivery Group" }, "dietary_restrictions": { "anyOf": [ { "type": "string" }, { "$ref": "#/components/schemas/ChangedFieldStr" } ], "default": "", "title": "Dietary Restrictions" }, "guardian_name": { "anyOf": [ { "type": "string" }, { "$ref": "#/components/schemas/ChangedFieldOptStr" }, { "type": "null" } ], "title": "Guardian Name" }, "halal": { "anyOf": [ { "type": "boolean" }, { "$ref": "#/components/schemas/ChangedFieldBool" } ], "default": false, "title": "Halal" }, "location_id": { "format": "uuid", "title": "Location Id", "type": "string" }, "num_children": { "anyOf": [ { "type": "integer" }, { "$ref": "#/components/schemas/ChangedFieldOptInt" }, { "type": "null" } ], "title": "Num Children" }, "phone_primary": { "anyOf": [ { "type": "string" }, { "$ref": "#/components/schemas/ChangedFieldStr" } ], "title": "Phone Primary" }, "phone_secondary": { "anyOf": [ { "type": "string" }, { "$ref": "#/components/schemas/ChangedFieldOptStr" }, { "type": "null" } ], "title": "Phone Secondary" }, "row": { "title": "Row", "type": "integer" } }, "required": [ "row", "location_id", "contact_name", "address", "phone_primary" ], "title": "ChangedEntry", "type": "object" }, "ChangedFieldBool": { "properties": { "new_value": { "title": "New Value", "type": "boolean" }, "old_value": { "title": "Old Value", "type": "boolean" } }, "required": [ "new_value", "old_value" ], "title": "ChangedFieldBool", "type": "object" }, "ChangedFieldOptInt": { "properties": { "new_value": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "New Value" }, "old_value": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Old Value" } }, "required": [ "new_value", "old_value" ], "title": "ChangedFieldOptInt", "type": "object" }, "ChangedFieldOptStr": { "properties": { "new_value": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "New Value" }, "old_value": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Old Value" } }, "required": [ "new_value", "old_value" ], "title": "ChangedFieldOptStr", "type": "object" }, "ChangedFieldStr": { "properties": { "new_value": { "title": "New Value", "type": "string" }, "old_value": { "title": "Old Value", "type": "string" } }, "required": [ "new_value", "old_value" ], "title": "ChangedFieldStr", "type": "object" }, "DeliveryTypeRename": { "description": "Request body for renaming a configured delivery type.\n\nRename is a distinct operation from the list-replacing PATCH: it preserves\nthe type's identity, cascading the new name onto every location (active or\nnot) that references the old one. A plain PATCH that swaps a name looks like\na remove + add and is blocked by the in-use guard, so renames must come\nthrough here.", "properties": { "new_name": { "maxLength": 100, "minLength": 1, "title": "New Name", "type": "string" }, "old_name": { "maxLength": 100, "minLength": 1, "title": "Old Name", "type": "string" } }, "required": [ "old_name", "new_name" ], "title": "DeliveryTypeRename", "type": "object" }, "DriveDaysOfWeekEnum": { "enum": [ "Mon", "Tue", "Wed", "Thu", "Fri" ], "title": "DriveDaysOfWeekEnum", "type": "string" }, "DriverAssignmentStatusEnum": { "description": "Whether the routes in a RouteGroup have drivers assigned (read from\nRoute.driver_id).", "enum": [ "Assigned", "Unassigned" ], "title": "DriverAssignmentStatusEnum", "type": "string" }, "DriverHistoryRead": { "description": "One month's km for a driver.\n\nComputed, never stored: the sum of `Route.length` over the driver's\nfrozen routes (those with a RouteSnapshot) in that month. Reassigning a\nroute or correcting its stops updates history automatically, so there is\nno stored total to drift out of sync.", "properties": { "driver_id": { "format": "uuid", "title": "Driver Id", "type": "string" }, "km": { "title": "Km", "type": "number" }, "month": { "title": "Month", "type": "integer" }, "year": { "title": "Year", "type": "integer" } }, "required": [ "driver_id", "year", "month", "km" ], "title": "DriverHistoryRead", "type": "object" }, "DriverHistorySummary": { "description": "Summary of driver's lifetime and current year kilometers", "properties": { "current_year_km": { "title": "Current Year Km", "type": "number" }, "last_year_km": { "title": "Last Year Km", "type": "number" }, "lifetime_km": { "title": "Lifetime Km", "type": "number" } }, "required": [ "lifetime_km", "current_year_km", "last_year_km" ], "title": "DriverHistorySummary", "type": "object" }, "DriverListRead": { "description": "Driver table row with aggregates computed by the list query.", "properties": { "active": { "default": true, "title": "Active", "type": "boolean" }, "address": { "anyOf": [ { "maxLength": 255, "type": "string" }, { "type": "null" } ], "title": "Address" }, "auth_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Auth Id" }, "availability": { "items": { "type": "boolean" }, "title": "Availability", "type": "array" }, "car_make_model": { "anyOf": [ { "maxLength": 255, "type": "string" }, { "type": "null" } ], "title": "Car Make Model" }, "current_year_km": { "default": 0, "title": "Current Year Km", "type": "number" }, "driver_id": { "format": "uuid", "title": "Driver Id", "type": "string" }, "email": { "format": "email", "title": "Email", "type": "string" }, "first_name": { "title": "First Name", "type": "string" }, "full_name": { "readOnly": true, "title": "Full Name", "type": "string" }, "is_active": { "default": false, "title": "Is Active", "type": "boolean" }, "last_delivery": { "anyOf": [ { "format": "date", "type": "string" }, { "type": "null" } ], "title": "Last Delivery" }, "last_name": { "title": "Last Name", "type": "string" }, "last_year_km": { "default": 0, "title": "Last Year Km", "type": "number" }, "license_plate": { "anyOf": [ { "maxLength": 20, "type": "string" }, { "type": "null" } ], "title": "License Plate" }, "note_chain_id": { "anyOf": [ { "format": "uuid", "type": "string" }, { "type": "null" } ], "title": "Note Chain Id" }, "partner_driver_name": { "anyOf": [ { "maxLength": 255, "type": "string" }, { "type": "null" } ], "title": "Partner Driver Name" }, "phone": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Phone" }, "role": { "title": "Role", "type": "string" }, "user_id": { "format": "uuid", "title": "User Id", "type": "string" } }, "required": [ "driver_id", "user_id", "auth_id", "first_name", "last_name", "email", "role", "full_name" ], "title": "DriverListRead", "type": "object" }, "DriverRankingItem": { "properties": { "driver_id": { "title": "Driver Id", "type": "string" }, "driver_name": { "title": "Driver Name", "type": "string" }, "km": { "title": "Km", "type": "number" } }, "required": [ "driver_id", "driver_name", "km" ], "title": "DriverRankingItem", "type": "object" }, "DriverRead": { "properties": { "active": { "default": true, "title": "Active", "type": "boolean" }, "address": { "anyOf": [ { "maxLength": 255, "type": "string" }, { "type": "null" } ], "title": "Address" }, "auth_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Auth Id" }, "availability": { "items": { "type": "boolean" }, "title": "Availability", "type": "array" }, "car_make_model": { "anyOf": [ { "maxLength": 255, "type": "string" }, { "type": "null" } ], "title": "Car Make Model" }, "driver_id": { "format": "uuid", "title": "Driver Id", "type": "string" }, "email": { "format": "email", "title": "Email", "type": "string" }, "first_name": { "title": "First Name", "type": "string" }, "full_name": { "readOnly": true, "title": "Full Name", "type": "string" }, "last_name": { "title": "Last Name", "type": "string" }, "license_plate": { "anyOf": [ { "maxLength": 20, "type": "string" }, { "type": "null" } ], "title": "License Plate" }, "note_chain_id": { "anyOf": [ { "format": "uuid", "type": "string" }, { "type": "null" } ], "title": "Note Chain Id" }, "partner_driver_name": { "anyOf": [ { "maxLength": 255, "type": "string" }, { "type": "null" } ], "title": "Partner Driver Name" }, "phone": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Phone" }, "role": { "title": "Role", "type": "string" }, "user_id": { "format": "uuid", "title": "User Id", "type": "string" } }, "required": [ "driver_id", "user_id", "auth_id", "first_name", "last_name", "email", "role", "full_name" ], "title": "DriverRead", "type": "object" }, "DriverRegister": { "description": "Driver registration request", "properties": { "address": { "anyOf": [ { "maxLength": 255, "type": "string" }, { "type": "null" } ], "title": "Address" }, "availability": { "items": { "type": "boolean" }, "title": "Availability", "type": "array" }, "car_make_model": { "anyOf": [ { "maxLength": 255, "type": "string" }, { "type": "null" } ], "title": "Car Make Model" }, "email": { "format": "email", "maxLength": 254, "title": "Email", "type": "string" }, "first_name": { "maxLength": 255, "minLength": 1, "title": "First Name", "type": "string" }, "last_name": { "maxLength": 255, "minLength": 1, "title": "Last Name", "type": "string" }, "license_plate": { "anyOf": [ { "maxLength": 20, "type": "string" }, { "type": "null" } ], "title": "License Plate" }, "partner_driver_name": { "anyOf": [ { "maxLength": 255, "type": "string" }, { "type": "null" } ], "title": "Partner Driver Name" }, "phone": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Phone" } }, "required": [ "first_name", "last_name", "email" ], "title": "DriverRegister", "type": "object" }, "DriverUpdate": { "properties": { "active": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Active" }, "address": { "anyOf": [ { "maxLength": 255, "type": "string" }, { "type": "null" } ], "title": "Address" }, "availability": { "anyOf": [ { "items": { "type": "boolean" }, "type": "array" }, { "type": "null" } ], "title": "Availability" }, "car_make_model": { "anyOf": [ { "maxLength": 255, "type": "string" }, { "type": "null" } ], "title": "Car Make Model" }, "first_name": { "anyOf": [ { "maxLength": 255, "minLength": 1, "type": "string" }, { "type": "null" } ], "title": "First Name" }, "last_name": { "anyOf": [ { "maxLength": 255, "minLength": 1, "type": "string" }, { "type": "null" } ], "title": "Last Name" }, "license_plate": { "anyOf": [ { "maxLength": 20, "type": "string" }, { "type": "null" } ], "title": "License Plate" }, "partner_driver_name": { "anyOf": [ { "maxLength": 255, "type": "string" }, { "type": "null" } ], "title": "Partner Driver Name" }, "phone": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Phone" } }, "title": "DriverUpdate", "type": "object" }, "DuplicateGroup": { "description": "Rows that refer to the same imported location under the 2-of-3 rule.", "properties": { "matching_fields": { "items": { "$ref": "#/components/schemas/DuplicateMatchField" }, "title": "Matching Fields", "type": "array" }, "rows": { "items": { "type": "integer" }, "title": "Rows", "type": "array" } }, "required": [ "rows", "matching_fields" ], "title": "DuplicateGroup", "type": "object" }, "DuplicateMatchField": { "description": "Import fields that can participate in the 2-of-3 duplicate rule.", "enum": [ "contact_name", "address", "phone_primary" ], "title": "DuplicateMatchField", "type": "string" }, "EmailReminder": { "description": "A single reminder email configuration.\n\nEach reminder fires ``days_before`` days ahead of a route's drive date, at its\nown ``time`` — so admins can set, e.g., a day-before reminder at 9 AM and a\nsame-day reminder at 11 AM.", "properties": { "days_before": { "minimum": 0, "title": "Days Before", "type": "integer" }, "time": { "format": "time", "title": "Time", "type": "string" } }, "required": [ "days_before", "time" ], "title": "EmailReminder", "type": "object" }, "ForgotPasswordRequest": { "properties": { "email": { "format": "email", "title": "Email", "type": "string" } }, "required": [ "email" ], "title": "ForgotPasswordRequest", "type": "object" }, "HTTPValidationError": { "properties": { "detail": { "items": { "$ref": "#/components/schemas/ValidationError" }, "title": "Detail", "type": "array" } }, "title": "HTTPValidationError", "type": "object" }, "JobEnqueueResponse": { "description": "Job creation response", "properties": { "job_id": { "format": "uuid", "title": "Job Id", "type": "string" } }, "required": [ "job_id" ], "title": "JobEnqueueResponse", "type": "object" }, "JobRead": { "description": "Job response model", "properties": { "error_message": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Error Message" }, "job_id": { "format": "uuid", "title": "Job Id", "type": "string" }, "progress": { "$ref": "#/components/schemas/ProgressEnum", "default": "Pending" }, "route_group_id": { "anyOf": [ { "format": "uuid", "type": "string" }, { "type": "null" } ], "title": "Route Group Id" }, "routes_created": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Routes Created" }, "total_distance_km": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Total Distance Km" }, "total_families": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Total Families" }, "total_stops": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Total Stops" } }, "required": [ "job_id" ], "title": "JobRead", "type": "object" }, "LocationCreate": { "description": "Create request model", "properties": { "address": { "title": "Address", "type": "string" }, "contact_name": { "title": "Contact Name", "type": "string" }, "delivery_type": { "maxLength": 100, "minLength": 1, "title": "Delivery Type", "type": "string" }, "dietary_restrictions": { "default": "", "title": "Dietary Restrictions", "type": "string" }, "guardian_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Guardian Name" }, "halal": { "default": false, "title": "Halal", "type": "boolean" }, "in_roster": { "default": true, "title": "In Roster", "type": "boolean" }, "latitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Latitude" }, "location_group_id": { "format": "uuid", "title": "Location Group Id", "type": "string" }, "longitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Longitude" }, "name": { "title": "Name", "type": "string" }, "note_chain_id": { "anyOf": [ { "format": "uuid", "type": "string" }, { "type": "null" } ], "title": "Note Chain Id" }, "num_children": { "default": 0, "minimum": 0, "title": "Num Children", "type": "integer" }, "phone_primary": { "title": "Phone Primary", "type": "string" }, "phone_secondary": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Phone Secondary" }, "place_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Place Id" } }, "required": [ "location_group_id", "name", "contact_name", "address", "phone_primary", "delivery_type" ], "title": "LocationCreate", "type": "object" }, "LocationGroup": { "additionalProperties": false, "description": "Location group model", "properties": { "color": { "title": "Color", "type": "string" }, "created_at": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "Created At" }, "location_group_id": { "format": "uuid", "title": "Location Group Id", "type": "string" }, "name": { "title": "Name", "type": "string" }, "notes": { "default": "", "title": "Notes", "type": "string" }, "updated_at": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "Updated At" } }, "required": [ "name", "color" ], "title": "LocationGroup", "type": "object" }, "LocationGroupCreate": { "description": "Location group creation request", "properties": { "color": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Color" }, "location_ids": { "items": { "format": "uuid", "type": "string" }, "minItems": 1, "title": "Location Ids", "type": "array" }, "name": { "title": "Name", "type": "string" }, "notes": { "default": "", "title": "Notes", "type": "string" } }, "required": [ "name", "location_ids" ], "title": "LocationGroupCreate", "type": "object" }, "LocationGroupRead": { "description": "Location group response model", "properties": { "color": { "title": "Color", "type": "string" }, "location_group_id": { "format": "uuid", "title": "Location Group Id", "type": "string" }, "name": { "title": "Name", "type": "string" }, "notes": { "default": "", "title": "Notes", "type": "string" }, "num_locations": { "title": "Num Locations", "type": "integer" } }, "required": [ "name", "color", "location_group_id", "num_locations" ], "title": "LocationGroupRead", "type": "object" }, "LocationGroupUpdate": { "description": "Location group update request - all optional", "properties": { "color": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Color" }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Name" }, "notes": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Notes" } }, "title": "LocationGroupUpdate", "type": "object" }, "LocationImportEntry": { "description": "Parsed row from import file; all fields optional until validated.", "properties": { "address": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Address" }, "contact_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Contact Name" }, "delivery_group": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Delivery Group" }, "dietary_restrictions": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Dietary Restrictions" }, "guardian_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Guardian Name" }, "halal": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Halal" }, "num_children": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Num Children" }, "phone_primary": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Phone Primary" }, "phone_secondary": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Phone Secondary" } }, "title": "LocationImportEntry", "type": "object" }, "LocationImportPreview": { "description": "What POST /locations/import/preview returns: what the file would do.\n\nsuccess=False when any row has alerts. duplicate_groups lists row numbers and\nmatching fields for each within-file duplicate cluster. net_new/stale/changed\ndescribe how the import would affect the existing locations table.\n\nThe old/new pairs on `changed` are for rendering the diff only — applying\nreplans from the file, so nothing here is read back.", "properties": { "changed": { "default": [], "items": { "$ref": "#/components/schemas/ChangedEntry" }, "title": "Changed", "type": "array" }, "duplicate_groups": { "default": [], "items": { "$ref": "#/components/schemas/DuplicateGroup" }, "title": "Duplicate Groups", "type": "array" }, "net_new": { "default": [], "items": { "$ref": "#/components/schemas/NetNewEntry" }, "title": "Net New", "type": "array" }, "rows": { "items": { "$ref": "#/components/schemas/LocationImportRow" }, "title": "Rows", "type": "array" }, "stale": { "default": [], "items": { "$ref": "#/components/schemas/StaleEntry" }, "title": "Stale", "type": "array" }, "success": { "title": "Success", "type": "boolean" }, "total_rows": { "title": "Total Rows", "type": "integer" } }, "required": [ "success", "total_rows", "rows" ], "title": "LocationImportPreview", "type": "object" }, "LocationImportResult": { "description": "What POST /locations/import returns: what it actually did.", "properties": { "archived": { "items": { "$ref": "#/components/schemas/LocationRead" }, "title": "Archived", "type": "array" }, "created": { "items": { "$ref": "#/components/schemas/LocationRead" }, "title": "Created", "type": "array" } }, "required": [ "created", "archived" ], "title": "LocationImportResult", "type": "object" }, "LocationImportRow": { "properties": { "alerts": { "items": { "$ref": "#/components/schemas/AlertCode" }, "title": "Alerts", "type": "array" }, "location": { "$ref": "#/components/schemas/LocationImportEntry" }, "row": { "title": "Row", "type": "integer" } }, "required": [ "row", "location", "alerts" ], "title": "LocationImportRow", "type": "object" }, "LocationRead": { "description": "Read response model.\n\n`has_future_route` is populated by the service layer (one batched query\nagainst route_stops + route_groups), and `status` is derived from it +\nin_roster. See LocationStatusEnum for the precedence rule.", "properties": { "address": { "title": "Address", "type": "string" }, "assigned_route": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Assigned Route" }, "contact_name": { "title": "Contact Name", "type": "string" }, "delivery_type": { "maxLength": 100, "minLength": 1, "title": "Delivery Type", "type": "string" }, "dietary_restrictions": { "default": "", "title": "Dietary Restrictions", "type": "string" }, "guardian_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Guardian Name" }, "halal": { "default": false, "title": "Halal", "type": "boolean" }, "has_future_route": { "default": false, "title": "Has Future Route", "type": "boolean" }, "in_roster": { "default": true, "title": "In Roster", "type": "boolean" }, "last_delivery_date": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "Last Delivery Date" }, "latest_note": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Latest Note" }, "latitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Latitude" }, "location_group_id": { "format": "uuid", "title": "Location Group Id", "type": "string" }, "location_group_name": { "title": "Location Group Name", "type": "string" }, "location_id": { "format": "uuid", "title": "Location Id", "type": "string" }, "longitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Longitude" }, "name": { "title": "Name", "type": "string" }, "note_chain_id": { "anyOf": [ { "format": "uuid", "type": "string" }, { "type": "null" } ], "title": "Note Chain Id" }, "num_children": { "default": 0, "minimum": 0, "title": "Num Children", "type": "integer" }, "phone_primary": { "title": "Phone Primary", "type": "string" }, "phone_secondary": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Phone Secondary" }, "place_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Place Id" }, "status": { "$ref": "#/components/schemas/LocationStatusEnum", "readOnly": true }, "total_deliveries": { "default": 0, "title": "Total Deliveries", "type": "integer" } }, "required": [ "location_group_id", "name", "contact_name", "address", "phone_primary", "delivery_type", "location_id", "location_group_name", "status" ], "title": "LocationRead", "type": "object" }, "LocationStatusEnum": { "description": "Derived status surfaced on LocationRead. Not stored — computed from\nLocation.in_roster + whether the location appears in a present/future\nroute. Precedence: any present/future route → ACTIVE (regardless of\nroster); otherwise in_roster → UNSCHEDULED; otherwise → INACTIVE.", "enum": [ "Active", "Unscheduled", "Inactive" ], "title": "LocationStatusEnum", "type": "string" }, "LoginRequest": { "description": "Login request", "properties": { "email": { "format": "email", "title": "Email", "type": "string" }, "password": { "title": "Password", "type": "string" }, "remember_me": { "default": false, "title": "Remember Me", "type": "boolean" } }, "required": [ "email", "password" ], "title": "LoginRequest", "type": "object" }, "MonthlyTotalsResponse": { "properties": { "month": { "title": "Month", "type": "integer" }, "total_deliveries": { "title": "Total Deliveries", "type": "integer" }, "total_km": { "title": "Total Km", "type": "number" }, "year": { "title": "Year", "type": "integer" } }, "required": [ "year", "month", "total_km", "total_deliveries" ], "title": "MonthlyTotalsResponse", "type": "object" }, "NetNewEntry": { "description": "A row in the import that has no matching existing location.", "properties": { "address": { "title": "Address", "type": "string" }, "contact_name": { "title": "Contact Name", "type": "string" }, "delivery_group": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Delivery Group" }, "dietary_restrictions": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Dietary Restrictions" }, "guardian_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Guardian Name" }, "halal": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Halal" }, "num_children": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Num Children" }, "phone_primary": { "title": "Phone Primary", "type": "string" }, "phone_secondary": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Phone Secondary" }, "row": { "title": "Row", "type": "integer" } }, "required": [ "row", "contact_name", "address", "phone_primary" ], "title": "NetNewEntry", "type": "object" }, "NoteChainRead": { "description": "Read response model", "properties": { "note_chain_id": { "format": "uuid", "title": "Note Chain Id", "type": "string" }, "read_permission": { "$ref": "#/components/schemas/NotePermission", "default": "Admin" }, "write_permission": { "$ref": "#/components/schemas/NotePermission", "default": "Admin" } }, "required": [ "note_chain_id" ], "title": "NoteChainRead", "type": "object" }, "NoteCreate": { "description": "Create request model - chain_id and user_id set by the service", "properties": { "attachments": { "default": [], "items": { "$ref": "#/components/schemas/Attachment" }, "maxItems": 3, "title": "Attachments", "type": "array" }, "message": { "maxLength": 2000, "minLength": 1, "title": "Message", "type": "string" } }, "required": [ "message" ], "title": "NoteCreate", "type": "object" }, "NoteFeedItem": { "description": "A location note with enough context for cross-location feeds.", "properties": { "attachments": { "default": [], "items": { "$ref": "#/components/schemas/Attachment" }, "title": "Attachments", "type": "array" }, "author_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Author Name" }, "author_role": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Author Role" }, "created_at": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "Created At" }, "is_system": { "default": false, "title": "Is System", "type": "boolean" }, "location_address": { "title": "Location Address", "type": "string" }, "location_group_name": { "title": "Location Group Name", "type": "string" }, "location_id": { "format": "uuid", "title": "Location Id", "type": "string" }, "location_name": { "title": "Location Name", "type": "string" }, "message": { "maxLength": 2000, "minLength": 1, "title": "Message", "type": "string" }, "note_chain_id": { "format": "uuid", "title": "Note Chain Id", "type": "string" }, "note_id": { "format": "uuid", "title": "Note Id", "type": "string" }, "updated_at": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "Updated At" }, "user_id": { "anyOf": [ { "format": "uuid", "type": "string" }, { "type": "null" } ], "title": "User Id" } }, "required": [ "note_chain_id", "message", "note_id", "location_id", "location_name", "location_address", "location_group_name" ], "title": "NoteFeedItem", "type": "object" }, "NoteFeedSort": { "enum": [ "recent", "oldest", "driver", "location" ], "title": "NoteFeedSort", "type": "string" }, "NotePermission": { "description": "Controls who can read/write on a note chain", "enum": [ "Admin", "All" ], "title": "NotePermission", "type": "string" }, "NoteRead": { "description": "Read response model", "properties": { "attachments": { "default": [], "items": { "$ref": "#/components/schemas/Attachment" }, "title": "Attachments", "type": "array" }, "author_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Author Name" }, "created_at": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "Created At" }, "is_system": { "default": false, "title": "Is System", "type": "boolean" }, "message": { "maxLength": 2000, "minLength": 1, "title": "Message", "type": "string" }, "note_chain_id": { "format": "uuid", "title": "Note Chain Id", "type": "string" }, "note_id": { "format": "uuid", "title": "Note Id", "type": "string" }, "updated_at": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "Updated At" }, "user_id": { "anyOf": [ { "format": "uuid", "type": "string" }, { "type": "null" } ], "title": "User Id" } }, "required": [ "note_chain_id", "message", "note_id" ], "title": "NoteRead", "type": "object" }, "NoteUpdate": { "description": "Update request model - only message can be edited", "properties": { "message": { "maxLength": 2000, "minLength": 1, "title": "Message", "type": "string" } }, "required": [ "message" ], "title": "NoteUpdate", "type": "object" }, "OrgContactRead": { "description": "Smaller response object for callers that shouldn't see all settings\n(driver screens, error pages).", "properties": { "contact_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Contact Name" }, "contact_phone": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Contact Phone" } }, "required": [ "contact_name", "contact_phone" ], "title": "OrgContactRead", "type": "object" }, "PaginatedResponse_DriverListRead_": { "properties": { "items": { "items": { "$ref": "#/components/schemas/DriverListRead" }, "title": "Items", "type": "array" }, "page": { "title": "Page", "type": "integer" }, "page_size": { "title": "Page Size", "type": "integer" }, "total": { "title": "Total", "type": "integer" }, "total_pages": { "title": "Total Pages", "type": "integer" } }, "required": [ "items", "total", "page", "page_size", "total_pages" ], "title": "PaginatedResponse[DriverListRead]", "type": "object" }, "PaginatedResponse_LocationRead_": { "properties": { "items": { "items": { "$ref": "#/components/schemas/LocationRead" }, "title": "Items", "type": "array" }, "page": { "title": "Page", "type": "integer" }, "page_size": { "title": "Page Size", "type": "integer" }, "total": { "title": "Total", "type": "integer" }, "total_pages": { "title": "Total Pages", "type": "integer" } }, "required": [ "items", "total", "page", "page_size", "total_pages" ], "title": "PaginatedResponse[LocationRead]", "type": "object" }, "PaginatedResponse_NoteFeedItem_": { "properties": { "items": { "items": { "$ref": "#/components/schemas/NoteFeedItem" }, "title": "Items", "type": "array" }, "page": { "title": "Page", "type": "integer" }, "page_size": { "title": "Page Size", "type": "integer" }, "total": { "title": "Total", "type": "integer" }, "total_pages": { "title": "Total Pages", "type": "integer" } }, "required": [ "items", "total", "page", "page_size", "total_pages" ], "title": "PaginatedResponse[NoteFeedItem]", "type": "object" }, "PaginatedResponse_RouteGroupRead_": { "properties": { "items": { "items": { "$ref": "#/components/schemas/RouteGroupRead" }, "title": "Items", "type": "array" }, "page": { "title": "Page", "type": "integer" }, "page_size": { "title": "Page Size", "type": "integer" }, "total": { "title": "Total", "type": "integer" }, "total_pages": { "title": "Total Pages", "type": "integer" } }, "required": [ "items", "total", "page", "page_size", "total_pages" ], "title": "PaginatedResponse[RouteGroupRead]", "type": "object" }, "PaginatedResponse_RouteWithDateRead_": { "properties": { "items": { "items": { "$ref": "#/components/schemas/RouteWithDateRead" }, "title": "Items", "type": "array" }, "page": { "title": "Page", "type": "integer" }, "page_size": { "title": "Page Size", "type": "integer" }, "total": { "title": "Total", "type": "integer" }, "total_pages": { "title": "Total Pages", "type": "integer" } }, "required": [ "items", "total", "page", "page_size", "total_pages" ], "title": "PaginatedResponse[RouteWithDateRead]", "type": "object" }, "ProgressEnum": { "enum": [ "Pending", "Running", "Cancelled", "Completed", "Failed" ], "title": "ProgressEnum", "type": "string" }, "ResendOnboardingEmailRequest": { "properties": { "email": { "format": "email", "title": "Email", "type": "string" } }, "required": [ "email" ], "title": "ResendOnboardingEmailRequest", "type": "object" }, "RouteDetailRead": { "description": "GET /routes/{route_id} response: the bare route plus its ordered stops.\n\nStops are assembled with snapshot-over-live precedence. See\nRouteStopDetailRead.\n\ndrive_date is sourced from the route's RouteGroup (mirrors\nRouteWithDateRead). delivery_type is uniform across a route's locations, so\nit's read from the first stop's Location and is None when the route has no\nstops.", "properties": { "cloned_from_route_id": { "anyOf": [ { "format": "uuid", "type": "string" }, { "type": "null" } ], "title": "Cloned From Route Id" }, "delivery_type": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Delivery Type" }, "drive_date": { "format": "date", "title": "Drive Date", "type": "string" }, "driver_id": { "anyOf": [ { "format": "uuid", "type": "string" }, { "type": "null" } ], "title": "Driver Id" }, "encoded_polyline": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Encoded Polyline" }, "ends_at_warehouse": { "default": false, "title": "Ends At Warehouse", "type": "boolean" }, "length": { "minimum": 0, "title": "Length", "type": "number" }, "name": { "default": "", "maxLength": 255, "minLength": 1, "title": "Name", "type": "string" }, "note_chain_id": { "anyOf": [ { "format": "uuid", "type": "string" }, { "type": "null" } ], "title": "Note Chain Id" }, "notes": { "default": "", "maxLength": 1000, "title": "Notes", "type": "string" }, "polyline_updated_at": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "Polyline Updated At" }, "route_group_id": { "format": "uuid", "title": "Route Group Id", "type": "string" }, "route_id": { "format": "uuid", "title": "Route Id", "type": "string" }, "start_time": { "anyOf": [ { "format": "time", "type": "string" }, { "type": "null" } ], "title": "Start Time" }, "stops": { "items": { "$ref": "#/components/schemas/RouteStopDetailRead" }, "title": "Stops", "type": "array" } }, "required": [ "length", "route_group_id", "route_id", "drive_date" ], "title": "RouteDetailRead", "type": "object" }, "RouteGenerationGroupInput": { "description": "Input bundle for a single location group route generation.", "properties": { "location_group": { "$ref": "#/components/schemas/LocationGroup" }, "settings": { "$ref": "#/components/schemas/RouteGenerationSettings" } }, "required": [ "location_group", "settings" ], "title": "RouteGenerationGroupInput", "type": "object" }, "RouteGenerationSettings": { "description": "Settings for route generation.\n\nThese are not persisted to the database; used as inputs to services.\n\nThe three configured numbers below — ``max_boxes_per_driver``,\n``children_per_box`` and ``service_time_minutes`` — are required, with no\nschema-level defaults. They come from the ``system_settings`` row (see\n``SystemSettings.boxes_per_car`` / ``children_per_box`` /\n``dropoff_minutes``), and a default here would silently outrank whatever the\norg configured whenever a caller dropped the key. Omitting one is a 422.", "properties": { "children_per_box": { "minimum": 1, "title": "Children Per Box", "type": "integer" }, "max_boxes_per_driver": { "exclusiveMinimum": 0, "title": "Max Boxes Per Driver", "type": "integer" }, "num_routes": { "title": "Num Routes", "type": "integer" }, "return_to_warehouse": { "default": false, "title": "Return To Warehouse", "type": "boolean" }, "route_start_time": { "format": "date-time", "title": "Route Start Time", "type": "string" }, "service_time_minutes": { "minimum": 0, "title": "Service Time Minutes", "type": "integer" } }, "required": [ "route_start_time", "num_routes", "max_boxes_per_driver", "children_per_box", "service_time_minutes" ], "title": "RouteGenerationSettings", "type": "object" }, "RouteGroupCreate": { "description": "Create request model", "properties": { "drive_date": { "format": "date", "title": "Drive Date", "type": "string" }, "name": { "maxLength": 255, "minLength": 1, "title": "Name", "type": "string" }, "notes": { "default": "", "title": "Notes", "type": "string" } }, "required": [ "name", "drive_date" ], "title": "RouteGroupCreate", "type": "object" }, "RouteGroupDuplicate": { "description": "Duplicate request model - overrides for the copied group.\n\nEvery field has a default so the endpoint also works with no body: name\nfalls back to \"Copy of {original}\", drive_date to the original's date, and\ndriver assignments carry over.", "properties": { "copy_drivers": { "default": true, "title": "Copy Drivers", "type": "boolean" }, "drive_date": { "anyOf": [ { "format": "date", "type": "string" }, { "type": "null" } ], "title": "Drive Date" }, "name": { "anyOf": [ { "maxLength": 255, "minLength": 1, "type": "string" }, { "type": "null" } ], "title": "Name" } }, "title": "RouteGroupDuplicate", "type": "object" }, "RouteGroupRead": { "description": "Read response model", "properties": { "created_at": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "Created At" }, "delivery_type": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Delivery Type" }, "drive_date": { "format": "date", "title": "Drive Date", "type": "string" }, "name": { "maxLength": 255, "minLength": 1, "title": "Name", "type": "string" }, "notes": { "default": "", "title": "Notes", "type": "string" }, "num_boxes": { "default": 0, "title": "Num Boxes", "type": "integer" }, "num_drivers_assigned": { "default": 0, "title": "Num Drivers Assigned", "type": "integer" }, "num_locations": { "default": 0, "title": "Num Locations", "type": "integer" }, "num_routes": { "title": "Num Routes", "type": "integer" }, "route_group_id": { "format": "uuid", "title": "Route Group Id", "type": "string" }, "routes": { "default": [], "items": { "$ref": "#/components/schemas/RouteReadSummary" }, "title": "Routes", "type": "array" }, "status": { "$ref": "#/components/schemas/RouteStatusEnum" }, "updated_at": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "Updated At" } }, "required": [ "name", "drive_date", "route_group_id", "num_routes", "status" ], "title": "RouteGroupRead", "type": "object" }, "RouteGroupUpdate": { "description": "Update request model - all optional", "properties": { "drive_date": { "anyOf": [ { "format": "date", "type": "string" }, { "type": "null" } ], "title": "Drive Date" }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Name" }, "notes": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Notes" } }, "title": "RouteGroupUpdate", "type": "object" }, "RoutePatchRequest": { "description": "Request body for PATCH /routes/{route_id}.\n\nAll fields are optional - only provided fields will be updated.\nIf location_ids is provided, the route stops will be fully replaced\nand the routing algorithm will be re-run to update polyline + mileage.", "properties": { "driver_id": { "anyOf": [ { "format": "uuid", "type": "string" }, { "type": "null" } ], "title": "Driver Id" }, "location_ids": { "anyOf": [ { "items": { "format": "uuid", "type": "string" }, "type": "array" }, { "type": "null" } ], "title": "Location Ids" }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Name" }, "notes": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Notes" }, "start_time": { "anyOf": [ { "format": "time", "type": "string" }, { "type": "null" } ], "title": "Start Time" } }, "title": "RoutePatchRequest", "type": "object" }, "RouteRead": { "description": "Read response model", "properties": { "cloned_from_route_id": { "anyOf": [ { "format": "uuid", "type": "string" }, { "type": "null" } ], "title": "Cloned From Route Id" }, "driver_id": { "anyOf": [ { "format": "uuid", "type": "string" }, { "type": "null" } ], "title": "Driver Id" }, "encoded_polyline": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Encoded Polyline" }, "ends_at_warehouse": { "default": false, "title": "Ends At Warehouse", "type": "boolean" }, "length": { "minimum": 0, "title": "Length", "type": "number" }, "name": { "default": "", "maxLength": 255, "minLength": 1, "title": "Name", "type": "string" }, "note_chain_id": { "anyOf": [ { "format": "uuid", "type": "string" }, { "type": "null" } ], "title": "Note Chain Id" }, "notes": { "default": "", "maxLength": 1000, "title": "Notes", "type": "string" }, "polyline_updated_at": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "Polyline Updated At" }, "route_group_id": { "format": "uuid", "title": "Route Group Id", "type": "string" }, "route_id": { "format": "uuid", "title": "Route Id", "type": "string" }, "start_time": { "anyOf": [ { "format": "time", "type": "string" }, { "type": "null" } ], "title": "Start Time" } }, "required": [ "length", "route_group_id", "route_id" ], "title": "RouteRead", "type": "object" }, "RouteReadSummary": { "description": "Lightweight route info returned inside a route group response", "properties": { "length": { "default": 0, "title": "Length", "type": "number" }, "name": { "title": "Name", "type": "string" }, "notes": { "default": "", "title": "Notes", "type": "string" }, "route_id": { "format": "uuid", "title": "Route Id", "type": "string" } }, "required": [ "route_id", "name" ], "title": "RouteReadSummary", "type": "object" }, "RouteStatusEnum": { "enum": [ "Upcoming", "Completed", "Archived" ], "title": "RouteStatusEnum", "type": "string" }, "RouteStopDetailRead": { "description": "A single ordered stop on a route, assembled with snapshot-over-live\nfield precedence: for a frozen (past) route the route_stop_snapshot wins,\notherwise the live Location is read. Embedded in RouteDetailRead.\n\nNotes are intentionally NOT embedded: note_chain_id points at the stop's\nnote chain, fetched separately via GET /note-chains/{id}/notes.", "properties": { "address": { "title": "Address", "type": "string" }, "boxes": { "title": "Boxes", "type": "integer" }, "contact_name": { "title": "Contact Name", "type": "string" }, "latitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Latitude" }, "location_id": { "format": "uuid", "title": "Location Id", "type": "string" }, "longitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Longitude" }, "note_chain_id": { "anyOf": [ { "format": "uuid", "type": "string" }, { "type": "null" } ], "title": "Note Chain Id" }, "phone_primary": { "title": "Phone Primary", "type": "string" }, "phone_secondary": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Phone Secondary" }, "stop_number": { "title": "Stop Number", "type": "integer" } }, "required": [ "stop_number", "location_id", "address", "contact_name", "phone_primary", "boxes" ], "title": "RouteStopDetailRead", "type": "object" }, "RouteWithDateRead": { "description": "Read response model for routes with drive date information.\n\ndrive_date is sourced from RouteGroup.drive_date via the route_group\nrelationship.", "properties": { "box_total": { "title": "Box Total", "type": "integer" }, "delivery_type": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Delivery Type" }, "drive_date": { "format": "date", "title": "Drive Date", "type": "string" }, "driver_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Driver Name" }, "group_name": { "title": "Group Name", "type": "string" }, "length": { "title": "Length", "type": "number" }, "name": { "title": "Name", "type": "string" }, "notes": { "title": "Notes", "type": "string" }, "num_stops": { "title": "Num Stops", "type": "integer" }, "route_group_id": { "format": "uuid", "title": "Route Group Id", "type": "string" }, "route_id": { "format": "uuid", "title": "Route Id", "type": "string" }, "start_time": { "anyOf": [ { "format": "time", "type": "string" }, { "type": "null" } ], "title": "Start Time" }, "status": { "$ref": "#/components/schemas/RouteStatusEnum" } }, "required": [ "route_id", "route_group_id", "name", "notes", "length", "drive_date", "group_name", "start_time", "num_stops", "box_total", "status" ], "title": "RouteWithDateRead", "type": "object" }, "StaleEntry": { "description": "An existing location not present in the import; would be set\nin_roster=False on ingest.", "properties": { "address": { "title": "Address", "type": "string" }, "contact_name": { "title": "Contact Name", "type": "string" }, "delivery_group": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Delivery Group" }, "location_id": { "format": "uuid", "title": "Location Id", "type": "string" }, "num_children": { "default": 0, "title": "Num Children", "type": "integer" }, "phone_primary": { "title": "Phone Primary", "type": "string" }, "phone_secondary": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Phone Secondary" } }, "required": [ "location_id", "contact_name", "address", "phone_primary" ], "title": "StaleEntry", "type": "object" }, "SuggestedDriverResponse": { "description": "A driver suggested for a route (most familiar with its locations from\npast completed deliveries).", "properties": { "driver_id": { "format": "uuid", "title": "Driver Id", "type": "string" }, "driver_name": { "title": "Driver Name", "type": "string" } }, "required": [ "driver_id", "driver_name" ], "title": "SuggestedDriverResponse", "type": "object" }, "SystemSettingsRead": { "description": "Read response model", "properties": { "boxes_per_car": { "default": 10, "minimum": 1, "title": "Boxes Per Car", "type": "integer" }, "children_per_box": { "default": 2, "minimum": 1, "title": "Children Per Box", "type": "integer" }, "contact_name": { "anyOf": [ { "maxLength": 255, "minLength": 1, "type": "string" }, { "type": "null" } ], "title": "Contact Name" }, "contact_phone": { "anyOf": [ { "maxLength": 100, "minLength": 1, "type": "string" }, { "type": "null" } ], "title": "Contact Phone" }, "delivery_types": { "items": { "type": "string" }, "title": "Delivery Types", "type": "array" }, "dropoff_minutes": { "default": 3, "minimum": 0, "title": "Dropoff Minutes", "type": "integer" }, "email_reminders": { "items": { "$ref": "#/components/schemas/EmailReminder" }, "title": "Email Reminders", "type": "array" }, "f4k_wr_address": { "anyOf": [ { "maxLength": 255, "minLength": 1, "type": "string" }, { "type": "null" } ], "title": "F4K Wr Address" }, "f4k_wr_email": { "anyOf": [ { "format": "email", "type": "string" }, { "type": "null" } ], "title": "F4K Wr Email" }, "f4k_wr_facebook": { "anyOf": [ { "maxLength": 255, "minLength": 1, "type": "string" }, { "type": "null" } ], "title": "F4K Wr Facebook" }, "f4k_wr_instagram": { "anyOf": [ { "maxLength": 255, "minLength": 1, "type": "string" }, { "type": "null" } ], "title": "F4K Wr Instagram" }, "f4k_wr_website": { "anyOf": [ { "maxLength": 255, "minLength": 1, "type": "string" }, { "type": "null" } ], "title": "F4K Wr Website" }, "import_column_map": { "anyOf": [ { "additionalProperties": { "type": "string" }, "type": "object" }, { "type": "null" } ], "title": "Import Column Map" }, "route_start_time": { "anyOf": [ { "format": "time", "type": "string" }, { "type": "null" } ], "title": "Route Start Time" }, "system_settings_id": { "format": "uuid", "title": "System Settings Id", "type": "string" }, "warehouse_latitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Warehouse Latitude" }, "warehouse_location": { "anyOf": [ { "minLength": 1, "type": "string" }, { "type": "null" } ], "title": "Warehouse Location" }, "warehouse_longitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Warehouse Longitude" } }, "required": [ "system_settings_id" ], "title": "SystemSettingsRead", "type": "object" }, "SystemSettingsUpdate": { "description": "Update request model - all optional", "properties": { "boxes_per_car": { "anyOf": [ { "minimum": 1, "type": "integer" }, { "type": "null" } ], "title": "Boxes Per Car" }, "children_per_box": { "anyOf": [ { "minimum": 1, "type": "integer" }, { "type": "null" } ], "title": "Children Per Box" }, "contact_name": { "anyOf": [ { "maxLength": 255, "minLength": 1, "type": "string" }, { "type": "null" } ], "title": "Contact Name" }, "contact_phone": { "anyOf": [ { "maxLength": 100, "minLength": 1, "type": "string" }, { "type": "null" } ], "title": "Contact Phone" }, "delivery_types": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "title": "Delivery Types" }, "dropoff_minutes": { "anyOf": [ { "minimum": 0, "type": "integer" }, { "type": "null" } ], "title": "Dropoff Minutes" }, "email_reminders": { "anyOf": [ { "items": { "$ref": "#/components/schemas/EmailReminder" }, "type": "array" }, { "type": "null" } ], "title": "Email Reminders" }, "f4k_wr_address": { "anyOf": [ { "maxLength": 255, "minLength": 1, "type": "string" }, { "type": "null" } ], "title": "F4K Wr Address" }, "f4k_wr_email": { "anyOf": [ { "format": "email", "type": "string" }, { "type": "null" } ], "title": "F4K Wr Email" }, "f4k_wr_facebook": { "anyOf": [ { "maxLength": 255, "minLength": 1, "type": "string" }, { "type": "null" } ], "title": "F4K Wr Facebook" }, "f4k_wr_instagram": { "anyOf": [ { "maxLength": 255, "minLength": 1, "type": "string" }, { "type": "null" } ], "title": "F4K Wr Instagram" }, "f4k_wr_website": { "anyOf": [ { "maxLength": 255, "minLength": 1, "type": "string" }, { "type": "null" } ], "title": "F4K Wr Website" }, "import_column_map": { "anyOf": [ { "additionalProperties": { "type": "string" }, "type": "object" }, { "type": "null" } ], "title": "Import Column Map" }, "route_start_time": { "anyOf": [ { "format": "time", "type": "string" }, { "type": "null" } ], "title": "Route Start Time" }, "warehouse_latitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Warehouse Latitude" }, "warehouse_location": { "anyOf": [ { "minLength": 1, "type": "string" }, { "type": "null" } ], "title": "Warehouse Location" }, "warehouse_longitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Warehouse Longitude" } }, "title": "SystemSettingsUpdate", "type": "object" }, "TotalsResponse": { "properties": { "total_deliveries": { "title": "Total Deliveries", "type": "integer" }, "total_km": { "title": "Total Km", "type": "number" } }, "required": [ "total_km", "total_deliveries" ], "title": "TotalsResponse", "type": "object" }, "UpdatePasswordAuthedRequest": { "properties": { "current_password": { "title": "Current Password", "type": "string" }, "new_password": { "maxLength": 100, "minLength": 8, "title": "New Password", "type": "string" } }, "required": [ "current_password", "new_password" ], "title": "UpdatePasswordAuthedRequest", "type": "object" }, "UpdatePasswordRequest": { "properties": { "new_password": { "maxLength": 100, "minLength": 8, "title": "New Password", "type": "string" }, "password_reset_token": { "title": "Password Reset Token", "type": "string" } }, "required": [ "password_reset_token", "new_password" ], "title": "UpdatePasswordRequest", "type": "object" }, "UserFinalize": { "properties": { "password": { "maxLength": 100, "minLength": 8, "title": "Password", "type": "string" }, "user_invite_id": { "format": "uuid", "title": "User Invite Id", "type": "string" } }, "required": [ "user_invite_id", "password" ], "title": "UserFinalize", "type": "object" }, "ValidateResetTokenRequest": { "properties": { "password_reset_token": { "title": "Password Reset Token", "type": "string" } }, "required": [ "password_reset_token" ], "title": "ValidateResetTokenRequest", "type": "object" }, "ValidationError": { "properties": { "ctx": { "title": "Context", "type": "object" }, "input": { "title": "Input" }, "loc": { "items": { "anyOf": [ { "type": "string" }, { "type": "integer" } ] }, "title": "Location", "type": "array" }, "msg": { "title": "Message", "type": "string" }, "type": { "title": "Error Type", "type": "string" } }, "required": [ "loc", "msg", "type" ], "title": "ValidationError", "type": "object" } }, "securitySchemes": { "HTTPBearer": { "scheme": "bearer", "type": "http" } } }, "info": { "description": "Backend API for the Food4Kids application", "title": "Food4Kids API", "version": "1.0.0" }, "openapi": "3.1.0", "paths": { "/api/announcements/": { "get": { "description": "Retrieve all announcements with is_read status for the authenticated user.", "operationId": "get_announcements", "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/AnnouncementRead" }, "title": "Response Get Announcements", "type": "array" } } }, "description": "Successful Response" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Announcements", "tags": [ "announcements" ] }, "post": { "description": "Create a new announcement", "operationId": "create_announcement", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AnnouncementCreate" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AnnouncementRead" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Create Announcement", "tags": [ "announcements" ] } }, "/api/announcements/mark-read": { "post": { "description": "Mark all announcements as read for the authenticated user.", "operationId": "mark_announcements_as_read", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AnnouncementLastReadResponse" } } }, "description": "Successful Response" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Mark Announcements As Read", "tags": [ "announcements" ] } }, "/api/announcements/{announcement_id}": { "delete": { "description": "Delete an announcement", "operationId": "delete_announcement", "parameters": [ { "in": "path", "name": "announcement_id", "required": true, "schema": { "format": "uuid", "title": "Announcement Id", "type": "string" } } ], "responses": { "204": { "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Delete Announcement", "tags": [ "announcements" ] }, "get": { "description": "Get a single announcement by ID", "operationId": "get_announcement", "parameters": [ { "in": "path", "name": "announcement_id", "required": true, "schema": { "format": "uuid", "title": "Announcement Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AnnouncementRead" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Announcement", "tags": [ "announcements" ] }, "put": { "description": "Update an existing announcement", "operationId": "update_announcement", "parameters": [ { "in": "path", "name": "announcement_id", "required": true, "schema": { "format": "uuid", "title": "Announcement Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AnnouncementUpdate" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AnnouncementRead" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Update Announcement", "tags": [ "announcements" ] } }, "/api/announcements/{announcement_id}/email": { "post": { "description": "Send announcement notification emails to all active drivers (admin only).", "operationId": "send_announcement_email", "parameters": [ { "in": "path", "name": "announcement_id", "required": true, "schema": { "format": "uuid", "title": "Announcement Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": { "type": "integer" }, "title": "Response Send Announcement Email", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Send Announcement Email", "tags": [ "announcements" ] } }, "/api/auth/forgot-password": { "post": { "description": "Triggers password reset for user with specified email (reset link will be emailed)\nReturns 204 regardless to avoid enumeration attacks", "operationId": "forgot_password", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ForgotPasswordRequest" } } }, "required": true }, "responses": { "204": { "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Forgot Password", "tags": [ "authentication" ] } }, "/api/auth/login": { "post": { "description": "Returns access token in response body and sets refreshToken as an httpOnly cookie", "operationId": "login", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LoginRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Login", "tags": [ "authentication" ] } }, "/api/auth/logout": { "post": { "description": "Revokes refresh tokens and clears cookies", "operationId": "logout", "responses": { "204": { "description": "Successful Response" } }, "summary": "Logout", "tags": [ "authentication" ] } }, "/api/auth/refresh": { "post": { "description": "Returns access token in response body and sets refreshToken as an httpOnly cookie", "operationId": "refresh", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthResponse" } } }, "description": "Successful Response" } }, "summary": "Refresh", "tags": [ "authentication" ] } }, "/api/auth/register": { "post": { "description": "Finish an invited account: create the Firebase user, stamp its role claim,\nfill in ``users.auth_id``, burn the invite, and log the caller in.\n\nDeliberately role-agnostic. ``UserInvite`` doesn't distinguish a driver from\nan admin and ``link_firebase_to_user`` reads the role off the user row, so\none endpoint serves both — a driver invited by an admin and an admin created\nby ``python -m app.create_admin`` follow the identical link and page.\n\nUnauthenticated by necessity: the caller has no account yet. The invite id\nin the body *is* the credential — a single-use, 48-hour, unguessable UUID\nbound to one pre-created user row. It grants exactly the role that row\nalready carries, so possession of a link can never escalate anyone.", "operationId": "register", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserFinalize" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Register", "tags": [ "authentication" ] } }, "/api/auth/resend-onboarding": { "post": { "description": "Resends the onboarding/invite email to a pending user.\nReturns 204 regardless of input/status to prevent user enumeration attacks.", "operationId": "resend_onboarding_email", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ResendOnboardingEmailRequest" } } }, "required": true }, "responses": { "204": { "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Resend Onboarding Email", "tags": [ "authentication" ] } }, "/api/auth/update-password": { "post": { "description": "Update an existing user's password if provided a valid password reset token", "operationId": "update_password", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdatePasswordRequest" } } }, "required": true }, "responses": { "204": { "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Update Password", "tags": [ "authentication" ] } }, "/api/auth/update-password-authed": { "post": { "description": "Update an authenticated user's password after verifying their current password,\nrevokes existing refresh tokens, and issues a fresh session with new tokens.", "operationId": "update_password_authed", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdatePasswordAuthedRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Update Password Authed", "tags": [ "authentication" ] } }, "/api/auth/validate-reset-token": { "post": { "description": "Validate that a password reset token exists, isn't used, and hasn't expired.", "operationId": "validate_reset_token", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ValidateResetTokenRequest" } } }, "required": true }, "responses": { "204": { "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Validate Reset Token", "tags": [ "authentication" ] } }, "/api/billing/costs": { "get": { "description": "Return month-to-date spend for the configured project, against its budget.\n\nFigures come from the Cloud Billing export and typically lag by several\nhours — see ``data_as_of``. Responses are cached for\n``BILLING_CACHE_TTL_SECONDS``, which is well under that lag.", "operationId": "get_billing_costs", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BillingCostsResponse" } } }, "description": "Successful Response" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Billing Costs", "tags": [ "billing" ] } }, "/api/drivers/": { "get": { "description": "Paginated driver rows with server-side name search and list aggregates.", "operationId": "get_drivers", "parameters": [ { "description": "Filter by first or last name", "in": "query", "name": "search", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter by first or last name", "title": "Search" } }, { "in": "query", "name": "sort_by", "required": false, "schema": { "default": "name", "enum": [ "name", "current_year_km", "last_year_km", "last_delivery" ], "title": "Sort By", "type": "string" } }, { "in": "query", "name": "order", "required": false, "schema": { "default": "asc", "enum": [ "asc", "desc" ], "title": "Order", "type": "string" } }, { "description": "Page number (1-indexed)", "in": "query", "name": "page", "required": false, "schema": { "default": 1, "description": "Page number (1-indexed)", "minimum": 1, "title": "Page", "type": "integer" } }, { "description": "Number of items per page", "in": "query", "name": "page_size", "required": false, "schema": { "default": 50, "description": "Number of items per page", "maximum": 200, "minimum": 1, "title": "Page Size", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PaginatedResponse_DriverListRead_" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Drivers", "tags": [ "drivers" ] } }, "/api/drivers/initialize": { "post": { "description": "Register a new driver in our backend, creates a User and Driver object, returns DriverRead\nNOTE: This does not create a firebase user, ie the User is in a hanging state\nWe need to do this so that we can implement our invite only system", "operationId": "initialize_driver", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DriverRegister" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DriverRead" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Initialize Driver", "tags": [ "drivers" ] } }, "/api/drivers/{driver_id}": { "delete": { "description": "Delete a driver by ID.\n\nA hard delete of the person: the user account and their Firebase login go\nwith the driver record, so a deleted driver can no longer sign in. Their\nroutes are detached (driver_id SET NULL) rather than deleted: the km and\ndeliveries stay in the org's totals, they just stop being attributed to\nanyone in the per-driver ranking and export.", "operationId": "delete_driver", "parameters": [ { "in": "path", "name": "driver_id", "required": true, "schema": { "format": "uuid", "title": "Driver Id", "type": "string" } } ], "responses": { "204": { "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Delete Driver", "tags": [ "drivers" ] }, "get": { "description": "Get a single driver by ID", "operationId": "get_driver", "parameters": [ { "in": "path", "name": "driver_id", "required": true, "schema": { "format": "uuid", "title": "Driver Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DriverRead" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Driver", "tags": [ "drivers" ] }, "put": { "description": "Update an existing driver", "operationId": "update_driver", "parameters": [ { "in": "path", "name": "driver_id", "required": true, "schema": { "format": "uuid", "title": "Driver Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DriverUpdate" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DriverRead" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Update Driver", "tags": [ "drivers" ] } }, "/api/drivers/{driver_id}/history/": { "get": { "description": "Get monthly km totals, derived from the driver's frozen routes\n(bucketed by drive_date month).\nRules:\n- No year, no month: return all months with activity\n- Year only: return all months for that year\n- Year + month: return specific month\n- Month without year: 400 error", "operationId": "get_driver_history", "parameters": [ { "in": "path", "name": "driver_id", "required": true, "schema": { "format": "uuid", "title": "Driver Id", "type": "string" } }, { "in": "query", "name": "year", "required": false, "schema": { "anyOf": [ { "maximum": 2100, "minimum": 2025, "type": "integer" }, { "type": "null" } ], "title": "Year" } }, { "in": "query", "name": "month", "required": false, "schema": { "anyOf": [ { "maximum": 12, "minimum": 1, "type": "integer" }, { "type": "null" } ], "title": "Month" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/DriverHistoryRead" }, "title": "Response Get Driver History", "type": "array" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Driver History", "tags": [ "driver-history" ] } }, "/api/drivers/{driver_id}/history/summary": { "get": { "description": "Get lifetime and current year KM summary for a driver", "operationId": "get_driver_history_summary", "parameters": [ { "in": "path", "name": "driver_id", "required": true, "schema": { "format": "uuid", "title": "Driver Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DriverHistorySummary" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Driver History Summary", "tags": [ "driver-history" ] } }, "/api/drivers/{driver_id}/history/{year}/export": { "get": { "description": "Export history for all drivers for a specific year. Includes data from that year and the previous year.\n\n- driver_id: Must be \"all\"\n- year: The year to export data for", "operationId": "export_all_drivers_history", "parameters": [ { "in": "path", "name": "driver_id", "required": true, "schema": { "title": "Driver Id", "type": "string" } }, { "in": "path", "name": "year", "required": true, "schema": { "title": "Year", "type": "integer" } } ], "responses": { "200": { "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Export All Drivers History", "tags": [ "driver-history" ] } }, "/api/jobs/": { "get": { "description": "Get all jobs", "operationId": "get_jobs", "parameters": [ { "description": "Filter by job status", "in": "query", "name": "progress", "required": false, "schema": { "anyOf": [ { "$ref": "#/components/schemas/ProgressEnum" }, { "type": "null" } ], "description": "Filter by job status", "title": "Progress" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/JobRead" }, "title": "Response Get Jobs", "type": "array" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Jobs", "tags": [ "jobs" ] } }, "/api/jobs/generate": { "post": { "description": "Accept a generation request: persist it as PENDING and wake the worker.\n\nAdmin-only — route generation is an admin workflow, and it burns Maps quota.", "operationId": "generate_job", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RouteGenerationGroupInput" } } }, "required": true }, "responses": { "202": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/JobEnqueueResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Generate Job", "tags": [ "jobs" ] } }, "/api/jobs/{job_id}": { "get": { "operationId": "get_job", "parameters": [ { "in": "path", "name": "job_id", "required": true, "schema": { "format": "uuid", "title": "Job Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/JobRead" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Job", "tags": [ "jobs" ] } }, "/api/jobs/{job_id}/cancel": { "post": { "description": "Cancel an in-flight route generation job.", "operationId": "cancel_job", "parameters": [ { "in": "path", "name": "job_id", "required": true, "schema": { "format": "uuid", "title": "Job Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/JobRead" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Cancel Job", "tags": [ "jobs" ] } }, "/api/location-groups/": { "get": { "description": "Get all location groups", "operationId": "get_location_groups", "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/LocationGroupRead" }, "title": "Response Get Location Groups", "type": "array" } } }, "description": "Successful Response" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Location Groups", "tags": [ "location-groups" ] }, "post": { "description": "Create a new location group", "operationId": "create_location_group", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LocationGroupCreate" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LocationGroupRead" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Create Location Group", "tags": [ "location-groups" ] } }, "/api/location-groups/{location_group_id}": { "delete": { "description": "Delete a location group by ID", "operationId": "delete_location_group", "parameters": [ { "in": "path", "name": "location_group_id", "required": true, "schema": { "format": "uuid", "title": "Location Group Id", "type": "string" } } ], "responses": { "204": { "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Delete Location Group", "tags": [ "location-groups" ] }, "get": { "description": "Get a single location group by ID", "operationId": "get_location_group", "parameters": [ { "in": "path", "name": "location_group_id", "required": true, "schema": { "format": "uuid", "title": "Location Group Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LocationGroupRead" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Location Group", "tags": [ "location-groups" ] }, "patch": { "description": "Update an existing location group", "operationId": "update_location_group", "parameters": [ { "in": "path", "name": "location_group_id", "required": true, "schema": { "format": "uuid", "title": "Location Group Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LocationGroupUpdate" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LocationGroupRead" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Update Location Group", "tags": [ "location-groups" ] } }, "/api/locations/": { "delete": { "description": "Delete all locations", "operationId": "delete_all_locations", "responses": { "204": { "description": "Successful Response" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Delete All Locations", "tags": [ "locations" ] }, "get": { "description": "Get all locations with pagination", "operationId": "get_locations", "parameters": [ { "description": "Filter by one or more delivery types", "in": "query", "name": "delivery_type", "required": false, "schema": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "description": "Filter by one or more delivery types", "title": "Delivery Type" } }, { "description": "Filter by one or more location statuses", "in": "query", "name": "status", "required": false, "schema": { "anyOf": [ { "items": { "$ref": "#/components/schemas/LocationStatusEnum" }, "type": "array" }, { "type": "null" } ], "description": "Filter by one or more location statuses", "title": "Status" } }, { "description": "Filter by one or more location groups", "in": "query", "name": "location_group_id", "required": false, "schema": { "anyOf": [ { "items": { "format": "uuid", "type": "string" }, "type": "array" }, { "type": "null" } ], "description": "Filter by one or more location groups", "title": "Location Group Id" } }, { "description": "Case-insensitive filter across the address/postal code, location, contact and guardian names, food restrictions, delivery group, and phone numbers", "in": "query", "name": "search", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Case-insensitive filter across the address/postal code, location, contact and guardian names, food restrictions, delivery group, and phone numbers", "title": "Search" } }, { "description": "Page number (1-indexed)", "in": "query", "name": "page", "required": false, "schema": { "default": 1, "description": "Page number (1-indexed)", "minimum": 1, "title": "Page", "type": "integer" } }, { "description": "Number of items per page", "in": "query", "name": "page_size", "required": false, "schema": { "default": 50, "description": "Number of items per page", "maximum": 200, "minimum": 1, "title": "Page Size", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PaginatedResponse_LocationRead_" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Locations", "tags": [ "locations" ] }, "post": { "description": "Create a new location", "operationId": "create_location", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LocationCreate" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LocationRead" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Create Location", "tags": [ "locations" ] } }, "/api/locations/import": { "post": { "description": "Apply this import: create net-new locations, update the ones that changed,\nand take stale ones off the roster.\n\nTakes the same file and mapping as the preview rather than a diff posted\nback from it, so the plan is recomputed here by the same planner and the\ncaller cannot choose which rows get rewritten. Rejected with a 400 while\nthe file still has validation errors.", "operationId": "apply_location_import", "requestBody": { "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/Body_apply_location_import" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LocationImportResult" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Apply Location Import", "tags": [ "locations" ] } }, "/api/locations/import/preview": { "post": { "description": "Describe what importing this file would do — row validation plus the\nnet_new / stale / changed split — without writing anything. Requires a\ncolumn_map JSON string mapping system field names to file headers.\n\nSide effect: the submitted column_map is persisted to system_settings so it\nbecomes the default mapping on the next import.", "operationId": "preview_location_import", "requestBody": { "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/Body_preview_location_import" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LocationImportPreview" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Preview Location Import", "tags": [ "locations" ] } }, "/api/locations/{location_id}": { "delete": { "description": "Delete a location by ID", "operationId": "delete_location", "parameters": [ { "in": "path", "name": "location_id", "required": true, "schema": { "format": "uuid", "title": "Location Id", "type": "string" } } ], "responses": { "204": { "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Delete Location", "tags": [ "locations" ] }, "get": { "description": "Get a single location by ID", "operationId": "get_location", "parameters": [ { "in": "path", "name": "location_id", "required": true, "schema": { "format": "uuid", "title": "Location Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LocationRead" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Location", "tags": [ "locations" ] } }, "/api/note-chains/{note_chain_id}": { "delete": { "description": "Delete a note chain and all its notes (admin only)", "operationId": "delete_note_chain", "parameters": [ { "in": "path", "name": "note_chain_id", "required": true, "schema": { "format": "uuid", "title": "Note Chain Id", "type": "string" } } ], "responses": { "204": { "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Delete Note Chain", "tags": [ "note-chains" ] }, "get": { "description": "Get a note chain by ID (checks read permission)", "operationId": "get_note_chain", "parameters": [ { "in": "path", "name": "note_chain_id", "required": true, "schema": { "format": "uuid", "title": "Note Chain Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NoteChainRead" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Note Chain", "tags": [ "note-chains" ] } }, "/api/note-chains/{note_chain_id}/notes": { "get": { "description": "Get notes for a chain with pagination.", "operationId": "get_notes", "parameters": [ { "in": "path", "name": "note_chain_id", "required": true, "schema": { "format": "uuid", "title": "Note Chain Id", "type": "string" } }, { "in": "query", "name": "limit", "required": false, "schema": { "default": 50, "maximum": 200, "minimum": 1, "title": "Limit", "type": "integer" } }, { "in": "query", "name": "offset", "required": false, "schema": { "default": 0, "minimum": 0, "title": "Offset", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/NoteRead" }, "title": "Response Get Notes", "type": "array" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Notes", "tags": [ "note-chains" ] }, "post": { "description": "Add a note to a chain", "operationId": "create_note", "parameters": [ { "in": "path", "name": "note_chain_id", "required": true, "schema": { "format": "uuid", "title": "Note Chain Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NoteCreate" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NoteRead" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Create Note", "tags": [ "note-chains" ] } }, "/api/note-chains/{note_chain_id}/notes/{note_id}": { "delete": { "description": "Delete a note (author or admin only)", "operationId": "delete_note", "parameters": [ { "in": "path", "name": "note_chain_id", "required": true, "schema": { "format": "uuid", "title": "Note Chain Id", "type": "string" } }, { "in": "path", "name": "note_id", "required": true, "schema": { "format": "uuid", "title": "Note Id", "type": "string" } } ], "responses": { "204": { "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Delete Note", "tags": [ "note-chains" ] }, "patch": { "description": "Edit a note's message (author or admin only)", "operationId": "update_note", "parameters": [ { "in": "path", "name": "note_chain_id", "required": true, "schema": { "format": "uuid", "title": "Note Chain Id", "type": "string" } }, { "in": "path", "name": "note_id", "required": true, "schema": { "format": "uuid", "title": "Note Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NoteUpdate" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NoteRead" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Update Note", "tags": [ "note-chains" ] } }, "/api/notes": { "get": { "description": "Get location notes across all location note chains.", "operationId": "get_notes_feed", "parameters": [ { "description": "Sort by recent, oldest, driver, or location", "in": "query", "name": "sort", "required": false, "schema": { "$ref": "#/components/schemas/NoteFeedSort", "default": "recent", "description": "Sort by recent, oldest, driver, or location" } }, { "in": "query", "name": "page", "required": false, "schema": { "default": 1, "minimum": 1, "title": "Page", "type": "integer" } }, { "in": "query", "name": "page_size", "required": false, "schema": { "default": 50, "maximum": 200, "minimum": 1, "title": "Page Size", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PaginatedResponse_NoteFeedItem_" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Notes Feed", "tags": [ "notes" ] } }, "/api/reports/monthly-series": { "get": { "description": "Return km and deliveries per month for a trailing window, oldest first.\n\nBacks the homepage statistics bar charts, which need a whole series at\nonce rather than one request per bar.", "operationId": "get_monthly_series", "parameters": [ { "description": "How many months to return, counting back from the end month", "in": "query", "name": "months", "required": false, "schema": { "default": 6, "description": "How many months to return, counting back from the end month", "maximum": 24, "minimum": 1, "title": "Months", "type": "integer" } }, { "description": "Year of the newest month; defaults to the current month", "in": "query", "name": "end_year", "required": false, "schema": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "description": "Year of the newest month; defaults to the current month", "title": "End Year" } }, { "description": "Month of the newest month (1-12)", "in": "query", "name": "end_month", "required": false, "schema": { "anyOf": [ { "maximum": 12, "minimum": 1, "type": "integer" }, { "type": "null" } ], "description": "Month of the newest month (1-12)", "title": "End Month" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/MonthlyTotalsResponse" }, "title": "Response Get Monthly Series", "type": "array" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Monthly Series", "tags": [ "reports" ] } }, "/api/reports/monthly/{year}/{month}/ranking": { "get": { "description": "Return monthly ranking list of drivers by km (descending).", "operationId": "get_monthly_ranking", "parameters": [ { "in": "path", "name": "year", "required": true, "schema": { "title": "Year", "type": "integer" } }, { "in": "path", "name": "month", "required": true, "schema": { "title": "Month", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/DriverRankingItem" }, "title": "Response Get Monthly Ranking", "type": "array" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Monthly Ranking", "tags": [ "reports" ] } }, "/api/reports/totals": { "get": { "description": "Return km driven and deliveries made — all time, or over [start, end).\n\nOmit both bounds for the all-time figures the homepage's headline totals\nshow. Supply both for a window: the params are read as EST when they carry\nno timezone, then reduced to calendar days (a drive date is a day, not an\ninstant), and the range is half-open like every other range in the\nreports, so consecutive windows tile instead of double-counting their\nshared boundary day.", "operationId": "get_totals", "parameters": [ { "description": "Start datetime, inclusive (assumed EST if no tz)", "in": "query", "name": "start", "required": false, "schema": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "description": "Start datetime, inclusive (assumed EST if no tz)", "title": "Start" } }, { "description": "End datetime, exclusive (assumed EST if no tz)", "in": "query", "name": "end", "required": false, "schema": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "description": "End datetime, exclusive (assumed EST if no tz)", "title": "End" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TotalsResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Totals", "tags": [ "reports" ] } }, "/api/route-groups": { "get": { "description": "Retrieve all route groups, optionally filtered by date range, weekday, delivery type, route status, and driver assignment status.\nCan include associated routes in the response.", "operationId": "get_route_groups", "parameters": [ { "description": "Filter route groups from this date", "in": "query", "name": "start_date", "required": false, "schema": { "anyOf": [ { "format": "date", "type": "string" }, { "type": "null" } ], "description": "Filter route groups from this date", "title": "Start Date" } }, { "description": "Filter route groups until this date", "in": "query", "name": "end_date", "required": false, "schema": { "anyOf": [ { "format": "date", "type": "string" }, { "type": "null" } ], "description": "Filter route groups until this date", "title": "End Date" } }, { "description": "Filter by one or more weekdays", "in": "query", "name": "weekday", "required": false, "schema": { "anyOf": [ { "items": { "$ref": "#/components/schemas/DriveDaysOfWeekEnum" }, "type": "array" }, { "type": "null" } ], "description": "Filter by one or more weekdays", "title": "Weekday" } }, { "description": "Filter by one or more delivery types", "in": "query", "name": "delivery_type", "required": false, "schema": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "description": "Filter by one or more delivery types", "title": "Delivery Type" } }, { "description": "Filter by one or more route statuses", "in": "query", "name": "route_status", "required": false, "schema": { "anyOf": [ { "items": { "$ref": "#/components/schemas/RouteStatusEnum" }, "type": "array" }, { "type": "null" } ], "description": "Filter by one or more route statuses", "title": "Route Status" } }, { "description": "Filter by one or more driver assignment statuses", "in": "query", "name": "driver_assignment_status", "required": false, "schema": { "anyOf": [ { "items": { "$ref": "#/components/schemas/DriverAssignmentStatusEnum" }, "type": "array" }, { "type": "null" } ], "description": "Filter by one or more driver assignment statuses", "title": "Driver Assignment Status" } }, { "description": "Include routes in the response", "in": "query", "name": "include_routes", "required": false, "schema": { "default": false, "description": "Include routes in the response", "title": "Include Routes", "type": "boolean" } }, { "description": "Case-insensitive filter on the route group name", "in": "query", "name": "search", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Case-insensitive filter on the route group name", "title": "Search" } }, { "description": "Page number (1-indexed)", "in": "query", "name": "page", "required": false, "schema": { "default": 1, "description": "Page number (1-indexed)", "minimum": 1, "title": "Page", "type": "integer" } }, { "description": "Number of items per page", "in": "query", "name": "page_size", "required": false, "schema": { "default": 50, "description": "Number of items per page", "maximum": 200, "minimum": 1, "title": "Page Size", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PaginatedResponse_RouteGroupRead_" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Route Groups", "tags": [ "route-groups" ] }, "post": { "description": "Create a new route group", "operationId": "create_route_group", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RouteGroupCreate" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RouteGroupRead" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Create Route Group", "tags": [ "route-groups" ] } }, "/api/route-groups/{route_group_id}": { "delete": { "description": "Delete a route group and all its route group memberships", "operationId": "delete_route_group", "parameters": [ { "in": "path", "name": "route_group_id", "required": true, "schema": { "format": "uuid", "title": "Route Group Id", "type": "string" } } ], "responses": { "204": { "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Delete Route Group", "tags": [ "route-groups" ] }, "patch": { "description": "Update an existing route group", "operationId": "update_route_group", "parameters": [ { "in": "path", "name": "route_group_id", "required": true, "schema": { "format": "uuid", "title": "Route Group Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RouteGroupUpdate" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RouteGroupRead" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Update Route Group", "tags": [ "route-groups" ] } }, "/api/route-groups/{route_group_id}/duplicate": { "post": { "description": "Duplicate a route group and its routes/stops for a new planning cycle.\nOptional body overrides the copy's name and drive date.", "operationId": "duplicate_route_group", "parameters": [ { "in": "path", "name": "route_group_id", "required": true, "schema": { "format": "uuid", "title": "Route Group Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "anyOf": [ { "$ref": "#/components/schemas/RouteGroupDuplicate" }, { "type": "null" } ], "title": "Overrides" } } } }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RouteGroupRead" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Duplicate Route Group", "tags": [ "route-groups" ] } }, "/api/routes": { "get": { "description": "Get routes with pagination and optional filtering for unassigned routes and date range.\nReturns routes with their drive dates - routes can appear multiple times for different dates.\nWhen unassigned_only is False, returns all routes (no assignment filter).\nWhen unassigned_only is True, returns only routes that are unassigned for the given route group.\n\nRequires a driver or admin caller.\nAdmins may scope to any driver via driver_id (or omit it for all routes).\nDrivers are always scoped to their own routes: omitting driver_id returns\ntheir own routes, and requesting another driver's is rejected.", "operationId": "get_routes", "parameters": [ { "description": "If true, only return unassigned routes. If false, return all routes regardless of assignment status.", "in": "query", "name": "unassigned_only", "required": false, "schema": { "default": false, "description": "If true, only return unassigned routes. If false, return all routes regardless of assignment status.", "title": "Unassigned Only", "type": "boolean" } }, { "description": "Filter route groups from this date", "in": "query", "name": "start_date", "required": false, "schema": { "anyOf": [ { "format": "date", "type": "string" }, { "type": "null" } ], "description": "Filter route groups from this date", "title": "Start Date" } }, { "description": "Filter route groups until this date", "in": "query", "name": "end_date", "required": false, "schema": { "anyOf": [ { "format": "date", "type": "string" }, { "type": "null" } ], "description": "Filter route groups until this date", "title": "End Date" } }, { "description": "Order by drive_date: 'asc' (default, oldest-first) for the upcoming feed, 'desc' (most-recent-first) for the past feed.", "in": "query", "name": "order", "required": false, "schema": { "default": "asc", "description": "Order by drive_date: 'asc' (default, oldest-first) for the upcoming feed, 'desc' (most-recent-first) for the past feed.", "enum": [ "asc", "desc" ], "title": "Order", "type": "string" } }, { "description": "Case-insensitive filter on the assigned driver's name, the route's name, or its route group's name", "in": "query", "name": "search", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Case-insensitive filter on the assigned driver's name, the route's name, or its route group's name", "title": "Search" } }, { "description": "Filter by one or more weekdays of the drive date", "in": "query", "name": "weekday", "required": false, "schema": { "anyOf": [ { "items": { "$ref": "#/components/schemas/DriveDaysOfWeekEnum" }, "type": "array" }, { "type": "null" } ], "description": "Filter by one or more weekdays of the drive date", "title": "Weekday" } }, { "description": "Filter by one or more delivery types", "in": "query", "name": "delivery_type", "required": false, "schema": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "description": "Filter by one or more delivery types", "title": "Delivery Type" } }, { "description": "Filter by one or more route statuses", "in": "query", "name": "route_status", "required": false, "schema": { "anyOf": [ { "items": { "$ref": "#/components/schemas/RouteStatusEnum" }, "type": "array" }, { "type": "null" } ], "description": "Filter by one or more route statuses", "title": "Route Status" } }, { "description": "Filter by one or more driver assignment statuses", "in": "query", "name": "driver_assignment_status", "required": false, "schema": { "anyOf": [ { "items": { "$ref": "#/components/schemas/DriverAssignmentStatusEnum" }, "type": "array" }, { "type": "null" } ], "description": "Filter by one or more driver assignment statuses", "title": "Driver Assignment Status" } }, { "description": "Page number (1-indexed)", "in": "query", "name": "page", "required": false, "schema": { "default": 1, "description": "Page number (1-indexed)", "minimum": 1, "title": "Page", "type": "integer" } }, { "description": "Number of items per page", "in": "query", "name": "page_size", "required": false, "schema": { "default": 50, "description": "Number of items per page", "maximum": 200, "minimum": 1, "title": "Page Size", "type": "integer" } }, { "description": "Filter routes by assigned driver. Admins may pass any driver_id, or omit it to get all routes. Drivers are always scoped to themselves: omitting it returns their own routes, and passing another driver's id is rejected with 403.", "in": "query", "name": "driver_id", "required": false, "schema": { "anyOf": [ { "format": "uuid", "type": "string" }, { "type": "null" } ], "description": "Filter routes by assigned driver. Admins may pass any driver_id, or omit it to get all routes. Drivers are always scoped to themselves: omitting it returns their own routes, and passing another driver's id is rejected with 403.", "title": "Driver Id" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PaginatedResponse_RouteWithDateRead_" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Routes", "tags": [ "routes" ] } }, "/api/routes/{route_id}": { "delete": { "description": "Delete a route by its unique identifier.\n\nParameters:\n route_id (UUID): The unique identifier of the route to delete.\n session (AsyncSession): The database session dependency.\n _ (bool): Indicates that the user is authenticated as a driver (injected by dependency).\n\nReturns:\n None. Responds with HTTP 204 No Content on successful deletion.", "operationId": "delete_route", "parameters": [ { "in": "path", "name": "route_id", "required": true, "schema": { "format": "uuid", "title": "Route Id", "type": "string" } } ], "responses": { "204": { "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Delete Route", "tags": [ "routes" ] }, "get": { "description": "Get a route by its unique identifier, with its ordered stops embedded.\n\nEach stop carries its sequence #, address, contact name, phone (+ secondary),\nbox count, and a note_chain_id reference. Stops are sourced live from\nLocation for upcoming routes and from frozen route_stop_snapshots for past\nroutes. Notes are not embedded: fetch them via GET /note-chains/{id}/notes.\n\nParameters:\n route_id (UUID): The unique identifier of the route to GET.\n session (AsyncSession): The database session dependency.\n\nReturns:\n The route with its ordered stops. Responds with HTTP 200 OK on success.", "operationId": "get_route", "parameters": [ { "in": "path", "name": "route_id", "required": true, "schema": { "format": "uuid", "title": "Route Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RouteDetailRead" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Route", "tags": [ "routes" ] }, "patch": { "description": "Update a route's metadata (name, notes) and/or its stop order/locations.\n\nIf location_ids is provided in the request body:\n- The route's stops are fully replaced with the new ordered list.\n- The routing algorithm is re-run to compute the new polyline and mileage.\n- This will affect ALL route groups that share this route.\n\nIf only name/notes are provided, stops and mileage are left unchanged.", "operationId": "update_route", "parameters": [ { "in": "path", "name": "route_id", "required": true, "schema": { "format": "uuid", "title": "Route Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RoutePatchRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RouteRead" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Update Route", "tags": [ "routes" ] } }, "/api/routes/{route_id}/google-maps-link": { "get": { "description": "Generate a Google Maps directions URL for a route.\n\nTakes a route ID, looks up its stops in order, and builds a Google Maps\ndirections link starting from the warehouse and visiting each stop.\n\nParameters:\n route_id (UUID): The unique identifier of the route.\n session (AsyncSession): The database session dependency.\n\nReturns:\n The Google Maps directions URL as a plain string.", "operationId": "get_google_maps_link", "parameters": [ { "in": "path", "name": "route_id", "required": true, "schema": { "format": "uuid", "title": "Route Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "title": "Response Get Google Maps Link", "type": "string" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Google Maps Link", "tags": [ "routes" ] } }, "/api/routes/{route_id}/suggested-driver": { "get": { "description": "Suggest a driver to assign to a route: the active driver most familiar\nwith the route's locations (by past completed deliveries), excluding\ndrivers already assigned within the given route group.\n\nParameters:\n route_id (UUID): The route to suggest a driver for.\n route_group_id (UUID): The route group the assignment is within.\n session (AsyncSession): The database session dependency.\n\nReturns:\n The suggested driver, or null if there's no candidate.", "operationId": "get_suggested_driver", "parameters": [ { "in": "path", "name": "route_id", "required": true, "schema": { "format": "uuid", "title": "Route Id", "type": "string" } }, { "description": "Route group the route is being assigned within", "in": "query", "name": "route_group_id", "required": true, "schema": { "description": "Route group the route is being assigned within", "format": "uuid", "title": "Route Group Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "anyOf": [ { "$ref": "#/components/schemas/SuggestedDriverResponse" }, { "type": "null" } ], "title": "Response Get Suggested Driver" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get Suggested Driver", "tags": [ "routes" ] } }, "/api/system-settings/": { "get": { "description": "Return the singleton settings row. Never null — PATCH already raises on\na missing row, so a soft read here would mean an unsaveable blank form.", "operationId": "get_system_settings", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SystemSettingsRead" } } }, "description": "Successful Response" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Get System Settings", "tags": [ "system-settings" ] }, "patch": { "description": "Patch the singleton system settings row.", "operationId": "patch_system_settings", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SystemSettingsUpdate" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SystemSettingsRead" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Patch System Settings", "tags": [ "system-settings" ] } }, "/api/system-settings/contact": { "get": { "description": "The org's name and phone. Unauthenticated — the error page renders for\nlogged-out visitors, and these are published details, not member data.", "operationId": "get_org_contact", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OrgContactRead" } } }, "description": "Successful Response" } }, "summary": "Get Org Contact", "tags": [ "system-settings" ] } }, "/api/system-settings/delivery-types/rename": { "post": { "description": "Rename a configured delivery type, cascading onto every location using it.", "operationId": "rename_delivery_type", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeliveryTypeRename" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SystemSettingsRead" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Rename Delivery Type", "tags": [ "system-settings" ] } }, "/api/upload/": { "post": { "description": "Create a file upload", "operationId": "upload_image", "requestBody": { "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/Body_upload_image" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": { "type": "string" }, "title": "Response Upload Image", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Upload Image", "tags": [ "upload" ] } }, "/api/upload/{filename}": { "delete": { "description": "Delete a file given the filename", "operationId": "delete_image", "parameters": [ { "in": "path", "name": "filename", "required": true, "schema": { "title": "Filename", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": { "type": "string" }, "title": "Response Delete Image", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "HTTPBearer": [] } ], "summary": "Delete Image", "tags": [ "upload" ] } } } }