// Package docs Code generated by swaggo/swag. DO NOT EDIT package docs import "github.com/swaggo/swag" const docTemplate = `{ "schemes": {{ marshal .Schemes }}, "swagger": "2.0", "info": { "description": "{{escape .Description}}", "title": "{{.Title}}", "termsOfService": "http://swagger.io/terms/", "contact": { "name": "API Support", "url": "https://github.com/davidfolch/apocapoc-api", "email": "contact@apocapoc.app" }, "license": { "name": "MIT", "url": "https://opensource.org/licenses/MIT" }, "version": "{{.Version}}" }, "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { "/auth/login": { "post": { "description": "Authenticate user with email and password. Returns both access token and refresh token. The access token is used for API requests, the refresh token is used to obtain new access tokens when they expire.", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "auth" ], "summary": "Login user", "parameters": [ { "description": "Login credentials", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/http.LoginRequest" } } ], "responses": { "200": { "description": "Returns access token, refresh token, and user ID", "schema": { "$ref": "#/definitions/http.AuthResponse" } }, "400": { "description": "Invalid request body", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "401": { "description": "Invalid email or password", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "500": { "description": "Internal server error", "schema": { "$ref": "#/definitions/http.ErrorResponse" } } } } }, "/auth/logout": { "post": { "description": "Revoke the refresh token to invalidate the user session. After logout, the refresh token cannot be used to obtain new access tokens. The user will need to login again. Always call this endpoint before clearing tokens from client storage to ensure proper session termination.", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "auth" ], "summary": "Logout user", "parameters": [ { "description": "Refresh token to revoke", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/http.LogoutRequest" } } ], "responses": { "200": { "description": "Successfully logged out - the refresh token is now invalid", "schema": { "type": "object", "additionalProperties": { "type": "string" } } }, "400": { "description": "Invalid request body or missing refresh token", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "404": { "description": "Refresh token not found (already revoked or never existed)", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "500": { "description": "Internal server error", "schema": { "$ref": "#/definitions/http.ErrorResponse" } } } } }, "/auth/refresh": { "post": { "description": "Exchange a valid refresh token for a new access token and refresh token pair. IMPORTANT: The old refresh token is automatically revoked and you receive a NEW refresh token - always update both tokens in storage. Use this endpoint when the access token expires to maintain the user session without requiring re-login.", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "auth" ], "summary": "Refresh access token", "parameters": [ { "description": "Current refresh token", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/http.RefreshRequest" } } ], "responses": { "200": { "description": "Returns NEW access token and NEW refresh token - the old refresh token is now invalid", "schema": { "$ref": "#/definitions/http.AuthResponse" } }, "400": { "description": "Invalid request body", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "401": { "description": "Invalid or expired refresh token", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "500": { "description": "Internal server error", "schema": { "$ref": "#/definitions/http.ErrorResponse" } } } } }, "/auth/register": { "post": { "description": "Create a new user account and receive both access token and refresh token. Store both tokens securely - the refresh token is used to obtain new access tokens when they expire.", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "auth" ], "summary": "Register a new user", "parameters": [ { "description": "Registration data (password requires: min 8 chars, uppercase, lowercase, digit, special char)", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/http.RegisterRequest" } } ], "responses": { "201": { "description": "Returns access token, refresh token, and user ID", "schema": { "$ref": "#/definitions/http.AuthResponse" } }, "400": { "description": "Invalid input: email format, password requirements, or timezone", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "409": { "description": "Email already registered", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "500": { "description": "Internal server error", "schema": { "$ref": "#/definitions/http.ErrorResponse" } } } } }, "/habits": { "get": { "security": [ { "BearerAuth": [] } ], "description": "Get all active habits for the authenticated user", "produces": [ "application/json" ], "tags": [ "habits" ], "summary": "Get all user habits", "responses": { "200": { "description": "OK", "schema": { "type": "array", "items": { "$ref": "#/definitions/http.UserHabitResponse" } } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/http.ErrorResponse" } } } }, "post": { "security": [ { "BearerAuth": [] } ], "description": "Create a new habit for the authenticated user", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "habits" ], "summary": "Create a new habit", "parameters": [ { "description": "Habit data", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/http.CreateHabitRequest" } } ], "responses": { "201": { "description": "Created", "schema": { "type": "object", "additionalProperties": { "type": "string" } } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/http.ErrorResponse" } } } } }, "/habits/today": { "get": { "security": [ { "BearerAuth": [] } ], "description": "Get all habits scheduled for today for the authenticated user", "produces": [ "application/json" ], "tags": [ "habits" ], "summary": "Get today's habits", "responses": { "200": { "description": "OK", "schema": { "type": "array", "items": { "$ref": "#/definitions/http.TodaysHabitResponse" } } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/http.ErrorResponse" } } } } }, "/habits/{id}": { "get": { "security": [ { "BearerAuth": [] } ], "description": "Get a specific habit by ID", "produces": [ "application/json" ], "tags": [ "habits" ], "summary": "Get habit by ID", "parameters": [ { "type": "string", "description": "Habit ID", "name": "id", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/http.UserHabitResponse" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/http.ErrorResponse" } } } }, "put": { "security": [ { "BearerAuth": [] } ], "description": "Update an existing habit", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "habits" ], "summary": "Update habit", "parameters": [ { "type": "string", "description": "Habit ID", "name": "id", "in": "path", "required": true }, { "description": "Update data", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/http.UpdateHabitRequest" } } ], "responses": { "200": { "description": "OK", "schema": { "type": "object", "additionalProperties": { "type": "string" } } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/http.ErrorResponse" } } } }, "delete": { "security": [ { "BearerAuth": [] } ], "description": "Archive (soft delete) a habit", "produces": [ "application/json" ], "tags": [ "habits" ], "summary": "Archive habit", "parameters": [ { "type": "string", "description": "Habit ID", "name": "id", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "type": "object", "additionalProperties": { "type": "string" } } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/http.ErrorResponse" } } } } }, "/habits/{id}/entries": { "get": { "security": [ { "BearerAuth": [] } ], "description": "Get entries (completion history) for a habit with optional date filtering and pagination", "produces": [ "application/json" ], "tags": [ "habits" ], "summary": "Get habit entries", "parameters": [ { "type": "string", "description": "Habit ID", "name": "id", "in": "path", "required": true }, { "type": "string", "description": "Start date (YYYY-MM-DD)", "name": "from", "in": "query" }, { "type": "string", "description": "End date (YYYY-MM-DD)", "name": "to", "in": "query" }, { "type": "integer", "description": "Page number", "name": "page", "in": "query" }, { "type": "integer", "description": "Page size (max 100)", "name": "limit", "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/http.HabitEntriesResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/http.ErrorResponse" } } } } }, "/habits/{id}/entries/{date}": { "delete": { "security": [ { "BearerAuth": [] } ], "description": "Delete a habit entry (unmark completion)", "produces": [ "application/json" ], "tags": [ "habits" ], "summary": "Unmark habit", "parameters": [ { "type": "string", "description": "Habit ID", "name": "id", "in": "path", "required": true }, { "type": "string", "description": "Date (YYYY-MM-DD)", "name": "date", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "type": "object", "additionalProperties": { "type": "string" } } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/http.ErrorResponse" } } } } }, "/habits/{id}/mark": { "post": { "security": [ { "BearerAuth": [] } ], "description": "Mark a habit as completed for a specific date", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "habits" ], "summary": "Mark habit as complete", "parameters": [ { "type": "string", "description": "Habit ID", "name": "id", "in": "path", "required": true }, { "description": "Mark data", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/http.MarkHabitRequest" } } ], "responses": { "200": { "description": "OK", "schema": { "type": "object", "additionalProperties": { "type": "string" } } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "409": { "description": "Conflict", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/http.ErrorResponse" } } } } }, "/health": { "get": { "description": "Get API health status including database connectivity and uptime", "produces": [ "application/json" ], "tags": [ "system" ], "summary": "Health check", "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/http.HealthResponse" } }, "503": { "description": "Service Unavailable", "schema": { "$ref": "#/definitions/http.HealthResponse" } } } } }, "/stats/habits/{id}": { "get": { "security": [ { "BearerAuth": [] } ], "description": "Get statistics for a specific habit including streaks and completion rates", "produces": [ "application/json" ], "tags": [ "stats" ], "summary": "Get habit statistics", "parameters": [ { "type": "string", "description": "Habit ID", "name": "id", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/queries.HabitStatsDTO" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/http.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/http.ErrorResponse" } } } } } }, "definitions": { "http.AuthResponse": { "type": "object", "properties": { "refresh_token": { "type": "string" }, "token": { "type": "string" }, "user_id": { "type": "string" } } }, "http.CreateHabitRequest": { "type": "object", "properties": { "carry_over": { "type": "boolean" }, "description": { "type": "string" }, "frequency": { "$ref": "#/definitions/value_objects.Frequency" }, "is_negative": { "type": "boolean" }, "name": { "type": "string" }, "specific_dates": { "type": "array", "items": { "type": "integer" } }, "specific_days": { "type": "array", "items": { "type": "integer" } }, "target_value": { "type": "number" }, "type": { "$ref": "#/definitions/value_objects.HabitType" } } }, "http.ErrorResponse": { "type": "object", "properties": { "error": { "type": "string" } } }, "http.HabitEntriesResponse": { "type": "object", "properties": { "entries": { "type": "array", "items": { "$ref": "#/definitions/http.HabitEntryResponse" } }, "limit": { "type": "integer" }, "page": { "type": "integer" }, "total": { "type": "integer" } } }, "http.HabitEntryResponse": { "type": "object", "properties": { "completed_at": { "type": "string" }, "habit_id": { "type": "string" }, "id": { "type": "string" }, "scheduled_date": { "type": "string" }, "value": { "type": "number" } } }, "http.HealthResponse": { "type": "object", "properties": { "database": { "type": "string" }, "status": { "type": "string" }, "uptime": { "type": "string" } } }, "http.LoginRequest": { "type": "object", "properties": { "email": { "type": "string" }, "password": { "type": "string" } } }, "http.LogoutRequest": { "type": "object", "properties": { "refresh_token": { "type": "string" } } }, "http.MarkHabitRequest": { "type": "object", "properties": { "scheduled_date": { "type": "string" }, "value": { "type": "number" } } }, "http.RefreshRequest": { "type": "object", "properties": { "refresh_token": { "type": "string" } } }, "http.RegisterRequest": { "type": "object", "properties": { "email": { "type": "string" }, "password": { "type": "string" }, "timezone": { "type": "string" } } }, "http.TodaysHabitResponse": { "type": "object", "properties": { "id": { "type": "string" }, "is_carried_over": { "type": "boolean" }, "is_negative": { "type": "boolean" }, "name": { "type": "string" }, "scheduled_date": { "type": "string" }, "target_value": { "type": "number" }, "type": { "$ref": "#/definitions/value_objects.HabitType" } } }, "http.UpdateHabitRequest": { "type": "object", "properties": { "carry_over": { "type": "boolean" }, "description": { "type": "string" }, "name": { "type": "string" }, "specific_dates": { "type": "array", "items": { "type": "integer" } }, "specific_days": { "type": "array", "items": { "type": "integer" } }, "target_value": { "type": "number" } } }, "http.UserHabitResponse": { "type": "object", "properties": { "carry_over": { "type": "boolean" }, "frequency": { "$ref": "#/definitions/value_objects.Frequency" }, "id": { "type": "string" }, "is_negative": { "type": "boolean" }, "name": { "type": "string" }, "specific_days": { "type": "array", "items": { "type": "integer" } }, "target_value": { "type": "number" }, "type": { "$ref": "#/definitions/value_objects.HabitType" } } }, "queries.HabitStatsDTO": { "type": "object", "properties": { "completion_rate": { "type": "number" }, "completions_this_month": { "type": "integer" }, "completions_this_week": { "type": "integer" }, "current_streak": { "type": "integer" }, "habit_id": { "type": "string" }, "habit_name": { "type": "string" }, "longest_streak": { "type": "integer" }, "total_completions": { "type": "integer" } } }, "value_objects.Frequency": { "type": "string", "enum": [ "DAILY", "WEEKLY", "MONTHLY" ], "x-enum-varnames": [ "FrequencyDaily", "FrequencyWeekly", "FrequencyMonthly" ] }, "value_objects.HabitType": { "type": "string", "enum": [ "BOOLEAN", "COUNTER", "VALUE" ], "x-enum-varnames": [ "HabitTypeBoolean", "HabitTypeCounter", "HabitTypeValue" ] } }, "securityDefinitions": { "BearerAuth": { "description": "Type \"Bearer\" followed by a space and JWT token.", "type": "apiKey", "name": "Authorization", "in": "header" } } }` // SwaggerInfo holds exported Swagger Info so clients can modify it var SwaggerInfo = &swag.Spec{ Version: "", Host: "", BasePath: "/api/v1", Schemes: []string{}, Title: "Apocapoc API", Description: "Self-hosted habit tracking service", InfoInstanceName: "swagger", SwaggerTemplate: docTemplate, LeftDelim: "{{", RightDelim: "}}", } func init() { swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) }