[
  {
    "id": "01-api-keys",
    "at": "2026-09-18T14:26:37.284Z",
    "build": "http://localhost:3102",
    "path": "/app/api-keys",
    "caption": "Account API keys on the signed-in training organization.",
    "callouts": [],
    "visibleText": "Select an option\nPhone\nChat\nAI Agent\nWhat's this?\nSupport\nReport a Bug\n1\n\n1 waiting on you\n\nOpen Approvals\nAPI Keys\nCreate New Key\nActive Keys (0)\nInactive Keys (0)\nNAME\tKEY\tSTATUS\tUSAGE\tCREATED\tLAST USED\tACTIONS\nNo API keys found.\nAPI Key Security\n\nYour API keys carry many privileges. Do not share your API keys in publicly accessible areas such as GitHub, client-side code, or in your application. Rotate your keys periodically and restrict them to specific IP addresses when possible.\n\nUnderstanding API Key Scopes\n\nAPI keys are granted specific permissions (scopes) that determine what actions they can perform:\n\nRead Permissions\n• read:profile - View user profile information\n• read:data - Access application data\n• read:analytics - View analytics and reports\nWrite Permissions\n• write:profile - Update user profile\n• write:data - Create and modify data\n• write:billing - Manage billing operations\nLearn more about API authentication and usage →"
  },
  {
    "id": "02-key-form",
    "at": "2026-09-18T14:26:37.366Z",
    "build": "http://localhost:3102",
    "path": "/app/api-keys",
    "caption": "API-key creation fields before entering a secret.",
    "callouts": [],
    "visibleText": "Select an option\nPhone\nChat\nAI Agent\nWhat's this?\nSupport\nReport a Bug\n1\n\n1 waiting on you\n\nOpen Approvals\nAPI Keys\nCancel\nSave API Key\nCreate New API Key\n×\nAPI Key Name\nA descriptive name for your API key\nDescription\nOptional description of what this key will be used for\nPermissions\nRate Limits\nRequests per minute\nRequests per hour\nRequests per day\nExpiration Date\nOptional expiration date for this API key\nActive Keys (0)\nInactive Keys (0)\nNAME\tKEY\tSTATUS\tUSAGE\tCREATED\tLAST USED\tACTIONS\nNo API keys found.\nAPI Key Security\n\nYour API keys carry many privileges. Do not share your API keys in publicly accessible areas such as GitHub, client-side code, or in your application. Rotate your keys periodically and restrict them to specific IP addresses when possible.\n\nUnderstanding API Key Scopes\n\nAPI keys are granted specific permissions (scopes) that determine what actions they can perform:\n\nRead Permissions\n• read:profile - View user profile information\n• read:data - Access application data\n• read:analytics - View analytics and reports\nWrite Permissions\n• write:profile - Update user profile\n• write:data - Create and modify data\n• write:billing - Manage billing operations\nLearn more about API authentication and usage →"
  },
  {
    "id": "03-staff-reservation",
    "at": "2026-09-18T14:27:58.920Z",
    "build": "http://localhost:3102",
    "path": "/app/reservations",
    "caption": "Staff Reservations board showing the customer API booking after reloading.",
    "callouts": [],
    "visibleText": "Select an option\nPhone\nChat\nAI Agent\nWhat's this?\nSupport\nReport a Bug\n1\n\n1 waiting on you\n\nOpen Approvals\nReservations\n\nManage reservations, service points, and booking schedules\n\nReservations\nReservation Definitions\nService Points\nCalendar\n1\nTotal\n0\nToday\n1\nUpcoming\n$0\nRevenue\nNew Reservation\nPipeline\nList\nFilter\nRefresh\nNew\n1\nLina Tutorial\n\n6f5c9155\n\nDesign consultation\nOct 5\n10:00 AM\nlina.events@example.invalid\n1 guests\nCHANGE STATUS\nNew\nConfirmed\nPending\nCancelled\nCompleted\nConfirmed\n0\nNo reservations\nPending\n0\nNo reservations\nCancelled\n0\nNo reservations\nCompleted\n0\nNo reservations"
  },
  {
    "id": "04-customer-responses",
    "at": "2026-09-18T14:29:30.424Z",
    "build": "null",
    "path": "/Users/imzee/projects/docs/tutorials-plan/course-content/assets/appengine-client/04-customer-responses.txt",
    "caption": "Sanitized transcript of actual HTTP results, displayed as text; not an application UI.",
    "callouts": [],
    "visibleText": "Customer data uses two nested data levels\nActual local API results — 18 September 2026\nSelected response fields; credentials omitted.\n\n{\n  \"GET /client-data/profile\": {\n    \"status\": 200,\n    \"sk\": \"6aad41ccbef5e1976f5c9102\",\n    \"data\": {\n      \"firstName\": \"Lina\",\n      \"lastName\": \"Tutorial\",\n      \"email\": \"lina.events@example.invalid\"\n    }\n  },\n  \"GET /client-data/reservations\": {\n    \"status\": 200,\n    \"total\": 1,\n    \"data\": [\n      {\n        \"sk\": \"6aad49f2bef5e1976f5c9155\",\n        \"data\": {\n          \"name\": \"Q508LI8A\",\n          \"service\": \"Design consultation\",\n          \"startTime\": \"2026-10-05T10:00:00-05:00\",\n          \"endTime\": \"2026-10-05T10:30:00-05:00\",\n          \"status\": \"new\",\n          \"timezone\": \"America/Chicago\"\n        }\n      }\n    ]\n  }\n}\n"
  },
  {
    "id": "05-access-check",
    "at": "2026-09-18T14:29:30.481Z",
    "build": "null",
    "path": "/Users/imzee/projects/docs/tutorials-plan/course-content/assets/appengine-client/05-access-check.txt",
    "caption": "Sanitized transcript of actual HTTP results, displayed as text; not an application UI.",
    "callouts": [],
    "visibleText": "Two accounts: list filtering and direct record access differ\nActual local API results — 18 September 2026\nSelected response fields; credentials omitted.\n\n{\n  \"Lina customer list\": {\n    \"status\": 200,\n    \"total\": 1\n  },\n  \"Kofi customer list\": {\n    \"status\": 200,\n    \"total\": 0\n  },\n  \"Kofi generic repository read of Lina training reservation\": {\n    \"status\": 200,\n    \"returnedReference\": \"Q508LI8A\",\n    \"returnedCustomer\": \"lina.events@example.invalid\"\n  },\n  \"Conclusion\": \"List filtering works in this example. Generic record access is not customer-isolated.\"\n}\n"
  },
  {
    "id": "06-update-and-retry",
    "at": "2026-09-18T14:29:30.540Z",
    "build": "null",
    "path": "/Users/imzee/projects/docs/tutorials-plan/course-content/assets/appengine-client/06-update-and-retry.txt",
    "caption": "Sanitized transcript of actual HTTP results, displayed as text; not an application UI.",
    "callouts": [],
    "visibleText": "A success status does not establish the intended result\nActual local API results — 18 September 2026\nSelected response fields; credentials omitted.\n\n{\n  \"PUT /client-data/profile\": {\n    \"status\": 200,\n    \"body\": \"\"\n  },\n  \"GET profile afterwards\": {\n    \"phone\": \"ABSENT\"\n  },\n  \"Refresh\": {\n    \"status\": 201,\n    \"body\": {\n      \"sessionIssued\": true,\n      \"renewalIssued\": false\n    }\n  },\n  \"First reservation\": \"Q508LI8A\",\n  \"Repeated identical booking POST\": {\n    \"status\": 201,\n    \"secondReference\": \"R88D6C8W\"\n  },\n  \"Conclusion\": \"Profile did not save; duplicate POST created another booking.\"\n}\n"
  },
  {
    "id": "07-auth-errors",
    "at": "2026-09-18T14:29:30.601Z",
    "build": "null",
    "path": "/Users/imzee/projects/docs/tutorials-plan/course-content/assets/appengine-client/07-auth-errors.txt",
    "caption": "Sanitized transcript of actual HTTP results, displayed as text; not an application UI.",
    "callouts": [],
    "visibleText": "Authentication errors\nActual local HTTP results — 18 September 2026\nSelected responses, credentials omitted.\n\n{\n  \"no organization\": {\n    \"status\": 400,\n    \"body\": {\n      \"code\": \"missing_orgid\",\n      \"statusCode\": 400,\n      \"error\": \"Organization ID is required. Pass orgid as a header, query param, or body field.\",\n      \"path\": \"/\",\n      \"method\": \"GET\",\n      \"timeStamp\": \"2026-09-18T14:22:52.545Z\"\n    }\n  },\n  \"no credentials\": {\n    \"status\": 401,\n    \"body\": {\n      \"code\": \"missing_authorization_header\",\n      \"statusCode\": 401,\n      \"error\": \"Authorization header is required. Send requests with `Authorization: Bearer <token>`.\",\n      \"path\": \"/client-data/reservations\",\n      \"method\": \"GET\",\n      \"timeStamp\": \"2026-09-18T14:22:52.547Z\"\n    }\n  },\n  \"malformed credential\": {\n    \"status\": 401,\n    \"body\": {\n      \"code\": \"invalid_token\",\n      \"action\": \"refresh_token\",\n      \"statusCode\": 401,\n      \"error\": \"Token is invalid or malformed.\",\n      \"path\": \"/client-data/reservations\",\n      \"method\": \"GET\",\n      \"timeStamp\": \"2026-09-18T14:29:29.917Z\"\n    }\n  }\n}"
  },
  {
    "id": "08-two-bookings",
    "at": "2026-09-18T14:29:32.064Z",
    "build": "http://localhost:3102",
    "path": "/app/reservations",
    "caption": "Reloaded staff board after a repeated POST created a second training booking.",
    "callouts": [],
    "visibleText": "Select an option\nPhone\nChat\nAI Agent\nWhat's this?\nSupport\nReport a Bug\n1\n\n1 waiting on you\n\nOpen Approvals\nReservations\n\nManage reservations, service points, and booking schedules\n\nReservations\nReservation Definitions\nService Points\nCalendar\n2\nTotal\n0\nToday\n2\nUpcoming\n$0\nRevenue\nNew Reservation\nPipeline\nList\nFilter\nRefresh\nNew\n2\nLina Tutorial\n\n6f5c916b\n\nDesign consultation\nOct 5\n10:00 AM\nlina.events@example.invalid\n1 guests\nCHANGE STATUS\nNew\nConfirmed\nPending\nCancelled\nCompleted\nLina Tutorial\n\n6f5c9155\n\nDesign consultation\nOct 5\n10:00 AM\nlina.events@example.invalid\n1 guests\nCHANGE STATUS\nNew\nConfirmed\nPending\nCancelled\nCompleted\nConfirmed\n0\nNo reservations\nPending\n0\nNo reservations\nCancelled\n0\nNo reservations\nCompleted\n0\nNo reservations"
  }
]
