{ "openapi": "3.0.0", "info": { "title": "SSHF API", "version": "1.1.1", "description": "API for managing veterans documents with Google authentication" }, "servers": [ { "url": "https://sshf-api-330507742215.us-central1.run.app", "description": "API Server" } ], "components": { "securitySchemes": { "GoogleAuth": { "type": "oauth2", "description": "Google OAuth2. The access token must be issued for this API's configured OAuth client; tokens from other clients are rejected with 401. Protected data endpoints return 401 for a missing, invalid, or wrong-audience token and 403 when the account email domain is not permitted or the user lacks the route permission (ALLOWED_EMAIL_DOMAINS is optional; AUTHZ_ROLE_FULL_GROUPS is required on Cloud Run and fails closed when empty). A 403 for a missing route permission includes requiredPermission. On Cloud Run an Admin SDK group-lookup failure returns 503 instead of an empty role list. Off Cloud Run that failure continues with no roles. GET /user/permissions is auth-only. Groups in AUTHZ_ROLE_*_GROUPS match direct or nested Workspace membership via members.hasMember. Each protected route declares x-required-permission.", "flows": { "implicit": { "authorizationUrl": "https://accounts.google.com/o/oauth2/v2/auth", "scopes": { "openid": "OpenID Connect scope", "email": "Email scope", "profile": "Profile scope" } } }, "x-clientId": "330507742215-scerc6p0lvou59tufmohq1b7b4bj0l90.apps.googleusercontent.com", "x-init": { "clientId": "330507742215-scerc6p0lvou59tufmohq1b7b4bj0l90.apps.googleusercontent.com", "appName": "SSHF API" } }, "IntakeIdToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT", "description": "Google-signed service-account ID token used only by POST /review/applications (website intake via the hf_appcollector Cloud Function). The token audience must match REVIEW_INTAKE_AUDIENCE (defaults to API_URL) and the service-account email must be listed in REVIEW_INTAKE_SERVICE_ACCOUNTS. Returns 401 for a missing or invalid token and 403 for an unlisted account." } }, "schemas": { "SearchRequest": { "type": "object", "properties": { "limit": { "type": "integer", "default": 25, "description": "Maximum number of results to return" }, "lastname": { "type": "string", "default": "", "description": "Last name prefix to search for. Apostrophes, periods, and spaces are removed before querying so the term matches the name index. Case is unchanged. Ignored when phone_num is provided." }, "phone_num": { "type": "string", "default": "", "description": "Phone number search term; non-digits are ignored and at least 3 numeric digits are required" }, "status": { "type": "string", "default": "Active", "enum": [ "All", "Active", "Flown", "Deceased", "Removed", "Future-Spring", "Future-Fall", "Future-PostRestriction" ], "description": "Status filter for the search" }, "flight": { "type": "string", "default": "All", "description": "Flight ID filter for the search" } } }, "SearchResult": { "type": "object", "properties": { "type": { "type": "string", "description": "Type of the document" }, "name": { "type": "string", "description": "Name of the person" }, "phone": { "type": "string", "description": "Phone number" }, "city": { "type": "string", "description": "City of residence" }, "appdate": { "type": "string", "description": "Application date" }, "flight": { "type": "string", "description": "Flight assignment" }, "status": { "type": "string", "description": "Current status" }, "pairing": { "type": "string", "description": "Name of paired person" }, "pairingId": { "type": "string", "description": "ID of paired person" } } }, "SearchResults": { "type": "object", "properties": { "total_rows": { "type": "integer", "description": "Total number of rows in the result set" }, "offset": { "type": "integer", "description": "Starting offset of the result set" }, "rows": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Document ID" }, "key": { "type": "array", "items": { "type": "string" }, "description": "Search key used for this result" }, "value": { "$ref": "#/components/schemas/SearchResult" } } } } } }, "Error": { "type": "object", "properties": { "error": { "type": "string" } } }, "Veteran": { "type": "object", "required": [ "name", "type", "address" ], "properties": { "_id": { "type": "string", "description": "Document ID" }, "_rev": { "type": "string", "description": "Document revision" }, "type": { "type": "string", "enum": [ "Veteran" ], "description": "Document type, must be \"Veteran\"" }, "name": { "type": "object", "required": [ "first", "last" ], "properties": { "first": { "type": "string", "pattern": "^[a-zA-Z'. ]{2,}$", "description": "First name (letters, periods, apostrophes and spaces only, min 2 chars)" }, "middle": { "type": "string", "pattern": "^[a-zA-Z' ]*$", "description": "Middle name (letters, apostrophes and spaces only)" }, "last": { "type": "string", "pattern": "^[a-zA-Z'. -]{2,}$", "description": "Last name (letters, periods, apostrophes, hyphens and spaces only, min 2 chars)" }, "nickname": { "type": "string", "pattern": "^[a-zA-Z'. ]*$", "description": "Nickname (letters, periods, apostrophes and spaces only)" } } }, "birth_date": { "type": "string" }, "gender": { "type": "string", "enum": [ "M", "F" ], "description": "Veteran gender" }, "address": { "type": "object", "required": [ "street", "city", "state", "zip", "county", "phone_day" ], "properties": { "street": { "type": "string", "pattern": "^[a-zA-Z0-9.,# /-]{2,}$", "description": "Street address (letters, numbers, basic punctuation, min 2 chars)" }, "city": { "type": "string", "pattern": "^[a-zA-Z. -]{2,}$", "description": "City name (letters, periods, hyphens and spaces only, min 2 chars)" }, "state": { "type": "string", "pattern": "^[a-zA-Z]{2}$", "description": "State code (exactly 2 letters)" }, "zip": { "type": "string", "pattern": "^[0-9 -]{5,}$", "description": "ZIP code (at least 5 digits)" }, "county": { "type": "string", "pattern": "^[a-zA-Z. ]{2,}$", "description": "County name (letters, periods and spaces only, min 2 chars)" }, "phone_day": { "type": "string", "pattern": "^[0-9 -]{12,}$", "description": "Day phone (at least 12 digits/characters)" }, "phone_eve": { "type": "string", "pattern": "^[0-9 -]*$", "description": "Evening phone (numbers, spaces and hyphens only)" }, "phone_mbl": { "type": "string", "pattern": "^[0-9 -]*$", "description": "Mobile phone (numbers, spaces and hyphens only)" }, "email": { "type": "string", "format": "email", "description": "Email address" } } }, "service": { "type": "object", "properties": { "branch": { "type": "string", "enum": [ "Unknown", "Army", "Air Force", "Navy", "Marines", "Coast Guard" ], "description": "Military branch of service" }, "rank": { "type": "string", "pattern": "^[a-zA-Z0-9.,# /-]*$", "description": "Military rank (letters, numbers, basic punctuation)" }, "dates": { "type": "string" }, "activity": { "type": "string" } } }, "flight": { "type": "object", "properties": { "id": { "type": "string", "default": "None", "description": "Flight ID. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "flight" } }, "status": { "type": "string", "enum": [ "All", "Active", "Flown", "Deceased", "Removed", "Future-Spring", "Future-Fall", "Future-PostRestriction" ], "default": "Active", "description": "Current flight status. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "status" } }, "group": { "type": "string", "description": "Flight group. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "group" } }, "bus": { "type": "string", "default": "None", "enum": [ "None", "Alpha1", "Alpha2", "Alpha3", "Alpha4", "Alpha5", "Bravo1", "Bravo2", "Bravo3", "Bravo4", "Bravo5" ], "description": "Assigned bus. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "bus" } }, "seat": { "type": "string", "description": "Assigned seat. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "seat" } }, "confirmed_date": { "type": "string", "description": "Date the flight was confirmed. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "confirmed date" } }, "confirmed_by": { "type": "string", "description": "Person who confirmed the flight" }, "status_note": { "type": "string", "description": "Notes about flight status" }, "waiver": { "type": "boolean", "default": false, "description": "Indicates liability waiver is received. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "flight waiver received" } }, "mediaWaiver": { "type": "boolean", "default": false, "description": "Indicates media waiver is received. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "media waiver received" } }, "vaccinated": { "type": "boolean", "default": false, "description": "Indicates veteran is vaccinated. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "vaccinated" } }, "infection_test": { "type": "boolean", "default": false, "description": "Indicates infection test is completed. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "infection test" } }, "nofly": { "type": "boolean", "default": false, "description": "Indicates veteran is not flying. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "flight nofly" } }, "history": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "format": "date-time", "description": "Timestamp of the change" }, "change": { "type": "string", "description": "Description of what changed" } } }, "description": "History of changes to flight-related fields. Records changes to: flight.id, flight.bus, flight.status, flight.seat, flight.confirmed_date, flight.group, flight.waiver, flight.mediaWaiver, flight.vaccinated, flight.infection_test, flight.nofly, medical.release, medical.form.\n" } } }, "medical": { "type": "object", "properties": { "form": { "type": "boolean", "default": false, "description": "Indicates medical form is received. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "medical form received" } }, "release": { "type": "boolean", "default": false, "description": "Indicates medical release is received. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "medical release received" } }, "level": { "type": "string", "enum": [ "1", "2", "3", "3.5", "4" ], "description": "Medical level" }, "limitations": { "type": "string" }, "food_restriction": { "type": "string", "enum": [ "None", "Gluten Free", "Vegetarian", "Vegan" ], "default": "None", "description": "Dietary restrictions" }, "usesCane": { "type": "boolean", "default": false }, "usesWalker": { "type": "boolean", "default": false }, "usesWheelchair": { "type": "boolean", "default": false }, "usesScooter": { "type": "boolean", "default": false }, "requiresOxygen": { "type": "boolean", "default": false }, "isWheelchairBound": { "type": "boolean", "default": false }, "alt_level": { "type": "string", "enum": [ "1", "2", "3", "3.5", "4" ], "description": "Alternative medical level" }, "examRequired": { "type": "boolean", "default": false }, "review": { "type": "string" } } }, "guardian": { "type": "object", "properties": { "id": { "type": "string", "description": "Paired guardian ID" }, "name": { "type": "string", "description": "Paired guardian name" }, "pref_notes": { "type": "string", "description": "Guardian preference notes" }, "history": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "format": "date-time", "description": "Timestamp of the change" }, "change": { "type": "string", "description": "Description of what changed" } } }, "description": "History of guardian pairing changes. Records pairing events: \"paired to: {guardianName} by: {userName}\" and \"unpaired from: {guardianName} by: {userName}\".\n" } } }, "app_date": { "type": "string" }, "vet_type": { "type": "string", "default": "WWII", "enum": [ "WWII", "Korea", "Vietnam", "Afghanistan", "Iraq", "Other" ], "description": "Type of veteran/war conflict served" }, "shirt": { "type": "object", "properties": { "size": { "type": "string", "default": "None", "enum": [ "None", "S", "M", "L", "XL", "2XL", "3XL", "4XL", "5XL" ] } } }, "metadata": { "type": "object", "properties": { "created_at": { "type": "string", "format": "date-time" }, "created_by": { "type": "string" }, "updated_at": { "type": "string", "format": "date-time" }, "updated_by": { "type": "string" } } }, "weight": { "type": "string", "pattern": "^\\d{1,3}$", "description": "Weight in pounds (1-999) (Obsolete)" }, "alt_contact": { "type": "object", "properties": { "name": { "type": "string", "pattern": "^[a-zA-Z'. -]{2,}$", "description": "Alternate contact name" }, "relation": { "type": "string" }, "address": { "type": "object", "properties": { "street": { "type": "string", "pattern": "^[a-zA-Z0-9.,# /-]{2,}$", "description": "Street address (letters, numbers, basic punctuation, min 2 chars)" }, "city": { "type": "string", "pattern": "^[a-zA-Z. -]{2,}$", "description": "City name (letters, periods, hyphens and spaces only, min 2 chars)" }, "state": { "type": "string", "pattern": "^[a-zA-Z]{2}$", "description": "State code (exactly 2 letters)" }, "zip": { "type": "string", "pattern": "^[0-9 -]{5,}$", "description": "ZIP code (at least 5 digits)" }, "county": { "type": "string", "pattern": "^[a-zA-Z. ]{2,}$", "description": "County name (letters, periods and spaces only, min 2 chars)" }, "phone_day": { "type": "string", "pattern": "^[0-9 -]{12,}$", "description": "Day phone (at least 12 digits/characters)" }, "phone_eve": { "type": "string", "pattern": "^[0-9 -]*$", "description": "Evening phone (numbers, spaces and hyphens only)" }, "phone_mbl": { "type": "string", "pattern": "^[0-9 -]*$", "description": "Mobile phone (numbers, spaces and hyphens only)" }, "email": { "type": "string", "format": "email", "description": "Email address" } } } } }, "emerg_contact": { "type": "object", "properties": { "name": { "type": "string", "pattern": "^[a-zA-Z'. -]{2,}$", "description": "Emergency contact name" }, "relation": { "type": "string" }, "address": { "type": "object", "properties": { "street": { "type": "string", "pattern": "^[a-zA-Z0-9.,# /-]{2,}$", "description": "Street address (letters, numbers, basic punctuation, min 2 chars)" }, "city": { "type": "string", "pattern": "^[a-zA-Z. -]{2,}$", "description": "City name (letters, periods, hyphens and spaces only, min 2 chars)" }, "state": { "type": "string", "pattern": "^[a-zA-Z]{2}$", "description": "State code (exactly 2 letters)" }, "zip": { "type": "string", "pattern": "^[0-9 -]{5,}$", "description": "ZIP code (at least 5 digits)" }, "county": { "type": "string", "pattern": "^[a-zA-Z. ]{2,}$", "description": "County name (letters, periods and spaces only, min 2 chars)" }, "phone_day": { "type": "string", "pattern": "^[0-9 -]{12,}$", "description": "Day phone (at least 12 digits/characters)" }, "phone_eve": { "type": "string", "pattern": "^[0-9 -]*$", "description": "Evening phone (numbers, spaces and hyphens only)" }, "phone_mbl": { "type": "string", "pattern": "^[0-9 -]*$", "description": "Mobile phone (numbers, spaces and hyphens only)" }, "email": { "type": "string", "format": "email", "description": "Email address" } } } } }, "mail_call": { "type": "object", "properties": { "received": { "type": "string", "description": "Date mail call was received. Changes are recorded in call.history.", "x-historyTracked": { "historyArray": "call.history", "displayName": "mail call received" } }, "name": { "type": "string", "pattern": "^[a-zA-Z'. -]{2,}$", "description": "Mail call contact name" }, "notes": { "type": "string", "description": "Mail call notes" }, "adopt": { "type": "string", "description": "Mail call adopt status. Changes are recorded in call.history.", "x-historyTracked": { "historyArray": "call.history", "displayName": "mail call adopt" } }, "relation": { "type": "string", "description": "Relation to veteran" }, "address": { "type": "object", "properties": { "phone": { "type": "string", "pattern": "^[0-9 -]{12,}$", "description": "Mail call phone" }, "email": { "type": "string", "format": "email", "description": "Mail call email" } } } } }, "media_interview_ok": { "type": "string", "enum": [ "Yes", "No", "Unknown" ], "default": "Unknown" }, "media_newspaper_ok": { "type": "string", "enum": [ "Yes", "No", "Unknown" ], "default": "Unknown" }, "apparel": { "type": "object", "properties": { "item": { "type": "string", "enum": [ "None", "Jacket", "Polo", "Both" ], "default": "None", "description": "Type of apparel items ordered" }, "jacket_size": { "type": "string", "default": "None", "enum": [ "None", "XS", "S", "M", "L", "XL", "2XL", "3XL", "4XL", "5XL" ] }, "shirt_size": { "type": "string", "default": "None", "enum": [ "None", "WXS", "WS", "WM", "WL", "WXL", "W2XL", "W3XL", "W4XL", "W5XL", "XS", "S", "M", "L", "XL", "2XL", "3XL", "4XL", "5XL" ] }, "delivery": { "type": "string", "default": "None", "enum": [ "None", "Mailed", "Pickup", "Delivered" ] }, "notes": { "type": "string" }, "date": { "type": "string" }, "by": { "type": "string" } } }, "call": { "type": "object", "properties": { "fm_number": { "type": "string", "description": "Family Member number (obsolete). Changes are recorded in call.history.", "x-historyTracked": { "historyArray": "call.history", "displayName": "FM #" } }, "notes": { "type": "string", "description": "Call notes" }, "email_sent": { "type": "boolean", "default": false, "description": "Whether email has been sent. Changes are recorded in call.history.", "x-historyTracked": { "historyArray": "call.history", "displayName": "mail call email sent" } }, "assigned_to": { "type": "string", "description": "VET member assigned to call. Changes are recorded in call.history.", "x-historyTracked": { "historyArray": "call.history", "displayName": "assigned caller" } }, "how_heard_about": { "type": "string", "default": "Unknown", "enum": [ "Unknown", "VA or vet org", "radio segment", "tv interview or segment", "school or community event", "an SSHF event or fundraiser", "newspaper or magazine ad or story", "social media", "family or friend", "airport signage or experience", "Kwik Trip Pump ad", "other" ], "description": "How the veteran heard about the program. Changes are recorded in call.history.", "x-historyTracked": { "historyArray": "call.history", "displayName": "how heard about" } }, "mail_sent": { "type": "boolean", "default": false, "description": "Whether mail has been sent. Changes are recorded in call.history.", "x-historyTracked": { "historyArray": "call.history", "displayName": "veteran mail sent" } }, "history": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "format": "date-time", "description": "Timestamp of the change" }, "change": { "type": "string", "description": "Description of what changed" } } }, "description": "History of changes to call-related fields. Records changes to: call.assigned_to, call.fm_number, call.how_heard_about, call.mail_sent, call.email_sent, mail_call.received, mail_call.adopt.\n" } } }, "homecoming": { "type": "object", "properties": { "destination": { "type": "string", "description": "Homecoming destination" } } } } }, "Guardian": { "type": "object", "required": [ "name", "type", "address" ], "properties": { "_id": { "type": "string", "description": "Document ID" }, "_rev": { "type": "string", "description": "Document revision" }, "type": { "type": "string", "enum": [ "Guardian" ], "description": "Document type, must be \"Guardian\"" }, "name": { "type": "object", "required": [ "first", "last" ], "properties": { "first": { "type": "string", "pattern": "^[a-zA-Z'. ]{2,}$", "description": "First name (letters, periods, apostrophes and spaces only, min 2 chars)" }, "middle": { "type": "string", "pattern": "^[a-zA-Z' ]*$", "description": "Middle name (letters, apostrophes and spaces only)" }, "last": { "type": "string", "pattern": "^[a-zA-Z'. -]{2,}$", "description": "Last name (letters, periods, apostrophes, hyphens and spaces only, min 2 chars)" }, "nickname": { "type": "string", "pattern": "^[a-zA-Z'. ]*$", "description": "Nickname (letters, periods, apostrophes and spaces only)" } } }, "birth_date": { "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$", "description": "Birth date in YYYY-MM-DD format" }, "gender": { "type": "string", "enum": [ "M", "F" ], "default": "M", "description": "Guardian gender" }, "address": { "type": "object", "required": [ "street", "city", "state", "zip", "county", "phone_day" ], "properties": { "street": { "type": "string", "pattern": "^[a-zA-Z0-9.,# /-]{2,}$", "description": "Street address (letters, numbers, basic punctuation, min 2 chars)" }, "city": { "type": "string", "pattern": "^[a-zA-Z. -]{2,}$", "description": "City name (letters, periods, hyphens and spaces only, min 2 chars)" }, "state": { "type": "string", "pattern": "^[a-zA-Z]{2}$", "description": "State code (exactly 2 letters)" }, "zip": { "type": "string", "pattern": "^[0-9 -]{5,}$", "description": "ZIP code (at least 5 digits)" }, "county": { "type": "string", "pattern": "^[a-zA-Z. ]{2,}$", "description": "County name (letters, periods and spaces only, min 2 chars)" }, "phone_day": { "type": "string", "pattern": "^[0-9 -]{12,}$", "description": "Day phone (at least 12 digits/characters)" }, "phone_eve": { "type": "string", "pattern": "^[0-9 -]*$", "description": "Evening phone (numbers, spaces and hyphens only)" }, "phone_mbl": { "type": "string", "pattern": "^[0-9 -]*$", "description": "Mobile phone (numbers, spaces and hyphens only)" }, "email": { "type": "string", "format": "email", "description": "Email address" } } }, "flight": { "type": "object", "properties": { "id": { "type": "string", "default": "None", "description": "Flight ID. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "flight" } }, "status": { "type": "string", "enum": [ "Active", "Flown", "Deceased", "Removed", "Future-Spring", "Future-Fall", "Future-PostRestriction", "Copied" ], "default": "Active", "description": "Current flight status. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "status" } }, "group": { "type": "string", "description": "Flight group" }, "bus": { "type": "string", "default": "None", "enum": [ "None", "Alpha1", "Alpha2", "Alpha3", "Alpha4", "Alpha5", "Bravo1", "Bravo2", "Bravo3", "Bravo4", "Bravo5" ], "description": "Assigned bus. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "bus" } }, "seat": { "type": "string", "description": "Assigned seat. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "seat" } }, "confirmed_date": { "type": "string", "description": "Date the flight was confirmed. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "confirmed date" } }, "confirmed_by": { "type": "string", "description": "Person who confirmed the flight" }, "status_note": { "type": "string", "description": "Notes about flight status" }, "history": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "format": "date-time", "description": "Timestamp of the change" }, "change": { "type": "string", "description": "Description of what changed" } } }, "description": "History of changes to flight-related fields. Records changes to: flight.id, flight.bus, flight.status, flight.seat, flight.confirmed_date, flight.training, flight.paid, flight.training_see_doc, flight.training_complete, flight.waiver, flight.mediaWaiver, flight.vaccinated, flight.infection_test, flight.nofly, flight.exempt, flight.booksOrdered, medical.release, medical.form.\n" }, "nofly": { "type": "boolean", "default": false, "description": "Indicates guardian is not flying. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "flight nofly" } }, "vaccinated": { "type": "boolean", "default": false, "description": "Indicates guardian is vaccinated. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "vaccinated" } }, "mediaWaiver": { "type": "boolean", "default": false, "description": "Indicates media waiver is received. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "media waiver received" } }, "infection_test": { "type": "boolean", "default": false, "description": "Indicates infection test is completed. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "infection test" } }, "waiver": { "type": "boolean", "default": false, "description": "Indicates liability waiver is received. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "flight waiver received" } }, "training": { "type": "string", "enum": [ "None", "Main", "Previous", "Phone", "Web", "Make-up" ], "description": "Type of training completed. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "training" } }, "training_notes": { "type": "string", "description": "Notes about guardian training" }, "training_see_doc": { "type": "boolean", "default": false, "description": "Indicates guardian needs to see a doctor at training. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "training see doctor" } }, "training_complete": { "type": "boolean", "default": false, "description": "Indicates guardian has completed training. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "training complete" } }, "paid": { "type": "boolean", "default": false, "description": "Indicates guardian has paid. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "paid" } }, "exempt": { "type": "boolean", "default": false, "description": "Indicates guardian is exempt from payment. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "exempt" } }, "booksOrdered": { "type": "integer", "default": 0, "description": "Number of books ordered. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "books ordered" } } } }, "medical": { "type": "object", "properties": { "form": { "type": "boolean", "default": false, "description": "Indicates medical form is received. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "medical form received" } }, "release": { "type": "boolean", "default": false, "description": "Indicates medical release is received. Changes are recorded in flight.history.", "x-historyTracked": { "historyArray": "flight.history", "displayName": "medical release received" } }, "level": { "type": "string", "pattern": "^[A-D]$", "description": "Medical level (A, B, C, or D)" }, "limitations": { "type": "string", "description": "Medical limitations" }, "food_restriction": { "type": "string", "enum": [ "None", "Gluten Free", "Vegetarian", "Vegan" ], "default": "None", "description": "Dietary restrictions" }, "experience": { "type": "string", "description": "Medical experience" }, "can_push": { "type": "boolean", "default": false, "description": "Indicates guardian can push a wheelchair" }, "can_lift": { "type": "boolean", "default": false, "description": "Indicates guardian can lift 100 pounds" } } }, "veteran": { "type": "object", "properties": { "pref_notes": { "type": "string", "description": "Veteran preference notes" }, "history": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "format": "date-time", "description": "Timestamp of the change" }, "change": { "type": "string", "description": "Description of what changed" } } }, "description": "History of veteran pairing changes. Records pairing events: \"paired to: {veteranName} by: {userName}\" and \"unpaired from: {veteranName} by: {userName}\".\n" }, "pairings": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Veteran ID" }, "name": { "type": "string", "description": "Veteran name" } } }, "description": "Paired veterans" } } }, "app_date": { "type": "string", "description": "Application date" }, "shirt": { "type": "object", "properties": { "size": { "type": "string", "default": "None", "enum": [ "None", "S", "M", "L", "XL", "2XL", "3XL", "4XL", "5XL" ], "description": "Shirt size" } } }, "metadata": { "type": "object", "properties": { "created_at": { "type": "string", "format": "date-time", "description": "Creation timestamp" }, "created_by": { "type": "string", "description": "User who created the record" }, "updated_at": { "type": "string", "format": "date-time", "description": "Last update timestamp" }, "updated_by": { "type": "string", "description": "User who last updated the record" } } }, "weight": { "type": "string", "pattern": "^\\d{1,3}$", "description": "Weight in pounds (60-450)" }, "emerg_contact": { "type": "object", "properties": { "name": { "type": "string", "pattern": "^[a-zA-Z'. -]{2,}$", "description": "Emergency contact name" }, "relation": { "type": "string", "description": "Relationship to guardian" }, "address": { "type": "object", "properties": { "phone": { "type": "string", "pattern": "^[0-9 -]{12,}$", "description": "Emergency contact phone" }, "email": { "type": "string", "format": "email", "description": "Emergency contact email" } } } } }, "notes": { "type": "object", "properties": { "other": { "type": "string", "description": "Other notes" }, "service": { "type": "string", "enum": [ "Y", "N" ], "default": "N", "description": "Indicates if guardian is a veteran" } } }, "occupation": { "type": "string", "description": "Guardian occupation" }, "accommodations": { "type": "object", "properties": { "departure_time": { "type": "string", "description": "Departure time" }, "arrival_date": { "type": "string", "description": "Arrival date" }, "notes": { "type": "string", "description": "Accommodation notes" }, "departure_date": { "type": "string", "description": "Departure date" }, "arrival_flight": { "type": "string", "description": "Arrival flight information" }, "attend_banquette": { "type": "string", "description": "Banquet attendance" }, "departure_flight": { "type": "string", "description": "Departure flight information" }, "arrival_time": { "type": "string", "description": "Arrival time" }, "banquette_guest": { "type": "string", "description": "Banquet guest information" }, "room_type": { "type": "string", "enum": [ "None", "Double", "Single" ], "default": "None", "description": "Hotel room type" }, "hotel_name": { "type": "string", "description": "Hotel name" } } }, "mail_call": { "type": "object", "properties": { "received": { "type": "string", "description": "Date mail call was received" }, "name": { "type": "string", "pattern": "^[a-zA-Z'. -]{2,}$", "description": "Mail call contact name" }, "notes": { "type": "string", "description": "Mail call notes" }, "relation": { "type": "string", "description": "Relation to guardian" }, "address": { "type": "object", "properties": { "phone": { "type": "string", "pattern": "^[0-9 -]{12,}$", "description": "Mail call phone" }, "email": { "type": "string", "format": "email", "description": "Mail call email" } } } } }, "call": { "type": "object", "properties": { "fm_number": { "type": "string", "description": "Family Member number. Changes are recorded in call.history.", "x-historyTracked": { "historyArray": "call.history", "displayName": "FM #" } }, "notes": { "type": "string", "description": "Call notes" }, "email_sent": { "type": "boolean", "default": false, "description": "Indicates if email has been sent. Changes are recorded in call.history.", "x-historyTracked": { "historyArray": "call.history", "displayName": "guardian email sent" } }, "assigned_to": { "type": "string", "description": "Staff member assigned to call. Changes are recorded in call.history.", "x-historyTracked": { "historyArray": "call.history", "displayName": "assigned caller" } }, "how_heard_about": { "type": "string", "default": "Unknown", "enum": [ "Unknown", "VA or vet org", "radio segment", "tv interview or segment", "school or community event", "an SSHF event or fundraiser", "newspaper or magazine ad or story", "social media", "family or friend", "airport signage or experience", "Kwik Trip Pump ad", "other" ], "description": "How the guardian heard about the program. Changes are recorded in call.history.", "x-historyTracked": { "historyArray": "call.history", "displayName": "how heard about" } }, "mail_sent": { "type": "boolean", "default": false, "description": "Indicates if mail has been sent" }, "history": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "format": "date-time", "description": "Timestamp of the change" }, "change": { "type": "string", "description": "Description of what changed" } } }, "description": "History of changes to call-related fields. Records changes to: call.assigned_to, call.fm_number, call.how_heard_about, call.email_sent.\n" } } }, "apparel": { "type": "object", "properties": { "jacket_size": { "type": "string", "default": "None", "enum": [ "None", "XS", "S", "M", "L", "XL", "2XL", "3XL", "4XL", "5XL" ], "description": "Jacket size" }, "notes": { "type": "string", "description": "Apparel notes" }, "delivery": { "type": "string", "default": "None", "enum": [ "None", "Mailed", "Training", "Home" ], "description": "Delivery method" }, "item": { "type": "string", "default": "None", "enum": [ "None", "Jacket", "Polo", "Both" ], "description": "Apparel items" }, "shirt_size": { "type": "string", "default": "None", "enum": [ "None", "WXS", "WS", "WM", "WL", "WXL", "W2XL", "W3XL", "W4XL", "W5XL", "XS", "S", "M", "L", "XL", "2XL", "3XL", "4XL", "5XL" ], "description": "Shirt size" }, "date": { "type": "string", "description": "Date apparel was sent" }, "by": { "type": "string", "description": "Person who sent the apparel" } } } } }, "Flight": { "type": "object", "required": [ "name", "flight_date", "capacity", "type" ], "properties": { "_id": { "type": "string", "description": "Document ID" }, "_rev": { "type": "string", "description": "Document revision" }, "type": { "type": "string", "enum": [ "Flight" ], "description": "Document type, must be \"Flight\"" }, "name": { "type": "string", "minLength": 1, "description": "Flight name (required, non-empty)" }, "flight_date": { "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$", "description": "Flight date in YYYY-MM-DD format" }, "capacity": { "type": "integer", "minimum": 1, "description": "Flight capacity (required, positive integer)" }, "completed": { "type": "boolean", "default": false, "description": "Whether the flight is completed" }, "metadata": { "type": "object", "properties": { "created_at": { "type": "string", "format": "date-time", "description": "Creation timestamp" }, "created_by": { "type": "string", "description": "User who created the record" }, "updated_at": { "type": "string", "format": "date-time", "description": "Last update timestamp" }, "updated_by": { "type": "string", "description": "User who last updated the record" } } } } }, "FlightAssignment": { "type": "object", "description": "Flight assignment data including flight info, counts, and veteran-guardian pairs", "properties": { "flight": { "type": "object", "description": "Flight metadata", "properties": { "id": { "type": "string", "description": "Flight document ID" }, "rev": { "type": "string", "description": "Flight document revision" }, "name": { "type": "string", "description": "Flight name" }, "capacity": { "type": "integer", "description": "Flight capacity" }, "flight_date": { "type": "string", "format": "date", "description": "Flight date in YYYY-MM-DD format" } } }, "counts": { "type": "object", "description": "Counts of veterans, guardians, and remaining capacity", "properties": { "veterans": { "type": "integer", "description": "Number of veterans assigned (excluding nofly)" }, "guardians": { "type": "integer", "description": "Number of guardians assigned (excluding nofly)" }, "veteransConfirmed": { "type": "integer", "description": "Number of confirmed veterans" }, "guardiansConfirmed": { "type": "integer", "description": "Number of confirmed guardians" }, "remaining": { "type": "integer", "description": "Remaining capacity on the flight" } } }, "pairs": { "type": "array", "description": "List of veteran-guardian pairs", "items": { "$ref": "#/components/schemas/AssignmentPair" } } } }, "AssignmentPair": { "type": "object", "description": "A veteran-guardian pairing", "properties": { "pairId": { "type": "string", "description": "Unique identifier for the pair" }, "group": { "type": "string", "description": "Veteran group name (if any)" }, "appDate": { "type": "string", "format": "date", "description": "Application date" }, "missingPerson": { "type": "boolean", "description": "True if the pair is missing a person (veteran has paired_with but only 1 person)" }, "people": { "type": "array", "description": "List of people in the pair (veteran and/or guardian)", "items": { "$ref": "#/components/schemas/AssignmentPerson" } } } }, "AssignmentPerson": { "type": "object", "description": "An individual person (veteran or guardian) in a flight assignment", "properties": { "type": { "type": "string", "enum": [ "Veteran", "Guardian" ], "description": "Person type" }, "id": { "type": "string", "description": "Document ID" }, "name_first": { "type": "string", "description": "First name" }, "name_last": { "type": "string", "description": "Last name" }, "city": { "type": "string", "description": "City" }, "appdate": { "type": "string", "format": "date", "description": "Application date" }, "group": { "type": "string", "description": "Group name (if any)" }, "nofly": { "type": "boolean", "description": "Whether person is marked as no-fly" }, "fm_number": { "type": "string", "description": "FM number for caller assignment" }, "assigned_to": { "type": "string", "description": "Assigned caller" }, "mail_sent": { "type": "boolean", "description": "Whether mail has been sent" }, "email_sent": { "type": "boolean", "description": "Whether email has been sent" }, "confirmed": { "type": "string", "description": "Confirmation status" }, "paired_with": { "type": "string", "description": "ID of paired person" } } }, "AddVeteransResult": { "type": "object", "description": "Result of adding veterans to a flight. Returned with 200 when every save\nsucceeded, 409 when a document conflict remains after one retry, and 500\nwhen a veteran or guardian save failed for another reason. Failure\nresponses list the document ids that were saved and the ids that failed.\n", "properties": { "added": { "type": "object", "properties": { "veterans": { "type": "integer", "description": "Number of veterans added" }, "guardians": { "type": "integer", "description": "Number of guardians added" } } }, "saved": { "type": "object", "description": "Document ids saved during this request", "properties": { "veterans": { "type": "array", "items": { "type": "string" }, "description": "Veteran document ids that were saved" }, "guardians": { "type": "array", "items": { "type": "string" }, "description": "Guardian document ids that were saved" } } }, "failed": { "type": "array", "description": "Documents that were not saved, including each document id", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Document id that failed to save" }, "type": { "type": "string", "enum": [ "veteran", "guardian" ], "description": "Whether the failed document is a veteran or a guardian" }, "status": { "type": "integer", "description": "Status for this document. 409 is a conflict that remained after one revision retry." }, "error": { "type": "string", "description": "Error message for this document" } } } }, "errors": { "type": "array", "items": { "type": "string" }, "description": "Error messages for documents that failed to save, in the same order as failed" } } }, "UnpairedVeteranResult": { "type": "object", "properties": { "name": { "type": "string", "description": "Full name of the veteran (first + last)" }, "city": { "type": "string", "description": "City and state of residence (city, state)" }, "flight": { "type": "string", "description": "Flight ID assignment" }, "prefs": { "type": "string", "description": "Guardian preference notes" } } }, "UnpairedVeteranResults": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Document ID" }, "name": { "type": "string", "description": "Full name of the veteran (first + last)" }, "city": { "type": "string", "description": "City and state of residence (city, state)" }, "flight": { "type": "string", "description": "Flight ID assignment" }, "prefs": { "type": "string", "description": "Guardian preference notes" } } } }, "RecentActivityEntry": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier for the document" }, "type": { "type": "string", "enum": [ "Veteran", "Guardian" ], "description": "Type of applicant - either Veteran or Guardian" }, "name": { "type": "string", "description": "Name of the applicant" }, "city": { "type": "string", "description": "City and state of residence" }, "appdate": { "type": "string", "description": "Date the application was received" }, "recdate": { "type": "string", "format": "date-time", "description": "Date and time the change occurred (UTC ISO string)" }, "recby": { "type": "string", "description": "User who made the change" }, "change": { "type": "string", "description": "Short summary of the change" } }, "required": [ "id", "type", "name", "city", "appdate", "recdate", "recby", "change" ] }, "FlightDetailResult": { "type": "object", "description": "Flight detail data including flight info, statistics, and seat/bus assignments", "properties": { "flight": { "type": "object", "description": "Flight metadata", "properties": { "id": { "type": "string", "description": "Flight document ID" }, "name": { "type": "string", "description": "Flight name" }, "capacity": { "type": "integer", "description": "Flight capacity" }, "flight_date": { "type": "string", "format": "date", "description": "Flight date in YYYY-MM-DD format" } } }, "stats": { "type": "object", "description": "Statistics for the flight", "properties": { "buses": { "type": "object", "description": "Count of people per bus", "properties": { "None": { "type": "integer" }, "Alpha1": { "type": "integer" }, "Alpha2": { "type": "integer" }, "Alpha3": { "type": "integer" }, "Alpha4": { "type": "integer" }, "Alpha5": { "type": "integer" }, "Bravo1": { "type": "integer" }, "Bravo2": { "type": "integer" }, "Bravo3": { "type": "integer" }, "Bravo4": { "type": "integer" }, "Bravo5": { "type": "integer" } } }, "tours": { "type": "object", "description": "Count of people per tour (Alpha = Alpha1-5, Bravo = Bravo1-5)", "properties": { "Alpha": { "type": "integer" }, "Bravo": { "type": "integer" }, "None": { "type": "integer" } } }, "flight": { "type": "object", "description": "Count of people per tour excluding nofly entries", "properties": { "Alpha": { "type": "integer" }, "Bravo": { "type": "integer" }, "None": { "type": "integer" } } } } }, "pairs": { "type": "array", "description": "List of veteran-guardian pairs with seat/bus assignments", "items": { "$ref": "#/components/schemas/FlightDetailPair" } } } }, "FlightDetailPair": { "type": "object", "description": "A veteran-guardian pairing with mismatch detection", "properties": { "pairId": { "type": "string", "description": "Unique identifier for the pair (veteran's ID or guardian's ID if unpaired)" }, "busMismatch": { "type": "boolean", "description": "True if people in the pair have different bus assignments" }, "missingPairedPerson": { "type": "boolean", "description": "True if a paired person is not on this flight" }, "people": { "type": "array", "description": "List of people in the pair (veteran and/or guardian)", "items": { "$ref": "#/components/schemas/FlightDetailPerson" } } } }, "FlightDetailPerson": { "type": "object", "description": "An individual person (veteran or guardian) in the flight detail", "properties": { "type": { "type": "string", "enum": [ "Veteran", "Guardian" ], "description": "Person type" }, "id": { "type": "string", "description": "Document ID" }, "name_first": { "type": "string", "description": "First name" }, "name_last": { "type": "string", "description": "Last name" }, "name_middle": { "type": "string", "description": "Middle name" }, "birth_date": { "type": "string", "description": "Birth date" }, "gender": { "type": "string", "description": "Gender" }, "city": { "type": "string", "description": "City and state" }, "phone_mbl": { "type": "string", "description": "Mobile phone number" }, "bus": { "type": "string", "enum": [ "None", "Alpha1", "Alpha2", "Alpha3", "Alpha4", "Alpha5", "Bravo1", "Bravo2", "Bravo3", "Bravo4", "Bravo5" ], "description": "Bus assignment" }, "seat": { "type": "string", "description": "Seat assignment (e.g., \"14A\")" }, "shirt": { "type": "string", "description": "Shirt size" }, "fm_number": { "type": "string", "maxLength": 5, "description": "Optional family member hold for application identifier, often blank" }, "assigned_to": { "type": "string", "description": "Assigned caller or coordinator name" }, "nofly": { "type": "boolean", "description": "Whether person is marked as no-fly" }, "confirmed": { "type": "boolean", "description": "Whether person is confirmed for the flight" }, "medical_form": { "type": "boolean", "description": "Whether medical form is received" }, "medical_level": { "type": "string", "description": "Medical level" }, "flight_vaccinated": { "type": "boolean", "description": "Whether person is marked as vaccinated for flight" }, "apparel_shirt_size": { "type": "string", "description": "Apparel shirt size" }, "apparel_jacket_size": { "type": "string", "description": "Apparel jacket size" }, "apparel_notes": { "type": "string", "description": "Apparel notes" }, "med_limits": { "type": "string", "description": "Medical limitations (Veterans only)" }, "group": { "type": "string", "description": "Group name (Veterans only)" }, "med_exprnc": { "type": "string", "description": "Medical experience (Guardians only)" }, "training": { "type": "string", "description": "Training type (Guardians only), such as Main, Web, Previous, Phone,\nMake-up, or None. A trailing medical-level suffix appended by the\nCouch flight_pairings view (` [A]` through ` [D]`) is removed in this\nresponse. Medical level stays on medical_level.\n" }, "training_complete": { "type": "boolean", "description": "Whether training is complete (Guardians only)" }, "mail_call_received": { "type": "boolean", "description": "Mail call received (Veterans only)" }, "mail_call_adopt": { "type": "boolean", "description": "Mail call adopt flag (Veterans only)" }, "mail_call_notes": { "type": "string", "description": "Mail call notes (Veterans only)" }, "medical_alt_level": { "type": "string", "description": "Alternate medical level (Veterans only)" }, "medical_limitations": { "type": "string", "description": "Medical limitations detail (Veterans only)" }, "medical_review": { "type": "string", "description": "Medical review notes (Veterans only)" }, "medical_requires_oxygen": { "type": "boolean", "description": "Whether oxygen is required (Veterans only)" }, "homecoming_destination": { "type": "string", "description": "Homecoming destination (Veterans only)" }, "flight_training_notes": { "type": "string", "description": "Training notes (Guardians only)" }, "flight_waiver": { "type": "boolean", "description": "Flight waiver flag (Guardians only)" }, "flight_training_see_doc": { "type": "boolean", "description": "Training see doctor flag (Guardians only)" }, "flight_paid": { "type": "boolean", "description": "Flight paid flag (Guardians only)" }, "flight_books_ordered": { "type": "integer", "description": "Number of books ordered (Guardians only)" } } }, "WaitlistVeteranGroup": { "type": "object", "description": "Active veteran names grouped by flight group assignment", "properties": { "group": { "type": "string", "description": "Flight group identifier from the waitlist_veteran_groups view key" }, "names": { "type": "array", "description": "Veteran display names from the view values for this group", "items": { "type": "string" } } }, "required": [ "group", "names" ] }, "QueryRequest": { "type": "object", "required": [ "selector" ], "properties": { "selector": { "type": "object", "description": "MongoDB-style query selector. An empty object {} matches all documents (subject to limit).\nMust not contain mutation operators like $set, $update, etc.\n", "example": { "type": "veteran", "status": "Active" } }, "fields": { "type": "array", "items": { "type": "string" }, "description": "Array of field names to include in results. If omitted, all fields are returned.", "example": [ "_id", "name", "status", "phone" ] }, "sort": { "type": "array", "items": { "type": "object" }, "description": "Sort specification as an array of field-direction objects", "example": [ { "name": "asc" } ] }, "limit": { "type": "integer", "minimum": 1, "maximum": 100, "default": 25, "description": "Maximum number of results to return. Defaults to 25, clamped to 100." }, "bookmark": { "type": "string", "description": "Pagination bookmark from a previous query result", "example": "g1AAAAG3eJzLYWBg4M" }, "use_index": { "type": "string", "description": "Index to use for the query (design doc name or array of [design_doc, index_name])", "example": "_design/my-index" }, "execution_stats": { "type": "boolean", "description": "If true, return execution statistics with the result" } } }, "QueryResults": { "type": "object", "required": [ "docs" ], "properties": { "docs": { "type": "array", "items": { "type": "object" }, "description": "Array of documents matching the query" }, "bookmark": { "type": "string", "description": "Pagination bookmark for retrieving the next page of results" }, "warning": { "type": "string", "description": "Warning message from CouchDB (e.g., \"no matching index found\")" }, "execution_stats": { "type": "object", "description": "Query execution statistics (only present if requested)", "properties": { "total_keys_examined": { "type": "integer" }, "total_docs_examined": { "type": "integer" }, "total_quorum_docs_examined": { "type": "integer" }, "results_returned": { "type": "integer" }, "execution_time_ms": { "type": "number" } } } } }, "ReviewApplication": { "type": "object", "description": "Normalized online application stored in the review database. When `type` is `VeteranApp`, veteran-only fields (`vet_type`, `service`, `guardian`, `medical`) are present. When `type` is `GuardianApp`, the guardian-only `veteran` object is present instead.\n", "required": [ "type", "name", "address" ], "properties": { "_id": { "type": "string", "readOnly": true, "description": "Document ID" }, "_rev": { "type": "string", "readOnly": true, "description": "Document revision" }, "type": { "type": "string", "enum": [ "VeteranApp", "GuardianApp" ], "description": "Application type" }, "app_status": { "type": "string", "enum": [ "New", "Hold", "Accepted", "Rejected", "Trash" ], "default": "New", "description": "Review workflow status" }, "app_status_note": { "type": "string", "description": "Optional note about the current status" }, "date_time": { "type": "string", "readOnly": true, "description": "Submission timestamp from the online form" }, "app_date": { "type": "string", "readOnly": true, "description": "Application date derived from date_time (YYYY-MM-DD)" }, "ip_address": { "type": "string", "readOnly": true, "description": "Submitter IP address" }, "accepted_as_rev": { "type": "string", "readOnly": true, "description": "Logistics database _rev when the application was last accepted" }, "name": { "type": "object", "required": [ "first", "last" ], "properties": { "first": { "type": "string", "description": "First name" }, "middle": { "type": "string", "description": "Middle name" }, "last": { "type": "string", "description": "Last name" }, "nickname": { "type": "string", "description": "Nickname" } } }, "address": { "type": "object", "properties": { "street": { "type": "string" }, "city": { "type": "string" }, "county": { "type": "string" }, "state": { "type": "string", "description": "Two-letter state code (upper-cased on intake)" }, "zip": { "type": "string" }, "phone_day": { "type": "string", "description": "Primary/day phone" }, "phone_mbl": { "type": "string", "description": "Mobile phone" }, "email": { "type": "string", "format": "email" } } }, "birth_date": { "type": "string", "format": "date", "description": "Birth date (YYYY-MM-DD)" }, "gender": { "type": "string", "enum": [ "M", "F" ], "default": "M", "description": "Gender" }, "shirt": { "type": "object", "properties": { "size": { "type": "string", "default": "None", "description": "Shirt size from the online form" } } }, "emerg_contact": { "type": "object", "properties": { "name": { "type": "string", "description": "Emergency contact name" }, "address": { "type": "object", "properties": { "phone": { "type": "string" }, "email": { "type": "string", "format": "email" } } } } }, "metadata": { "type": "object", "readOnly": true, "properties": { "created_at": { "type": "string", "format": "date-time" }, "created_by": { "type": "string" }, "updated_at": { "type": "string", "format": "date-time" }, "updated_by": { "type": "string" } } }, "vet_type": { "type": "string", "enum": [ "WWII", "Korea", "Vietnam", "Afghanistan", "Iraq", "Other" ], "default": "WWII", "description": "War/conflict served (VeteranApp only)" }, "service": { "type": "object", "description": "Military service details (VeteranApp only)", "properties": { "branch": { "type": "string", "enum": [ "", "Unknown", "Army", "Air Force", "Navy", "Marines", "Coast Guard" ], "description": "Branch of service" }, "dates": { "type": "string", "description": "Service dates" }, "rank": { "type": "string", "description": "Rank at discharge" } } }, "guardian": { "type": "object", "description": "Preferred guardian contact (VeteranApp only)", "properties": { "pref_notes": { "type": "string", "description": "Guardian preference notes" }, "pref_phone": { "type": "string", "description": "Preferred guardian phone" }, "pref_email": { "type": "string", "format": "email", "description": "Preferred guardian email" } } }, "medical": { "type": "object", "description": "Medical mobility needs (VeteranApp only)", "properties": { "usesWheelchair": { "type": "boolean", "default": false }, "requiresOxygen": { "type": "boolean", "default": false } } }, "veteran": { "type": "object", "description": "Veteran the guardian wishes to accompany (GuardianApp only)", "properties": { "pref_notes": { "type": "string", "description": "Veteran preference notes" } } } }, "example": { "_id": "a1b2c3", "_rev": "3-xyz", "type": "VeteranApp", "app_status": "New", "app_status_note": "", "date_time": "2024-03-05 14:22:01", "app_date": "2024-03-05", "ip_address": "203.0.113.9", "accepted_as_rev": "", "name": { "first": "John", "middle": "Q", "last": "Public", "nickname": "Jack" }, "address": { "street": "123 Main St", "city": "Madison", "county": "Dane", "state": "WI", "zip": "53703", "phone_day": "608-555-1234", "phone_mbl": "608-555-5678", "email": "john@example.com" }, "birth_date": "1948-05-17", "gender": "M", "shirt": { "size": "XL" }, "emerg_contact": { "name": "Jane Public", "address": { "phone": "608-555-9999", "email": "jane@example.com" } }, "metadata": { "created_at": "2024-03-05T14:22:01Z", "created_by": "Online App", "updated_at": "2024-03-05T14:22:01Z", "updated_by": "Online App" }, "vet_type": "Vietnam", "service": { "branch": "Army", "dates": "1966-1968", "rank": "SGT" }, "guardian": { "pref_notes": "Son Bob", "pref_phone": "608-555-0000", "pref_email": "bob@example.com" }, "medical": { "usesWheelchair": true, "requiresOxygen": false } } }, "ReviewApplicationIntake": { "type": "object", "description": "Raw legacy form payload accepted by POST /review/applications. Field names match the online application form. Additional unknown keys are preserved in the stored CouchDB document. The keys `cburi`, `cbusr`, `cbpwd`, and `full_message` are stripped on intake and never stored.\n", "additionalProperties": true, "required": [ "type", "First-Name", "Last-Name" ], "properties": { "type": { "type": "string", "enum": [ "VeteranApp", "GuardianApp" ], "description": "Application type" }, "date_time": { "type": "string", "description": "Submission timestamp (defaults to now if omitted)" }, "ip_address": { "type": "string", "description": "Submitter IP address" }, "First-Name": { "type": "string", "description": "First name" }, "Middle-Name": { "type": "string", "description": "Middle name" }, "Last-Name": { "type": "string", "description": "Last name" }, "Nickname": { "type": "string", "description": "Nickname" }, "Street": { "type": "string", "description": "Street address" }, "City": { "type": "string", "description": "City" }, "County": { "type": "string", "description": "County" }, "State": { "type": "string", "description": "State (two-letter code; upper-cased on storage)" }, "Zip": { "type": "string", "description": "ZIP code" }, "Primary-Phone": { "type": "string", "description": "Primary/day phone" }, "Mobile-Phone": { "type": "string", "description": "Mobile phone" }, "from_email": { "type": "string", "description": "Email address" }, "Date-Of-Birth": { "type": "string", "description": "Birth date (MM/DD/YYYY)" }, "Gender": { "type": "string", "enum": [ "Male", "Female" ], "description": "Gender" }, "Shirt-Size": { "type": "string", "description": "Shirt size" }, "Conflict": { "type": "string", "description": "War/conflict served (VeteranApp only; maps to vet_type)" }, "Branch-of-Service": { "type": "string", "description": "Military branch (VeteranApp only)" }, "Service-Dates": { "type": "string", "description": "Service dates (VeteranApp only)" }, "Rank": { "type": "string", "description": "Rank at discharge (VeteranApp only)" }, "Emergency-Contact-Name": { "type": "string", "description": "Emergency contact name" }, "Emergency-Contact-Phone": { "type": "string", "description": "Emergency contact phone" }, "Emergency-Contact-Email": { "type": "string", "description": "Emergency contact email" }, "medical-wheelchair": { "type": "string", "enum": [ "Yes", "No" ], "description": "Uses wheelchair (VeteranApp only)" }, "medical-oxygen": { "type": "string", "enum": [ "Yes", "No" ], "description": "Requires oxygen (VeteranApp only)" }, "Guardian-Preference": { "type": "string", "description": "Preferred guardian notes (VeteranApp only)" }, "Preferred-Guardian-Phone-Number": { "type": "string", "description": "Preferred guardian phone (VeteranApp only)" }, "Preferred-Guardian-Email": { "type": "string", "description": "Preferred guardian email (VeteranApp only)" }, "Veteran-Preference": { "type": "string", "description": "Veteran preference notes (GuardianApp only)" } }, "example": { "type": "VeteranApp", "date_time": "2024-03-05 14:22:01", "ip_address": "203.0.113.9", "First-Name": "John", "Middle-Name": "Q", "Last-Name": "Public", "Nickname": "Jack", "Street": "123 Main St", "City": "Madison", "County": "Dane", "State": "wi", "Zip": "53703", "Primary-Phone": "(608) 555-1234", "Mobile-Phone": "6085555678", "from_email": "john@example.com", "Date-Of-Birth": "05/17/1948", "Gender": "Male", "Shirt-Size": "XL", "Conflict": "Vietnam", "Branch-of-Service": "Army", "Service-Dates": "1966-1968", "Rank": "SGT", "Emergency-Contact-Name": "Jane Public", "Emergency-Contact-Phone": "608-555-9999", "Emergency-Contact-Email": "jane@example.com", "medical-wheelchair": "Yes", "medical-oxygen": "No", "Guardian-Preference": "Son Bob", "Preferred-Guardian-Phone-Number": "6085550000", "Preferred-Guardian-Email": "bob@example.com", "app_status": "New", "app_status_note": "", "full_message": "raw text" } }, "ReviewApplicationSummary": { "type": "object", "properties": { "id": { "type": "string", "description": "Document ID" }, "type": { "type": "string", "enum": [ "VeteranApp", "GuardianApp" ], "description": "Application type" }, "name": { "type": "string", "description": "Applicant display name" }, "city": { "type": "string", "description": "City of residence" }, "app_date": { "type": "string", "description": "Application date (YYYY-MM-DD)" }, "app_status": { "type": "string", "enum": [ "New", "Hold", "Accepted", "Rejected", "Trash" ], "description": "Review workflow status" }, "pairing": { "type": "string", "description": "Pairing information from the review view" }, "email": { "type": "string", "description": "Applicant email address" }, "ip_address": { "type": "string", "description": "Submitter IP address" } } }, "ReviewApplicationList": { "type": "object", "properties": { "total_rows": { "type": "integer", "description": "Total number of rows in the result set" }, "offset": { "type": "integer", "description": "Starting offset of the result set" }, "rows": { "type": "array", "items": { "$ref": "#/components/schemas/ReviewApplicationSummary" } } } }, "ReviewApplicationStatusUpdate": { "type": "object", "required": [ "app_status" ], "properties": { "app_status": { "type": "string", "enum": [ "New", "Hold", "Rejected", "Trash" ], "description": "New review status. Accepted is not allowed here; use POST /review/applications/:id/accept instead (returns 400 if Accepted is sent).\n" }, "app_status_note": { "type": "string", "description": "Optional note about the status change" } } }, "ReviewApplicationAcceptResult": { "type": "object", "description": "Result of accepting an application. The applicant is copied into the logistics database under the same `_id`. `accepted_as_rev` on the review application records the logistics document revision at accept time. If the logistics document has changed since that revision, a subsequent accept returns 409 Conflict without modifying the review document.\n", "properties": { "application": { "$ref": "#/components/schemas/ReviewApplication", "description": "Updated review application with app_status Accepted" }, "record": { "oneOf": [ { "$ref": "#/components/schemas/Veteran" }, { "$ref": "#/components/schemas/Guardian" } ], "description": "Veteran or Guardian record written to the logistics database" } } }, "DocRevision": { "type": "object", "required": [ "rev", "status" ], "properties": { "rev": { "type": "string", "description": "Full CouchDB revision token", "example": "5-aaa111aaa111aaa111aaa111aaa111aa" }, "status": { "type": "string", "enum": [ "available", "missing", "deleted" ], "description": "Whether the revision body can still be retrieved" } } }, "DocRevisionList": { "type": "object", "required": [ "id", "currentRev", "revisions", "availableCount" ], "properties": { "id": { "type": "string", "description": "CouchDB document ID" }, "currentRev": { "type": "string", "description": "Winning current revision token" }, "revisions": { "type": "array", "description": "Revision history newest first, including compacted entries", "items": { "$ref": "#/components/schemas/DocRevision" } }, "availableCount": { "type": "integer", "description": "Number of revisions whose bodies are still stored" }, "warning": { "type": "string", "description": "Present when older revisions were removed by compaction", "example": "Older revisions were removed by database compaction." } } }, "DocDiffChange": { "type": "object", "required": [ "path", "op" ], "properties": { "path": { "type": "string", "description": "Dotted object path with array indexes in brackets", "example": "name.first" }, "op": { "type": "string", "enum": [ "add", "remove", "replace" ] }, "from": { "description": "Previous value for replace and remove operations" }, "to": { "description": "New value for replace and add operations" } } }, "DocDiff": { "type": "object", "required": [ "id", "from", "to", "changes", "fromDoc", "toDoc" ], "properties": { "id": { "type": "string", "description": "CouchDB document ID" }, "from": { "$ref": "#/components/schemas/DocRevision" }, "to": { "$ref": "#/components/schemas/DocRevision" }, "changes": { "type": "array", "items": { "$ref": "#/components/schemas/DocDiffChange" } }, "fromDoc": { "type": "object", "description": "Raw older document snapshot" }, "toDoc": { "type": "object", "description": "Raw newer document snapshot" }, "warning": { "type": "string", "description": "Present when older revisions were removed by compaction", "example": "Older revisions were removed by database compaction." } } }, "GenericDocumentWrite": { "type": "object", "description": "Logistics document written through POST /docs or PUT /docs/{id}. type must be Flight, Guardian, or Veteran. The stored document is built with that type's model, so the same field validation applies as on the typed routes. _id is required and must not refer to a design or system document. On update, _id must match the URL id and the type must match the stored document. Client-supplied _rev, _deleted, other underscore fields, design-document fields, and audit metadata are ignored. Creation metadata and history are preserved on update. updated_by and updated_at are set from the authenticated user. A new flight is stored with completed false. Update uses the revision currently stored in CouchDB.\n", "required": [ "_id", "type" ], "properties": { "_id": { "type": "string", "description": "CouchDB document id. Rejected when empty, when it starts with an underscore (design or system documents), when it contains a slash or backslash, or when it is the dot-dot path segment.\n" }, "type": { "type": "string", "enum": [ "Flight", "Guardian", "Veteran" ], "description": "Allowlisted logistics document type." } }, "additionalProperties": true }, "UserPermissions": { "type": "object", "required": [ "email", "hasAccess", "roles", "permissions", "evaluatedAt", "expiresAt" ], "properties": { "email": { "type": "string", "description": "Authenticated account, for display and support" }, "hasAccess": { "type": "boolean", "description": "True when permissions is non-empty" }, "roles": { "type": "array", "description": "Role ids granted directly by group membership. Inherited roles are not listed.", "items": { "type": "string", "enum": [ "READ", "WRITE", "FULL", "MEDICAL", "REVIEW" ] } }, "permissions": { "type": "array", "description": "Effective permission union, including permissions inherited from WRITE and FULL", "items": { "type": "string", "enum": [ "applications:accept", "applications:review", "documents:admin", "exports:read", "flights:manage", "medical:read", "medical:write", "records:delete", "records:read", "records:write" ] } }, "evaluatedAt": { "type": "string", "format": "date-time", "description": "When membership was resolved (cache fill time)" }, "expiresAt": { "type": "string", "format": "date-time", "description": "When the server-side cache entry expires" } } }, "FlightStatusBulkResult": { "type": "object", "description": "Result of a flight status bulk update. Returned with 200 when every attempted\nsave succeeded and 207 when one or more did not. counts.failed counts people\nonly. A failed flight save is listed in failed with type flight and does not\nincrement counts.failed. assignedToFlight is present only for\nPOST /flights/future-status/activate.\n", "properties": { "fromStatus": { "type": "string", "description": "Status people were changed from" }, "toStatus": { "type": "string", "description": "Status people were changed to" }, "flight": { "type": "object", "description": "Present for POST /flights/{id}/complete. completed is the stored value after the request.", "properties": { "id": { "type": "string", "description": "Flight document id" }, "name": { "type": "string", "description": "Flight name stored on person flight.id" }, "completed": { "description": "Stored completed value after the request" } } }, "counts": { "type": "object", "properties": { "matched": { "type": "integer", "description": "People returned by the view who matched the endpoint filter" }, "changed": { "type": "integer", "description": "People saved with toStatus in this request" }, "skipped": { "type": "integer", "description": "Matched people who were not changed because they did not qualify" }, "failed": { "type": "integer", "description": "People who qualified but could not be saved" } } }, "failed": { "type": "array", "description": "Documents that were not saved, including each document id", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Document id that failed to save" }, "type": { "type": "string", "enum": [ "veteran", "guardian", "flight" ], "description": "Whether the failed document is a veteran, a guardian, or the flight" }, "status": { "type": "integer", "description": "Status for this document. 409 is a conflict that remained after one revision retry." }, "error": { "type": "string", "description": "Stable error message for this document" } } } }, "assignedToFlight": { "type": "array", "description": "POST /flights/future-status/activate only. Ids of matched people whose\nflight.id was present and not \"None\" when they were read. The list is\ninformational and does not change 200 versus 207.\n", "items": { "type": "string" } } } }, "FutureStatusActivateRequest": { "type": "object", "required": [ "status" ], "properties": { "status": { "type": "string", "pattern": "^Future-.+", "description": "Any flight status that begins with Future-" } } } } }, "security": [ { "GoogleAuth": [ "openid", "email", "profile" ] } ], "paths": { "/docs": { "post": { "summary": "Create an allowlisted logistics document", "description": "Stores a new CouchDB document whose type is Flight, Guardian, or Veteran.\nThe body is validated with that type's model. The body `_id` is required\nand must not refer to a design or system document. Client-supplied\n`_rev`, `_deleted`, design-document fields, and audit metadata are not\nstored. Creation and update metadata are set from the authenticated user.\nA new flight is stored with completed false.\n", "tags": [ "Documents" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "documents:admin", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GenericDocumentWrite" } } } }, "responses": { "201": { "description": "Document created successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "id": { "type": "string" }, "rev": { "type": "string" } } } } } }, "400": { "description": "Invalid document id, missing _id, a design or system document id, a type that is not allowlisted, or data that fails Flight, Guardian, or Veteran validation", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "409": { "description": "Document update conflict", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } }, "500": { "description": "Server error" }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } } }, "/docs/{id}": { "get": { "summary": "Retrieve a CouchDB document by ID", "tags": [ "Documents" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:read", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "CouchDB document ID" } ], "responses": { "200": { "description": "Document retrieved successfully", "content": { "application/json": { "schema": { "type": "object" } } } }, "400": { "description": "Invalid document id" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Document not found" }, "500": { "description": "Server error" }, "503": { "description": "Database session error" } } }, "put": { "summary": "Update an allowlisted logistics document by ID", "description": "Replaces a Flight, Guardian, or Veteran document using that type's model\nvalidation. The body `_id` is required and must match the URL id.\nDesign or system document ids are rejected. The stored type cannot be\nchanged, and a document whose stored type is not allowlisted cannot be\nreplaced. Creation metadata and history stay as stored. The\nauthenticated user is recorded as the updater. Client-supplied `_rev`,\n`_deleted`, design-document fields, and audit metadata are not stored;\nthe current CouchDB revision is sent instead.\n", "tags": [ "Documents" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "documents:admin", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "CouchDB document ID" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GenericDocumentWrite" } } } }, "responses": { "200": { "description": "Document updated successfully", "content": { "application/json": { "schema": { "type": "object" } } } }, "400": { "description": "Invalid document id, missing _id, a body _id that does not match the URL id, a design or system document id, a type that is not allowlisted, a type that does not match the stored document type, stored document type is not allowed, or data that fails Flight, Guardian, or Veteran validation" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Document not found" }, "409": { "description": "Document update conflict" }, "500": { "description": "Server error" }, "503": { "description": "Database session error" } } }, "delete": { "summary": "Delete an allowlisted logistics document by ID", "description": "Deletes a document only when its stored type is Flight, Guardian, or\nVeteran. Design or system document ids are rejected before CouchDB is\ncalled.\n", "tags": [ "Documents" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "documents:admin", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "CouchDB document ID" } ], "responses": { "200": { "description": "Document deleted successfully", "content": { "application/json": { "schema": { "type": "object" } } } }, "400": { "description": "Invalid document id, or stored document type is not allowed" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Document not found" }, "409": { "description": "Document update conflict" }, "500": { "description": "Server error" }, "503": { "description": "Database session error" } } } }, "/docs/{id}/revisions": { "get": { "summary": "List a document's CouchDB revision history", "description": "Returns revision metadata for a document using CouchDB `revs_info=true`.\nRevisions marked `missing` were removed by database compaction and cannot\nbe fetched or diffed. This endpoint is intended for testers and debugging.\n", "tags": [ "Documents" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:read", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "CouchDB document ID" } ], "responses": { "200": { "description": "Revision history retrieved successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DocRevisionList" } } } }, "400": { "description": "Invalid document id", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Document not found", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } }, "example": { "error": "Document not found" } } } }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } } }, "/docs/{id}/diff": { "get": { "summary": "Diff two revisions of a CouchDB document", "description": "Fetches two revision snapshots and returns a field-level JSON diff.\nWhen `from` and `to` are omitted, the current winning revision is\ncompared with the next most recent available revision. Aliases\n`current` and `previous` are accepted. Compacted revisions cannot be\nretrieved and return 404. Intended for testers and debugging.\n", "tags": [ "Documents" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:read", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "CouchDB document ID" }, { "in": "query", "name": "from", "schema": { "type": "string" }, "description": "Older revision token, or `previous` (the default)" }, { "in": "query", "name": "to", "schema": { "type": "string" }, "description": "Newer revision token, or `current` (the default)" } ], "responses": { "200": { "description": "Diff computed successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DocDiff" } } } }, "400": { "description": "Invalid document id, invalid revision parameters, or no previous revision", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Document or requested revision not found", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } } }, "/exports/flight": { "get": { "summary": "Export flight roster data as CSV", "description": "Proxies the CouchDB `flight-csv` list export and returns a CSV file.\nThis export accepts a flight name and an optional role filter.\nThe response is served as a downloadable CSV attachment.\n", "tags": [ "Exports" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "exports:read", "parameters": [ { "in": "query", "name": "flightName", "required": false, "schema": { "type": "string" }, "description": "Flight name to export." }, { "in": "query", "name": "filter", "required": false, "schema": { "type": "string", "enum": [ "All", "Veterans", "Guardians" ], "default": "All" }, "description": "Optional role-based filter for the flight export." } ], "responses": { "200": { "description": "CSV export generated successfully", "content": { "text/csv": { "schema": { "type": "string", "format": "binary" } } } }, "400": { "description": "Missing or invalid query parameters", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "500": { "description": "Failed to retrieve export data", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "Database session could not be established", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/exports/callcenterfollowup": { "get": { "summary": "Export call center follow-up list as CSV", "description": "Proxies the CouchDB `callcenterfollowup-csv` list export and returns\na CSV file for the selected flight.\n", "tags": [ "Exports" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "exports:read", "parameters": [ { "in": "query", "name": "flightName", "required": false, "schema": { "type": "string" }, "description": "Flight name to export." } ], "responses": { "200": { "description": "CSV export generated successfully", "content": { "text/csv": { "schema": { "type": "string", "format": "binary" } } } }, "400": { "description": "Missing required query parameters", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "500": { "description": "Failed to retrieve export data", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "Database session could not be established", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/exports/tourlead": { "get": { "summary": "Export tour lead data as CSV", "description": "Proxies the CouchDB `tourlead-csv` list export and returns\na CSV file for the selected flight.\n", "tags": [ "Exports" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "exports:read", "parameters": [ { "in": "query", "name": "flightName", "required": false, "schema": { "type": "string" }, "description": "Flight name to export." } ], "responses": { "200": { "description": "CSV export generated successfully", "content": { "text/csv": { "schema": { "type": "string", "format": "binary" } } } }, "400": { "description": "Missing required query parameters", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "500": { "description": "Failed to retrieve export data", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "Database session could not be established", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/flights/{id}/assignments": { "get": { "summary": "Retrieve flight assignment data", "description": "Retrieves the current assignment data for a specified flight including:\n- Flight metadata (name, capacity, date)\n- List of veteran-guardian pairs assigned to the flight\n- Counts of veterans, guardians, confirmed, and remaining capacity\n\nVeterans and guardians marked as nofly are excluded from counts.\nPairs are sorted by group (if present) then by application date.\n", "tags": [ "Flight Assignments" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:read", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Flight document ID" } ], "responses": { "200": { "description": "Flight assignment data retrieved successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FlightAssignment" } } } }, "400": { "description": "Invalid document id or document is not a flight record" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Flight not found" }, "500": { "description": "Server error" }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } }, "post": { "summary": "Add veterans from waitlist to flight", "description": "Adds a specified number of veterans from the waitlist to the flight.\n\nThe selection follows these rules:\n- Veterans are taken in order of application date\n- When a veteran in a group is selected, all group members are added\n- Veterans with paired guardians have their guardian added automatically\n- Flight history entries are recorded for each assignment\n\nEach veteran is saved, then each paired guardian. A CouchDB 409 is\nretried once after the current revision is re-read. If that retry still\nconflicts, the failure is a conflict for that document.\n\nThe response is 200 only when every attempted save succeeds. When a\nveteran or guardian save fails, the status is 409 if any remaining\nfailure is a conflict and 500 otherwise. Both failure responses list\nthe ids that were saved and the ids that failed.\n\nThe veteranCount must be between 1 and 100.\n", "tags": [ "Flight Assignments" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "flights:manage", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Flight document ID" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "veteranCount" ], "properties": { "veteranCount": { "type": "integer", "minimum": 1, "maximum": 100, "description": "Number of veterans to add from waitlist" } } } } } }, "responses": { "200": { "description": "Every selected veteran and paired guardian was saved", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddVeteransResult" } } } }, "400": { "description": "Invalid document id or invalid request (bad veteranCount or not a flight record)" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Flight not found" }, "409": { "description": "One or more veteran or guardian documents conflicted. The handler\nre-reads the current revision and retries that write once. This\nstatus is returned when a conflict remains after that retry. The\nbody lists the ids that were saved and the ids that failed.\n", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddVeteransResult" } } } }, "500": { "description": "Server error while preparing the assignment, or one or more veteran\nor guardian saves failed for a reason other than a remaining document\nconflict. Save failures list the ids that were saved and the ids that failed.\n", "content": { "application/json": { "schema": { "oneOf": [ { "$ref": "#/components/schemas/AddVeteransResult" }, { "$ref": "#/components/schemas/Error" } ] } } } }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } } }, "/flights/{id}/detail": { "get": { "summary": "Retrieve flight detail data with seat and bus assignments", "description": "Retrieves detailed seat and bus assignment data for a specified flight including:\n- Flight metadata (name, capacity, date)\n- Statistics:\n - Bus counts (None, Alpha1-5, Bravo1-5)\n - Tour counts (Alpha, Bravo, None)\n - Flight counts (excludes nofly entries)\n- List of veteran-guardian pairs with seat/bus assignments\n- Per-person call-center fields such as fm_number and assigned_to when present\n- Per-person form fields used by gt-checkin, medical, and other flight forms\n- Guardian training as the training type only. A trailing medical-level\n suffix (` [A]` through ` [D]`) from the flight_pairings view is removed\n here. medical_level remains a separate field. The Couch view is unchanged.\n\nEach pair includes mismatch flags:\n- busMismatch: true if people in the pair have different bus assignments\n- missingPairedPerson: true if a paired person is not on this flight\n\nGuardians paired with multiple veterans are deduplicated within each pair.\n", "tags": [ "Flight Detail" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:read", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Flight document ID" } ], "responses": { "200": { "description": "Flight detail data retrieved successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FlightDetailResult" } } } }, "400": { "description": "Invalid document id or document is not a flight record" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Flight not found" }, "500": { "description": "Server error" }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } } }, "/flights/{id}/complete": { "post": { "summary": "Mark a flight completed and its active people as Flown", "description": "Matches people by flight name (flight.id) using\n_design/basic/_view/all_by_flight_and_name. Each changed person gets a\nflight.history status line and updated metadata.updated_at and\nmetadata.updated_by, the same as an individual status edit. The flight\nis marked completed only after every person save succeeds.\n", "tags": [ "Flights" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "flights:manage", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Flight document ID" } ], "responses": { "200": { "description": "Every qualifying person and the flight were saved, including when nobody needed changing", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FlightStatusBulkResult" } } } }, "207": { "description": "Some documents were attempted and one or more were not saved. failed lists their ids. The flight stays not completed when any person failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FlightStatusBulkResult" } } } }, "400": { "description": "Invalid document id, document is not a flight record, or flight name cannot be used to match people" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Flight not found" }, "409": { "description": "Flight is already completed. Nothing was changed" }, "500": { "description": "Server error before any document was saved" }, "503": { "description": "Database unreachable before any document was saved" } } } }, "/flights/future-status/activate": { "post": { "summary": "Change every person with a Future-* status to Active", "description": "Accepts any status beginning with \"Future-\". Reads\n_design/basic/_view/all_by_status_and_name. Each changed person gets a\nflight.history status line and updated metadata.updated_at and\nmetadata.updated_by, the same as an individual status edit. Matched\npeople who are on a flight are still changed and listed in\nassignedToFlight.\n", "tags": [ "Flights" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "flights:manage", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FutureStatusActivateRequest" } } } }, "responses": { "200": { "description": "Every matching person was saved, including when nobody had the status", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FlightStatusBulkResult" } } } }, "207": { "description": "Some documents were attempted and one or more were not saved. failed lists their ids", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FlightStatusBulkResult" } } } }, "400": { "description": "status is missing or does not begin with \"Future-\"" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "500": { "description": "Server error before any document was saved" }, "503": { "description": "Database unreachable before any document was saved" } } } }, "/flights": { "get": { "summary": "Retrieve a list of all flights", "description": "Retrieves all flights from the database using the CouchDB \"Flights\" view.\nReturns an array of flight objects containing name, flight_date, capacity, and completed fields.\n", "tags": [ "Flights" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:read", "responses": { "200": { "description": "List of flights retrieved successfully", "content": { "application/json": { "schema": { "type": "array", "items": { "type": "object", "properties": { "_id": { "type": "string", "description": "Flight document ID" }, "name": { "type": "string", "description": "Flight name" }, "flight_date": { "type": "string", "format": "date", "description": "Flight date in YYYY-MM-DD format" }, "capacity": { "type": "integer", "description": "Flight capacity" }, "completed": { "type": "boolean", "description": "Whether the flight is completed" } } } }, "example": [ { "_id": "422fc05d0401190a7a13ad7ffde62d3c", "name": "SSHF-Nov2011", "flight_date": "2011-11-05", "capacity": 448, "completed": true } ] } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "500": { "description": "Server error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } }, "post": { "summary": "Create a new flight record", "tags": [ "Flights" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "flights:manage", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Flight" } } } }, "responses": { "201": { "description": "Flight record created successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Flight" } } } }, "400": { "description": "Invalid flight data", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "500": { "description": "Server error" }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } } }, "/flights/{id}": { "get": { "summary": "Retrieve a flight record by ID", "tags": [ "Flights" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:read", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Flight record ID" } ], "responses": { "200": { "description": "Flight record retrieved successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Flight" } } } }, "400": { "description": "Invalid document id or document is not a flight record" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Flight not found" }, "500": { "description": "Server error" }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } }, "put": { "summary": "Update a flight record", "tags": [ "Flights" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "flights:manage", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Flight record ID" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Flight" } } } }, "responses": { "200": { "description": "Flight record updated successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Flight" } } } }, "400": { "description": "Invalid document id, invalid flight data, or document is not a flight record" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Flight not found" }, "500": { "description": "Server error" }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } } }, "/guardians": { "post": { "summary": "Create a new guardian record", "tags": [ "Guardians" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Guardian" } } } }, "responses": { "201": { "description": "Guardian record created successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Guardian" } } } }, "400": { "description": "Invalid guardian data", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "500": { "description": "Server error" }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } } }, "/guardians/{id}": { "get": { "summary": "Retrieve a guardian record by ID", "tags": [ "Guardians" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:read", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Guardian record ID" } ], "responses": { "200": { "description": "Guardian record retrieved successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Guardian" } } } }, "400": { "description": "Invalid document id or document is not a guardian record" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Guardian not found" }, "500": { "description": "Server error" }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } }, "put": { "summary": "Update a guardian record", "tags": [ "Guardians" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Guardian record ID" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Guardian" } } } }, "responses": { "200": { "description": "Guardian record updated successfully. When veteran.pairings array is modified, the affected veteran records are automatically updated to reflect the pairing changes. History entries are added to both guardian and veteran records.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Guardian" } } } }, "400": { "description": "Invalid document id, invalid guardian data, or document is not a guardian record" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Guardian not found" }, "500": { "description": "Server error" }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } }, "x-code-samples": [ { "lang": "JavaScript", "label": "Example: Adding a veteran pairing", "source": "// When updating veteran.pairings, the system automatically:\n// 1. Updates the veteran's guardian.id and guardian.name\n// 2. Adds history entries to both guardian and veteran records\nconst response = await fetch('/guardians/guardian-id', {\n method: 'PUT',\n body: JSON.stringify({\n veteran: {\n pairings: [{ id: 'veteran-id', name: 'Veteran Name' }]\n }\n })\n});\n" } ] }, "delete": { "summary": "Delete a guardian record", "tags": [ "Guardians" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:delete", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Guardian record ID" } ], "responses": { "200": { "description": "Guardian record deleted successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "id": { "type": "string" }, "rev": { "type": "string" } } } } } }, "400": { "description": "Invalid document id or document is not a guardian record" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Guardian not found" }, "500": { "description": "Server error" }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } } }, "/guardians/{id}/seat": { "patch": { "summary": "Update a guardian's seat assignment", "description": "Quickly updates only the seat assignment for a guardian without loading the full model.\nAdds a history entry for the change.\n", "tags": [ "Guardians" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Guardian record ID" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "string", "description": "New seat assignment (e.g., \"14A\")" } } } } } }, "responses": { "200": { "description": "Seat updated successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "id": { "type": "string" }, "rev": { "type": "string" }, "seat": { "type": "string" } } } } } }, "400": { "description": "Invalid document id, invalid request, or document is not a guardian record" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Guardian not found" }, "500": { "description": "Server error" }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } } }, "/guardians/{id}/bus": { "patch": { "summary": "Update a guardian's bus assignment", "description": "Quickly updates only the bus assignment for a guardian without loading the full model.\nAdds a history entry for the change.\nBus must be one of: None, Alpha1, Alpha2, Alpha3, Alpha4, Alpha5, Bravo1, Bravo2, Bravo3, Bravo4, Bravo5\n", "tags": [ "Guardians" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Guardian record ID" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "string", "enum": [ "None", "Alpha1", "Alpha2", "Alpha3", "Alpha4", "Alpha5", "Bravo1", "Bravo2", "Bravo3", "Bravo4", "Bravo5" ], "description": "New bus assignment" } } } } } }, "responses": { "200": { "description": "Bus updated successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "id": { "type": "string" }, "rev": { "type": "string" }, "bus": { "type": "string" } } } } } }, "400": { "description": "Invalid document id, invalid request, invalid bus value, or document is not a guardian record" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Guardian not found" }, "500": { "description": "Server error" }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } } }, "/guardians/{id}/training-notes": { "patch": { "summary": "Update guardian training notes", "description": "Patches one field on the record. Requires records:write.", "tags": [ "Guardians" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Record id" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "string" } } } } } }, "responses": { "200": { "description": "Field updated" }, "400": { "description": "Invalid id or value" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Guardian not found" }, "503": { "description": "Database session error" } } } }, "/guardians/{id}/training-complete": { "patch": { "summary": "Update the guardian training-complete indicator", "description": "Patches one field on the record. Requires records:write.", "tags": [ "Guardians" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Record id" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "boolean" } } } } } }, "responses": { "200": { "description": "Field updated" }, "400": { "description": "Invalid id or value" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Guardian not found" }, "503": { "description": "Database session error" } } } }, "/guardians/{id}/waiver": { "patch": { "summary": "Update the guardian waiver-received indicator", "description": "Patches one field on the record. Requires records:write.", "tags": [ "Guardians" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Record id" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "boolean" } } } } } }, "responses": { "200": { "description": "Field updated" }, "400": { "description": "Invalid id or value" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Guardian not found" }, "503": { "description": "Database session error" } } } }, "/guardians/{id}/training-see-doc": { "patch": { "summary": "Update the guardian training-see-doctor indicator", "description": "Patches one field on the record. Requires records:write.", "tags": [ "Guardians" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Record id" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "boolean" } } } } } }, "responses": { "200": { "description": "Field updated" }, "400": { "description": "Invalid id or value" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Guardian not found" }, "503": { "description": "Database session error" } } } }, "/guardians/{id}/vaccinated": { "patch": { "summary": "Update the guardian vaccinated indicator", "description": "Patches one field on the record. Requires records:write.", "tags": [ "Guardians" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Record id" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "boolean" } } } } } }, "responses": { "200": { "description": "Field updated" }, "400": { "description": "Invalid id or value" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Guardian not found" }, "503": { "description": "Database session error" } } } }, "/guardians/{id}/medical-form": { "patch": { "summary": "Update the guardian medical-form-received indicator", "description": "Patches one field on the record. Requires records:write.", "tags": [ "Guardians" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Record id" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "boolean" } } } } } }, "responses": { "200": { "description": "Field updated" }, "400": { "description": "Invalid id or value" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Guardian not found" }, "503": { "description": "Database session error" } } } }, "/guardians/{id}/paid": { "patch": { "summary": "Update the guardian paid indicator", "description": "Patches one field on the record. Requires records:write.", "tags": [ "Guardians" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Record id" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "boolean" } } } } } }, "responses": { "200": { "description": "Field updated" }, "400": { "description": "Invalid id or value" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Guardian not found" }, "503": { "description": "Database session error" } } } }, "/guardians/{id}/books-ordered": { "patch": { "summary": "Update how many books were ordered for a guardian", "description": "Patches one field on the record. Requires records:write.", "tags": [ "Guardians" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Record id" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "integer", "minimum": 0, "maximum": 9 } } } } } }, "responses": { "200": { "description": "Field updated" }, "400": { "description": "Invalid id or value" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Guardian not found" }, "503": { "description": "Database session error" } } } }, "/guardians/{id}/apparel-shirt-size": { "patch": { "summary": "Update a guardian apparel shirt size", "description": "Patches one field on the record. Requires records:write.", "tags": [ "Guardians" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Record id" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "string" } } } } } }, "responses": { "200": { "description": "Field updated" }, "400": { "description": "Invalid id or value" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Guardian not found" }, "503": { "description": "Database session error" } } } }, "/guardians/{id}/apparel-jacket-size": { "patch": { "summary": "Update a guardian apparel jacket size", "description": "Patches one field on the record. Requires records:write.", "tags": [ "Guardians" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Record id" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "string" } } } } } }, "responses": { "200": { "description": "Field updated" }, "400": { "description": "Invalid id or value" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Guardian not found" }, "503": { "description": "Database session error" } } } }, "/guardians/{id}/apparel-notes": { "patch": { "summary": "Update guardian apparel notes", "description": "Patches one field on the record. Requires records:write.", "tags": [ "Guardians" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Record id" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "string" } } } } } }, "responses": { "200": { "description": "Field updated" }, "400": { "description": "Invalid id or value" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Guardian not found" }, "503": { "description": "Database session error" } } } }, "/query": { "post": { "summary": "Execute a CouchDB Mango _find query", "description": "Executes a read-only Mango selector query against the database.\nThis endpoint is a secure proxy that only allows _find queries and prevents\nany mutation operations. Queries are never persisted.\n\n**Security**: Queries are validated to prevent mutations. The following are forbidden:\n- Mutation operators ($set, $update, $unset, $inc, $push, $pull)\n- Bulk operations (docs, bulk, new_edits)\n- Index creation (index, ddoc, type)\n- Map/reduce operations (map, reduce, views)\n- Skip-based pagination (use bookmark instead)\n\n**Pagination**: Use bookmark for pagination, not skip.\nDefault limit is 25, maximum is 100. Limits exceeding 100 are clamped.\n\n**Empty selector**: An empty selector object {} is allowed and matches all documents\n(subject to the limit).\n\n**Index refresh**: This endpoint forces update: false in the CouchDB request to disable\nindex refresh during query execution.\n", "tags": [ "Search" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:read", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/QueryRequest" }, "examples": { "basicQuery": { "summary": "Basic query with selector", "value": { "selector": { "type": "veteran", "status": "Active" }, "limit": 25 } }, "withFields": { "summary": "Query with field projection", "value": { "selector": { "type": "guardian" }, "fields": [ "_id", "name", "phone", "status" ], "limit": 10 } }, "withBookmark": { "summary": "Paginated query with bookmark", "value": { "selector": { "flight": "SSHF-Nov2024" }, "bookmark": "g1AAAAG3eJzLYWBg4M", "limit": 50 } }, "withSort": { "summary": "Query with sorting", "value": { "selector": { "status": "Active" }, "sort": [ { "name": "asc" } ], "limit": 25 } } } } } }, "responses": { "200": { "description": "Query executed successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/QueryResults" }, "examples": { "success": { "summary": "Successful query result", "value": { "docs": [ { "_id": "v123", "type": "veteran", "name": "John Smith", "status": "Active" }, { "_id": "v124", "type": "veteran", "name": "Jane Doe", "status": "Active" } ], "bookmark": "g1AAAAG3eJzLYWBg4M", "warning": "no matching index found, the query was executed without an index" } }, "withStats": { "summary": "Result with execution statistics", "value": { "docs": [ { "_id": "v123", "type": "veteran" } ], "bookmark": "g1AAAAG3eJzLYWBg4M", "execution_stats": { "total_keys_examined": 0, "total_docs_examined": 100, "total_quorum_docs_examined": 0, "results_returned": 1, "execution_time_ms": 12.5 } } } } } } }, "400": { "description": "Invalid query or forbidden operation", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } }, "examples": { "missingSelector": { "summary": "Missing selector", "value": { "error": "Validation failed: selector is required" } }, "mutationAttempt": { "summary": "Mutation operator detected", "value": { "error": "Validation failed: mutation operator not allowed: $set" } }, "skipNotAllowed": { "summary": "Skip pagination not allowed", "value": { "error": "Validation failed: forbidden keys detected: skip" } }, "invalidSyntax": { "summary": "CouchDB syntax error", "value": { "error": "Invalid selector syntax" } } } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - insufficient permissions" }, "500": { "description": "Server error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } } }, "/recent-activity": { "get": { "summary": "Retrieve recent activity entries", "description": "Retrieves paginated recent activity entries from the database.\nShows various categories of recent changes from most recent to oldest.\nThe type parameter determines which category of changes to retrieve.\n", "tags": [ "Recent Activity" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:read", "parameters": [ { "in": "query", "name": "type", "required": true, "schema": { "type": "string", "enum": [ "modified", "added", "call", "flight", "pairing" ] }, "description": "Type of recent activity to retrieve:\n- modified: Recently modified records\n- added: Recently added records\n- call: Recent call changes\n- flight: Recent flight changes\n- pairing: Recent pairing changes\n" }, { "in": "query", "name": "offset", "schema": { "type": "integer", "default": 0 }, "description": "Zero-based offset for pagination (number of records to skip)" }, { "in": "query", "name": "limit", "schema": { "type": "integer", "default": 20 }, "description": "Maximum number of results to return" } ], "responses": { "200": { "description": "Recent activity entries retrieved successfully", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/RecentActivityEntry" } }, "example": [ { "id": "0ccf1cdbac2279ae3e2de3791209c357", "type": "Guardian", "name": "Catherine Manaspas", "city": "Chippewa Falls, WI", "appdate": "2025-11-18", "recdate": "2025-12-29T01:04:40Z", "recby": "Steve Schmechel", "change": "changed flight from: None to: SSHF-Test01" } ] } } }, "400": { "description": "Invalid or missing type parameter", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } }, "example": { "error": "type parameter is required" } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "500": { "description": "Server error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } } }, "/review/applications": { "post": { "summary": "Submit a new application for review (website intake)", "description": "Called by the hf_appcollector Cloud Function with the raw website form payload. Requires a Google-signed service-account ID token whose email is listed in REVIEW_INTAKE_SERVICE_ACCOUNTS. Legacy credential fields (cburi, cbusr, cbpwd) and full_message are stripped before storage. The application is stored with app_status \"New\". Intake is permissive: only `type` (VeteranApp or GuardianApp) is required; incomplete form payloads are stored as-is for reviewers to fix in the UI. Logistics model validation runs only on accept.\n", "tags": [ "Review Applications" ], "security": [ { "IntakeIdToken": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReviewApplicationIntake" } } } }, "responses": { "201": { "description": "Application stored for review", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReviewApplication" } } } }, "400": { "description": "Invalid or missing application type (must be VeteranApp or GuardianApp)", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } }, "401": { "description": "Missing or invalid intake token" }, "403": { "description": "Service account not permitted" }, "500": { "description": "Server error" }, "503": { "description": "Review database session unavailable" } } }, "get": { "summary": "List applications awaiting review", "description": "Returns applications with the given status, newest first, using the legacy hf-app-review/new_apps view in the review database.\n", "tags": [ "Review Applications" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "applications:review", "parameters": [ { "in": "query", "name": "status", "schema": { "type": "string", "enum": [ "New", "Hold", "Accepted", "Rejected", "Trash" ], "default": "New" }, "description": "Application status to list" }, { "in": "query", "name": "limit", "schema": { "type": "integer", "minimum": 1, "maximum": 500, "default": 25 }, "description": "Maximum number of rows to return (clamped to 1-500)" } ], "responses": { "200": { "description": "Matching applications", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReviewApplicationList" } } } }, "400": { "description": "Invalid application status", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "500": { "description": "Server error" }, "503": { "description": "Review database session unavailable" } } } }, "/review/applications/{id}": { "get": { "summary": "Retrieve an application under review", "tags": [ "Review Applications" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "applications:review", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Review application document ID" } ], "responses": { "200": { "description": "Normalized application", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReviewApplication" } } } }, "400": { "description": "Invalid document id or document is not a review application" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Application not found" }, "500": { "description": "Server error" }, "503": { "description": "Review database session unavailable" } } }, "put": { "summary": "Edit an application under review", "description": "Replaces the editable (normalized) fields of the application. Submission metadata (date_time, ip_address, accepted_as_rev, created_*) is preserved and unknown legacy fields in the stored document are kept. Setting app_status to \"Accepted\" is rejected; use the accept endpoint instead.\n", "tags": [ "Review Applications" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "applications:review", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Review application document ID" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReviewApplication" } } } }, "responses": { "200": { "description": "Application updated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReviewApplication" } } } }, "400": { "description": "Invalid document id, validation failure, not a review application, or attempted accept via update", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Application not found" }, "500": { "description": "Server error" }, "503": { "description": "Review database session unavailable" } } } }, "/review/applications/{id}/status": { "patch": { "summary": "Set the review status of an application (Hold, Rejected, Trash, New)", "tags": [ "Review Applications" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "applications:review", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Review application document ID" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReviewApplicationStatusUpdate" } } } }, "responses": { "200": { "description": "Status updated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReviewApplication" } } } }, "400": { "description": "Invalid document id, invalid status, attempted accept via status endpoint, or not a review application", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Application not found" }, "500": { "description": "Server error" }, "503": { "description": "Review database session unavailable" } } } }, "/review/applications/{id}/accept": { "post": { "summary": "Accept an application and copy it into the logistics database", "description": "Builds a Veteran or Guardian record from the application (using the standard models and validation) and writes it to the logistics database with the same document ID. If the application was accepted before, the logistics record is updated only when its revision still matches the revision recorded at the previous acceptance (accepted_as_rev); otherwise 409 is returned and nothing is changed. On success the application is marked Accepted and accepted_as_rev is updated.\n", "tags": [ "Review Applications" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "applications:accept", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Review application document ID" } ], "requestBody": { "required": false, "content": { "application/json": { "schema": { "type": "object", "properties": { "app_status_note": { "type": "string", "description": "Optional reviewer note stored with the application" } } } } } }, "responses": { "200": { "description": "Application accepted and logistics record saved", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReviewApplicationAcceptResult" } } } }, "400": { "description": "Invalid document id, logistics record validation failed (edit the application first), or not a review application", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Application not found" }, "409": { "description": "Logistics record was modified since the previous acceptance", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } }, "500": { "description": "Server error" }, "503": { "description": "Database session unavailable" } } } }, "/search": { "get": { "summary": "Search for veterans and guardians", "description": "Searches for veterans and guardians based on provided criteria.\nThe search can be filtered by status or flight, but not both simultaneously.\nIf status is not 'All', flight filter will be ignored.\n", "tags": [ "Search" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:read", "parameters": [ { "in": "query", "name": "limit", "schema": { "type": "integer", "default": 25 }, "description": "Maximum number of results to return" }, { "in": "query", "name": "lastname", "schema": { "type": "string" }, "description": "Last name prefix to search for (partial match). Apostrophes, periods, and spaces are removed before querying so the term matches the name index. Case is unchanged. Ignored when phone_num is provided." }, { "in": "query", "name": "phone_num", "schema": { "type": "string" }, "description": "Phone number search term. Non-digits are ignored; requires at least 3 numeric digits." }, { "in": "query", "name": "status", "schema": { "type": "string", "enum": [ "All", "Active", "Flown", "Deceased", "Removed", "Future-Spring", "Future-Fall", "Future-PostRestriction" ], "default": "Active" }, "description": "Status filter for the search" }, { "in": "query", "name": "flight", "schema": { "type": "string", "default": "All" }, "description": "Flight ID filter for the search (ignored if status is not 'All')" } ], "responses": { "200": { "description": "Search completed successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchResults" }, "example": { "total_rows": 2, "offset": 0, "rows": [ { "id": "doc1", "key": [ "Active", "Smith" ], "value": { "type": "Veteran", "name": "John Smith", "phone": "312-555-1234", "city": "Chicago", "appdate": "2024-01-15", "flight": "F23", "status": "Active", "pairing": "Jane Doe", "pairingId": "guard1" } } ] } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "500": { "description": "Server error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } } }, "/user/permissions": { "get": { "summary": "Summarize the authenticated user's roles and permissions", "description": "Auth-only permission summary for UI hints. Skips requirePermission so a signed-in user with no roles receives 200 and an empty permissions list. roles lists only the roles granted directly by group membership (a FULL user is [\"FULL\"], not READ and WRITE). permissions is the effective union, including inheritance. Group emails are omitted. The API still enforces permissions on each data route.\n", "tags": [ "User" ], "security": [ { "GoogleAuth": [] } ], "responses": { "200": { "description": "Effective roles and permissions for the signed-in user", "headers": { "Cache-Control": { "description": "Per-user authorization data is not stored by caches", "schema": { "type": "string", "example": "no-store" } } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserPermissions" } } } }, "401": { "description": "Missing, invalid, or wrong-audience token" }, "403": { "description": "Email domain rejected by ALLOWED_EMAIL_DOMAINS" }, "503": { "description": "Token introspection or Workspace Directory group lookup temporarily unavailable" } } } }, "/veterans": { "post": { "summary": "Create a new veteran record", "tags": [ "Veterans" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Veteran" } } } }, "responses": { "201": { "description": "Veteran record created successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Veteran" } } } }, "400": { "description": "Invalid veteran data", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "500": { "description": "Server error" }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } } }, "/veterans/{id}": { "get": { "summary": "Retrieve a veteran record by ID", "tags": [ "Veterans" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:read", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Veteran record ID" } ], "responses": { "200": { "description": "Veteran record retrieved successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Veteran" } } } }, "400": { "description": "Invalid document id or document is not a veteran record" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Veteran not found" }, "500": { "description": "Server error" }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } }, "put": { "summary": "Update a veteran record", "tags": [ "Veterans" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Veteran record ID" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Veteran" } } } }, "responses": { "200": { "description": "Veteran record updated successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Veteran" } } } }, "400": { "description": "Invalid document id, invalid veteran data, or document is not a veteran record" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Veteran not found" }, "500": { "description": "Server error" }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } }, "delete": { "summary": "Delete a veteran record", "tags": [ "Veterans" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:delete", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Veteran record ID" } ], "responses": { "200": { "description": "Veteran record deleted successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "id": { "type": "string" }, "rev": { "type": "string" } } } } } }, "400": { "description": "Invalid document id or document is not a veteran record" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Veteran not found" }, "500": { "description": "Server error" }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } } }, "/veterans/search": { "get": { "summary": "Search for unpaired veterans", "description": "Searches for unpaired veterans based on provided criteria.\nCurrently only supports searching for unpaired veterans (paired=false).\nThe search uses the unpaired_veterans_by_last_name view which filters\nveterans where guardian.id is empty. That view emits\n[flight.status, name.last.toUpperCase()] and keeps spaces and punctuation.\nThe lastname query is uppercased to match that key. It is not passed\nthrough the /search name-index helper, which strips spaces, apostrophes,\nand periods and leaves case unchanged.\n", "tags": [ "Veterans" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:read", "parameters": [ { "in": "query", "name": "paired", "schema": { "type": "boolean", "default": false }, "description": "Whether to search for paired veterans (currently not implemented)" }, { "in": "query", "name": "status", "schema": { "type": "string", "enum": [ "Active", "Flown", "Deceased", "Removed", "Future-Spring", "Future-Fall", "Future-PostRestriction" ], "default": "Active" }, "description": "Flight status filter for the search" }, { "in": "query", "name": "lastname", "schema": { "type": "string" }, "description": "Last name prefix. Uppercased to match unpaired_veterans_by_last_name.\nSpaces and punctuation are kept, so \"Le Roy\" and \"le roy\" share a key\nand \"LeRoy\" does not.\n" }, { "in": "query", "name": "limit", "schema": { "type": "integer", "default": 25 }, "description": "Maximum number of results to return" } ], "responses": { "200": { "description": "Search completed successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UnpairedVeteranResults" }, "example": [ { "id": "doc1", "name": "John Smith", "city": "Chicago, IL", "flight": "F23", "prefs": "Prefers window seat" }, { "id": "doc2", "name": "Jane Doe", "city": "New York, NY", "flight": "F24", "prefs": "" } ] } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "500": { "description": "Server error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } }, "501": { "description": "Not Implemented - paired=true is not yet supported", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } } }, "/veterans/{id}/seat": { "patch": { "summary": "Update a veteran's seat assignment", "description": "Quickly updates only the seat assignment for a veteran without loading the full model.\nAdds a history entry for the change.\n", "tags": [ "Veterans" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Veteran record ID" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "string", "description": "New seat assignment (e.g., \"14A\")" } } } } } }, "responses": { "200": { "description": "Seat updated successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "id": { "type": "string" }, "rev": { "type": "string" }, "seat": { "type": "string" } } } } } }, "400": { "description": "Invalid document id, invalid request, or document is not a veteran record" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Veteran not found" }, "500": { "description": "Server error" }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } } }, "/veterans/{id}/bus": { "patch": { "summary": "Update a veteran's bus assignment", "description": "Quickly updates only the bus assignment for a veteran without loading the full model.\nAdds a history entry for the change.\nBus must be one of: None, Alpha1, Alpha2, Alpha3, Alpha4, Alpha5, Bravo1, Bravo2, Bravo3, Bravo4, Bravo5\n", "tags": [ "Veterans" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Veteran record ID" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "string", "enum": [ "None", "Alpha1", "Alpha2", "Alpha3", "Alpha4", "Alpha5", "Bravo1", "Bravo2", "Bravo3", "Bravo4", "Bravo5" ], "description": "New bus assignment" } } } } } }, "responses": { "200": { "description": "Bus updated successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "id": { "type": "string" }, "rev": { "type": "string" }, "bus": { "type": "string" } } } } } }, "400": { "description": "Invalid document id, invalid request, invalid bus value, or document is not a veteran record" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Veteran not found" }, "500": { "description": "Server error" }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } } }, "/veterans/{id}/mail-call-received": { "patch": { "summary": "Update whether a veteran mail call was received", "description": "Patches one field on the record. Requires records:write.", "tags": [ "Veterans" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Record id" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "boolean" } } } } } }, "responses": { "200": { "description": "Field updated" }, "400": { "description": "Invalid id or value" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Veteran not found" }, "503": { "description": "Database session error" } } } }, "/veterans/{id}/mail-call-adopt": { "patch": { "summary": "Update whether a veteran mail call was adopted", "description": "Patches one field on the record. Requires records:write.", "tags": [ "Veterans" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Record id" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "boolean" } } } } } }, "responses": { "200": { "description": "Field updated" }, "400": { "description": "Invalid id or value" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Veteran not found" }, "503": { "description": "Database session error" } } } }, "/veterans/{id}/medical-form": { "patch": { "summary": "Update the veteran medical-form-received indicator", "description": "Patches one field on the record. Requires records:write.", "tags": [ "Veterans" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Record id" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "boolean" } } } } } }, "responses": { "200": { "description": "Field updated" }, "400": { "description": "Invalid id or value" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Veteran not found" }, "503": { "description": "Database session error" } } } }, "/veterans/{id}/medical-review": { "patch": { "summary": "Update the veteran medical-review indicator", "description": "Patches one field on the record. Requires records:write.", "tags": [ "Veterans" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Record id" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "string" } } } } } }, "responses": { "200": { "description": "Field updated" }, "400": { "description": "Invalid id or value" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Veteran not found" }, "503": { "description": "Database session error" } } } }, "/veterans/{id}/vaccinated": { "patch": { "summary": "Update the veteran vaccinated indicator", "description": "Patches one field on the record. Requires records:write.", "tags": [ "Veterans" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Record id" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "boolean" } } } } } }, "responses": { "200": { "description": "Field updated" }, "400": { "description": "Invalid id or value" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Veteran not found" }, "503": { "description": "Database session error" } } } }, "/veterans/{id}/homecoming-destination": { "patch": { "summary": "Update a veteran homecoming destination", "description": "Patches one field on the record. Requires records:write.", "tags": [ "Veterans" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Record id" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "string" } } } } } }, "responses": { "200": { "description": "Field updated" }, "400": { "description": "Invalid id or value" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Veteran not found" }, "503": { "description": "Database session error" } } } }, "/veterans/{id}/apparel-shirt-size": { "patch": { "summary": "Update a veteran apparel shirt size", "description": "Patches one field on the record. Requires records:write.", "tags": [ "Veterans" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Record id" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "string" } } } } } }, "responses": { "200": { "description": "Field updated" }, "400": { "description": "Invalid id or value" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Veteran not found" }, "503": { "description": "Database session error" } } } }, "/veterans/{id}/apparel-jacket-size": { "patch": { "summary": "Update a veteran apparel jacket size", "description": "Patches one field on the record. Requires records:write.", "tags": [ "Veterans" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Record id" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "string" } } } } } }, "responses": { "200": { "description": "Field updated" }, "400": { "description": "Invalid id or value" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Veteran not found" }, "503": { "description": "Database session error" } } } }, "/veterans/{id}/apparel-notes": { "patch": { "summary": "Update veteran apparel notes", "description": "Patches one field on the record. Requires records:write.", "tags": [ "Veterans" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:write", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" }, "description": "Record id" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "value" ], "properties": { "value": { "type": "string" } } } } } }, "responses": { "200": { "description": "Field updated" }, "400": { "description": "Invalid id or value" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "404": { "description": "Veteran not found" }, "503": { "description": "Database session error" } } } }, "/waitlist/veteran-groups": { "get": { "summary": "Retrieve active veteran groups from waitlist", "description": "Retrieves active veterans that have a flight group assignment and\nreturns them grouped by group number.\nGroup keys are sorted ascending in the API response.\n", "tags": [ "Waitlist" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:read", "responses": { "200": { "description": "Veteran groups retrieved successfully", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/WaitlistVeteranGroup" } }, "example": [ { "group": "853-3", "names": [ "William Mathias (SSHF-Mark1)", "Robert Kossow (SSHF-Mark1)" ] }, { "group": "855-2", "names": [ "Philip Schultz" ] } ] } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "500": { "description": "Server error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } } }, "/waitlist": { "get": { "summary": "Retrieve waitlist entries for veterans or guardians", "description": "Retrieves paginated waitlist entries from the database.\nThe veteran waitlist shows veterans waiting to be assigned to a flight.\nThe guardian waitlist shows unpaired guardians waiting to be matched with a veteran.\nResults are returned in waitlist order as defined by the database views.\n", "tags": [ "Waitlist" ], "security": [ { "GoogleAuth": [] } ], "x-required-permission": "records:read", "parameters": [ { "in": "query", "name": "type", "required": true, "schema": { "type": "string", "enum": [ "veterans", "guardians" ] }, "description": "Type of waitlist to retrieve" }, { "in": "query", "name": "offset", "schema": { "type": "integer", "default": 0 }, "description": "Zero-based offset for pagination (number of records to skip)" }, { "in": "query", "name": "limit", "schema": { "type": "integer", "default": 20 }, "description": "Maximum number of results to return" } ], "responses": { "200": { "description": "Waitlist entries retrieved successfully", "content": { "application/json": { "schema": { "type": "array", "items": { "oneOf": [ { "$ref": "#/components/schemas/Veteran" }, { "$ref": "#/components/schemas/Guardian" } ] } }, "examples": { "veterans": { "summary": "Veteran waitlist response", "value": [ { "_id": "vet123", "type": "Veteran", "name": { "first": "John", "last": "Smith" }, "address": { "city": "Chicago", "state": "IL" } } ] }, "guardians": { "summary": "Guardian waitlist response", "value": [ { "_id": "guard456", "type": "Guardian", "name": { "first": "Jane", "last": "Doe" }, "address": { "city": "Springfield", "state": "IL" } } ] } } } } }, "400": { "description": "Invalid or missing type parameter", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } }, "example": { "error": "type parameter is required" } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden - missing required permission" }, "500": { "description": "Server error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } }, "503": { "description": "Database session error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } } } } }