{"openapi":"3.0.3","info":{"title":"Dogfood API","description":"API of the Arkadium dogfood game-playtesting portal.","version":"0.1.0"},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"def-0":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"}},"required":["id","name","email"],"title":"User"},"def-1":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string"},"version":{"type":"integer","minimum":1},"url":{"type":"string","format":"uri"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","version","url","createdAt"],"title":"GameVersion"},"def-2":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string"},"gameId":{"type":"string"},"gameVersionId":{"type":"string"},"resolvedInVersionId":{"type":"string","nullable":true},"author":{"$ref":"#/components/schemas/def-0"},"rating":{"type":"integer","minimum":1,"maximum":10},"comment":{"type":"string"},"status":{"type":"string","enum":["open","resolved","wont_fix"]},"createdAt":{"type":"string","format":"date-time"}},"required":["id","gameId","gameVersionId","resolvedInVersionId","author","rating","comment","status","createdAt"],"title":"Feedback"},"def-3":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"thumbnailUrl":{"type":"string","nullable":true},"author":{"$ref":"#/components/schemas/def-0"},"versions":{"type":"array","items":{"$ref":"#/components/schemas/def-1"}},"latestVersion":{"anyOf":[{"$ref":"#/components/schemas/def-1"},{"type":"object","nullable":true,"enum":[null]}]},"averageRating":{"type":"number","nullable":true},"ratingsCount":{"type":"integer","minimum":0},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","description","thumbnailUrl","author","versions","latestVersion","averageRating","ratingsCount","createdAt"],"title":"Game"},"def-4":{"type":"object","additionalProperties":false,"properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}},"required":["statusCode","error","message"],"title":"ErrorResponse"},"def-5":{"type":"object","additionalProperties":false,"properties":{"gameId":{"type":"string"},"version":{"$ref":"#/components/schemas/def-1"},"resolvedFeedbackIds":{"type":"array","items":{"type":"string"}}},"required":["gameId","version","resolvedFeedbackIds"],"title":"PublishVersionResult"},"def-6":{"type":"object","additionalProperties":false,"properties":{"device_code":{"type":"string"},"user_code":{"type":"string"},"verification_uri":{"type":"string"},"expires_in":{"type":"integer"},"message":{"type":"string"}},"required":["device_code","user_code","verification_uri","expires_in","message"],"title":"DeviceCodeStartResponse"},"def-7":{"type":"object","oneOf":[{"type":"object","properties":{"status":{"enum":["pending"]}},"required":["status"],"additionalProperties":false},{"type":"object","properties":{"status":{"enum":["expired"]}},"required":["status"],"additionalProperties":false},{"type":"object","properties":{"access_token":{"type":"string"}},"required":["access_token"],"additionalProperties":false}],"title":"DevicePollResponse"},"def-8":{"type":"object","additionalProperties":false,"properties":{"status":{"type":"string","enum":["ok"]}},"required":["status"],"title":"HealthResponse"}}},"paths":{"/auth/device/start":{"post":{"summary":"Start a device code login","tags":["auth"],"description":"Initiates the OAuth 2.0 device authorization grant. Poll `/auth/device/poll` until it returns an access token.","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-6"}}}},"4XX":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-4"}}}},"5XX":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-4"}}}}}}},"/auth/device/poll":{"post":{"summary":"Poll for a device code access token","tags":["auth"],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-7"}}}},"4XX":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-4"}}}}}}},"/me":{"get":{"summary":"Get the current user","tags":["me"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-0"}}}},"4XX":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-4"}}}}}}},"/me/games":{"get":{"summary":"List games authored by the current user","tags":["me"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/def-3"}}}}},"4XX":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-4"}}}}}},"post":{"summary":"Create a game","tags":["me"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string","minLength":1,"maxLength":100},"description":{"type":"string","maxLength":2000,"default":""}},"required":["name"]}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-3"}}}},"4XX":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-4"}}}}}}},"/me/games/{id}":{"put":{"summary":"Publish a new game version","tags":["me"],"description":"Body is a raw .zip archive (application/zip or application/octet-stream, max 50MB) containing index.html at its root. Files are served from the blob container under <gameId>/<versionNumber>/.","parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-5"}}}},"4XX":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-4"}}}}}}},"/me/games/{id}/thumbnail":{"post":{"summary":"Upload a game thumbnail","tags":["me"],"description":"Body is a raw png/jpeg/webp image (max 5MB). Returns the updated game.","parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-3"}}}},"4XX":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-4"}}}}}}},"/me/games/{id}/feedback":{"get":{"summary":"List all feedback for an owned game (any status)","tags":["feedback"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/def-2"}}}}},"4XX":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-4"}}}}}}},"/me/games/{gameId}/feedback/{feedbackId}":{"patch":{"summary":"Set feedback status (game author only)","tags":["feedback"],"description":"Only the game author may set a status. When 'resolved', the feedback is marked as resolved in the game's latest version.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"status":{"type":"string","enum":["resolved","wont_fix"]}},"required":["status"]}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"gameId","required":true},{"schema":{"type":"string"},"in":"path","name":"feedbackId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-2"}}}},"4XX":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-4"}}}}}}},"/me/games/{gameId}/feedback/{feedbackId}/reopen":{"post":{"summary":"Reopen feedback (feedback author only)","tags":["feedback"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"gameId","required":true},{"schema":{"type":"string"},"in":"path","name":"feedbackId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-2"}}}},"4XX":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-4"}}}}}}},"/games":{"get":{"summary":"List published games","tags":["games"],"description":"Sorted by latest version (`new`, default) or by average rating (`top`). Paginated with `limit` (max 50) and `offset`.","parameters":[{"schema":{"type":"string","enum":["new","top"],"default":"new"},"in":"query","name":"sort","required":false},{"schema":{"type":"integer","minimum":1,"maximum":50,"default":20},"in":"query","name":"limit","required":false},{"schema":{"type":"integer","minimum":0,"default":0},"in":"query","name":"offset","required":false}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/def-3"}}}}},"4XX":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-4"}}}}}}},"/games/{id}":{"get":{"summary":"Get a single game","tags":["games"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-3"}}}},"4XX":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-4"}}}}}}},"/games/{id}/feedback":{"post":{"summary":"Submit feedback for a game","tags":["feedback"],"description":"Rating 1-10 and a comment (max 2000 chars). One feedback per user per game — re-posting updates the existing feedback and resets its status to 'open'. The game author cannot review their own game. Feedback is attached to the game's latest version.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"rating":{"type":"integer","minimum":1,"maximum":10},"comment":{"type":"string","maxLength":2000,"default":""}},"required":["rating"]}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-2"}}}},"4XX":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-4"}}}}}},"get":{"summary":"List public feedback for a game","tags":["feedback"],"description":"Returns open feedback plus feedback attached to (or resolved in) the game's latest version. wont_fix feedback is hidden.","parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/def-2"}}}}},"4XX":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-4"}}}}}}},"/health":{"get":{"summary":"Liveness probe","tags":["health"],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/def-8"}}}}}}}},"servers":[{"url":"https://dogfood.internal-aks-dev.arkadiumhosted.com/api"}],"tags":[{"name":"auth","description":"Authentication (device code flow for CLIs/agents)"},{"name":"me","description":"Current user, owned games, publishing"},{"name":"games","description":"Public game catalog"},{"name":"feedback","description":"Game feedback"},{"name":"health","description":"Health checks"}]}