{"openapi": "3.1.0", "info": {"title": "The Board API", "version": "1.0.0", "description": "A self-modifying feature board API"}, "paths": {"/api/features": {"get": {"operationId": "api_features_list", "summary": "Features List", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/FeaturesListResponse"}}}}}, "description": "List pending features ordered by popularity and implemented features chronologically."}}, "/api/features/create": {"post": {"operationId": "api_feature_create", "summary": "Feature Create", "parameters": [], "responses": {"201": {"description": "Created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/FeatureCreateResponse"}}}}}, "description": "Create a new feature or variation.", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/FeatureCreateInput"}}}, "required": true}, "security": [{"SessionAuth": []}]}}, "/api/features/{pk}": {"get": {"operationId": "api_feature_detail", "summary": "Feature Detail", "parameters": [{"in": "path", "name": "pk", "schema": {"title": "Pk", "type": "integer"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/FeatureDetailResponse"}}}}}, "description": "Get a single feature with its variations."}}, "/api/features/{pk}/delete": {"post": {"operationId": "api_feature_delete", "summary": "Feature Delete", "parameters": [{"in": "path", "name": "pk", "schema": {"title": "Pk", "type": "integer"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MessageResponse"}}}}}, "description": "Delete a feature (only by its creator).", "security": [{"SessionAuth": []}]}}, "/api/features/{pk}/vote": {"post": {"operationId": "api_vote_toggle", "summary": "Vote Toggle", "parameters": [{"in": "path", "name": "pk", "schema": {"title": "Pk", "type": "integer"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/VoteToggleResponse"}}}}}, "description": "Toggle a vote on a feature (requires Turnstile verification in production).", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/VoteToggleInput"}}}, "required": true}, "security": [{"SessionAuth": []}]}}, "/api/easter-eggs/claim": {"post": {"operationId": "api_neon_egg_claim", "summary": "Claim Neon Egg", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/NeonEggClaimResponse"}}}}}, "description": "Claim a neon egg to award an extra vote to a feature.", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/NeonEggClaimInput"}}}, "required": true}, "security": [{"SessionAuth": []}]}}, "/api/auth/login": {"post": {"operationId": "api_login", "summary": "Auth Login", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LoginResponse"}}}}}, "description": "Authenticate a user.", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/LoginInput"}}}, "required": true}}}, "/api/auth/logout": {"post": {"operationId": "api_logout", "summary": "Auth Logout", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MessageResponse"}}}}}, "description": "Log out the current user."}}, "/api/auth/signup": {"post": {"operationId": "api_signup", "summary": "Auth Signup", "parameters": [], "responses": {"201": {"description": "Created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SignupResponse"}}}}}, "description": "Register a new user account.", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/SignupInput"}}}, "required": true}}}, "/api/auth/me": {"get": {"operationId": "api_current_user", "summary": "Current User", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CurrentUserResponse"}}}}}, "description": "Get the current authenticated user.", "security": [{"SessionAuth": []}]}}, "/api/web5": {"get": {"operationId": "api_web5_status", "summary": "Web5 Status", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Web5StatusResponse"}}}}}, "description": "Return the latest Web 5.0 treasury totals."}}, "/api/web5/invest": {"post": {"operationId": "api_web5_invest", "summary": "Web5 Invest", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Web5InvestmentResponse"}}}}}, "description": "Invest a slice of the user's balance into Web 5.0.", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Web5InvestmentInput"}}}, "required": true}, "security": [{"SessionAuth": []}]}}, "/api/top": {"get": {"operationId": "api_top", "summary": "Top Feature", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/FeatureDetailResponse"}}}}}, "description": "Return the highest-rated feature as JSON."}}}, "components": {"schemas": {"FeatureSchema": {"description": "Feature representation in list views.", "properties": {"id": {"title": "Id", "type": "integer"}, "title": {"title": "Title", "type": "string"}, "description": {"title": "Description", "type": "string"}, "created_at": {"format": "date-time", "title": "Created At", "type": "string"}, "implemented_at": {"anyOf": [{"format": "date-time", "type": "string"}, {"type": "null"}], "title": "Implemented At"}, "implemented_state": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Implemented State"}, "implementation_commit_url": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Implementation Commit Url"}, "implementation_failure_notes": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Implementation Failure Notes"}, "creator": {"$ref": "#/components/schemas/UserSchema"}, "vote_total": {"title": "Vote Total", "type": "integer"}, "bonus_votes": {"title": "Bonus Votes", "type": "integer"}, "user_has_voted": {"title": "User Has Voted", "type": "boolean"}, "parent": {"anyOf": [{"$ref": "#/components/schemas/ParentFeatureSchema"}, {"type": "null"}]}, "variation_count": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Variation Count"}, "last_upvote_at": {"anyOf": [{"format": "date-time", "type": "string"}, {"type": "null"}], "title": "Last Upvote At"}, "expired_at": {"anyOf": [{"format": "date-time", "type": "string"}, {"type": "null"}], "title": "Expired At"}, "expires_at": {"anyOf": [{"format": "date-time", "type": "string"}, {"type": "null"}], "title": "Expires At"}}, "required": ["id", "title", "description", "created_at", "creator", "vote_total", "bonus_votes", "user_has_voted"], "title": "FeatureSchema", "type": "object"}, "FeaturesListResponse": {"description": "Response for features list endpoint.", "properties": {"features": {"items": {"$ref": "#/components/schemas/FeatureSchema"}, "title": "Features", "type": "array"}, "implemented_features": {"items": {"$ref": "#/components/schemas/FeatureSchema"}, "title": "Implemented Features", "type": "array"}, "graveyard_features": {"items": {"$ref": "#/components/schemas/FeatureSchema"}, "title": "Graveyard Features", "type": "array"}, "can_submit": {"title": "Can Submit", "type": "boolean"}, "user": {"anyOf": [{"$ref": "#/components/schemas/UserSchema"}, {"type": "null"}]}, "next_iteration_at": {"anyOf": [{"format": "date-time", "type": "string"}, {"type": "null"}], "title": "Next Iteration At"}}, "required": ["features", "implemented_features", "graveyard_features", "can_submit", "user"], "title": "FeaturesListResponse", "type": "object"}, "ParentFeatureSchema": {"description": "Minimal parent feature representation.", "properties": {"id": {"title": "Id", "type": "integer"}, "title": {"title": "Title", "type": "string"}}, "required": ["id", "title"], "title": "ParentFeatureSchema", "type": "object"}, "UserSchema": {"description": "User representation in API responses.", "properties": {"id": {"title": "Id", "type": "integer"}, "username": {"title": "Username", "type": "string"}, "display_name": {"title": "Display Name", "type": "string"}, "avatar_url": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Avatar Url"}, "status": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Status"}, "is_superuser": {"title": "Is Superuser", "type": "boolean"}, "balance": {"title": "Balance", "type": "integer"}, "web5_invested": {"title": "Web5 Invested", "type": "integer"}, "last_daily_bonus_at": {"anyOf": [{"format": "date-time", "type": "string"}, {"type": "null"}], "title": "Last Daily Bonus At"}, "next_daily_bonus_at": {"anyOf": [{"format": "date-time", "type": "string"}, {"type": "null"}], "title": "Next Daily Bonus At"}, "daily_bonus_available": {"title": "Daily Bonus Available", "type": "boolean"}, "daily_bonus_amount": {"title": "Daily Bonus Amount", "type": "integer"}}, "required": ["id", "username", "display_name", "is_superuser", "balance", "web5_invested", "daily_bonus_available", "daily_bonus_amount"], "title": "UserSchema", "type": "object"}, "FeatureCreateResponse": {"description": "Response for feature creation.", "properties": {"feature": {"$ref": "#/components/schemas/FeatureSchema"}, "message": {"title": "Message", "type": "string"}}, "required": ["feature", "message"], "title": "FeatureCreateResponse", "type": "object"}, "FeatureCreateInput": {"description": "Input for creating a new feature or variation.", "properties": {"title": {"title": "Title", "type": "string"}, "description": {"title": "Description", "type": "string"}, "parent_id": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Parent Id"}, "turnstile_token": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Turnstile Token"}}, "required": ["title", "description"], "title": "FeatureCreateInput", "type": "object"}, "FeatureDetailResponse": {"description": "Response for feature detail endpoint.", "properties": {"feature": {"$ref": "#/components/schemas/FeatureSchema"}, "variations": {"items": {"$ref": "#/components/schemas/FeatureSchema"}, "title": "Variations", "type": "array"}, "can_submit_variation": {"title": "Can Submit Variation", "type": "boolean"}, "user": {"anyOf": [{"$ref": "#/components/schemas/UserSchema"}, {"type": "null"}]}}, "required": ["feature", "variations", "can_submit_variation", "user"], "title": "FeatureDetailResponse", "type": "object"}, "MessageResponse": {"description": "Generic message response.", "properties": {"message": {"title": "Message", "type": "string"}}, "required": ["message"], "title": "MessageResponse", "type": "object"}, "VoteToggleResponse": {"description": "Response for vote toggle endpoint.", "properties": {"action": {"title": "Action", "type": "string"}, "has_voted": {"title": "Has Voted", "type": "boolean"}, "vote_total": {"title": "Vote Total", "type": "integer"}}, "required": ["action", "has_voted", "vote_total"], "title": "VoteToggleResponse", "type": "object"}, "VoteToggleInput": {"description": "Input for vote toggle (with optional Turnstile token).", "properties": {"turnstile_token": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Turnstile Token"}}, "title": "VoteToggleInput", "type": "object"}, "NeonEggClaimResponse": {"description": "Response after claiming a neon egg.", "properties": {"message": {"title": "Message", "type": "string"}, "feature": {"$ref": "#/components/schemas/FeatureSchema"}, "already_claimed": {"title": "Already Claimed", "type": "boolean"}}, "required": ["message", "feature", "already_claimed"], "title": "NeonEggClaimResponse", "type": "object"}, "NeonEggClaimInput": {"description": "Input for claiming a neon egg bonus vote.", "properties": {"egg_key": {"title": "Egg Key", "type": "string"}, "feature_id": {"title": "Feature Id", "type": "integer"}, "turnstile_token": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Turnstile Token"}}, "required": ["egg_key", "feature_id"], "title": "NeonEggClaimInput", "type": "object"}, "LoginResponse": {"description": "Response for login endpoint.", "properties": {"message": {"title": "Message", "type": "string"}, "user": {"$ref": "#/components/schemas/UserSchema"}, "daily_bonus_awarded": {"title": "Daily Bonus Awarded", "type": "boolean"}, "daily_bonus_amount": {"title": "Daily Bonus Amount", "type": "integer"}}, "required": ["message", "user", "daily_bonus_awarded", "daily_bonus_amount"], "title": "LoginResponse", "type": "object"}, "LoginInput": {"description": "Input for user login.", "properties": {"username": {"title": "Username", "type": "string"}, "password": {"title": "Password", "type": "string"}}, "required": ["username", "password"], "title": "LoginInput", "type": "object"}, "SignupResponse": {"description": "Response for signup endpoint.", "properties": {"message": {"title": "Message", "type": "string"}, "user": {"$ref": "#/components/schemas/UserSchema"}, "daily_bonus_awarded": {"title": "Daily Bonus Awarded", "type": "boolean"}, "daily_bonus_amount": {"title": "Daily Bonus Amount", "type": "integer"}}, "required": ["message", "user", "daily_bonus_awarded", "daily_bonus_amount"], "title": "SignupResponse", "type": "object"}, "SignupInput": {"description": "Input for user registration.", "properties": {"username": {"title": "Username", "type": "string"}, "password": {"title": "Password", "type": "string"}, "password_confirm": {"title": "Password Confirm", "type": "string"}}, "required": ["username", "password", "password_confirm"], "title": "SignupInput", "type": "object"}, "CurrentUserResponse": {"description": "Response for current user endpoint.", "properties": {"user": {"$ref": "#/components/schemas/UserSchema"}, "can_submit": {"title": "Can Submit", "type": "boolean"}}, "required": ["user", "can_submit"], "title": "CurrentUserResponse", "type": "object"}, "Web5StatusResponse": {"description": "Read-only snapshot of Web 5.0 fund totals.", "properties": {"total_committed": {"title": "Total Committed", "type": "integer"}, "user_committed": {"title": "User Committed", "type": "integer"}, "balance": {"title": "Balance", "type": "integer"}}, "required": ["total_committed", "user_committed", "balance"], "title": "Web5StatusResponse", "type": "object"}, "Web5InvestmentResponse": {"description": "Response after investing in Web 5.0.", "properties": {"message": {"title": "Message", "type": "string"}, "total_committed": {"title": "Total Committed", "type": "integer"}, "user_committed": {"title": "User Committed", "type": "integer"}, "balance": {"title": "Balance", "type": "integer"}}, "required": ["message", "total_committed", "user_committed", "balance"], "title": "Web5InvestmentResponse", "type": "object"}, "Web5InvestmentInput": {"description": "Input payload for Web 5.0 investment.", "properties": {"amount": {"title": "Amount", "type": "integer"}}, "required": ["amount"], "title": "Web5InvestmentInput", "type": "object"}}, "securitySchemes": {"SessionAuth": {"type": "apiKey", "in": "cookie", "name": "sessionid"}}}, "servers": []}