// 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}}", "contact": {}, "version": "{{.Version}}" }, "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { "/auth/login": { "post": { "description": "Login with username or email; returns a JWT (TTL from auth.token_ttl) and the user.", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "public" ], "summary": "Login", "parameters": [ { "description": "Login credentials", "name": "credentials", "in": "body", "required": true, "schema": { "$ref": "#/definitions/auth.LoginRequest" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/auth.LoginResponse" } }, "400": { "description": "invalid request", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "401": { "description": "incorrect account or password", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } } }, "/auth/register": { "post": { "description": "Public registration. Creates a regular user in the default user group (id 1). username is 3-50 chars and unique; email is unique; password is 6-72 chars.", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "public" ], "summary": "Register", "parameters": [ { "description": "Registration payload", "name": "user", "in": "body", "required": true, "schema": { "$ref": "#/definitions/auth.RegisterRequest" } } ], "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/model.User" } }, "400": { "description": "invalid request", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "409": { "description": "username or email already exists", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } } }, "/files": { "post": { "security": [ { "BearerAuth": [] } ], "description": "Upload a file (multipart field file). Content is deduplicated by sha256; the returned file has ref_count 0 until a business reference is acquired. Size limit from storage.max_size_mb.", "consumes": [ "multipart/form-data" ], "produces": [ "application/json" ], "tags": [ "user" ], "summary": "Upload a file", "parameters": [ { "type": "file", "description": "File content", "name": "file", "in": "formData", "required": true } ], "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/model.File" } }, "400": { "description": "invalid request or empty file", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "413": { "description": "file too large", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } } }, "/files/{id}": { "get": { "description": "Public file content. Images, videos, audio, PDF and plain text are served inline; other types are served as attachments. Disabled files return 404.", "produces": [ "application/octet-stream" ], "tags": [ "public" ], "summary": "Get file content", "parameters": [ { "type": "integer", "example": 1, "description": "File ID", "name": "id", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "type": "file" } }, "400": { "description": "invalid id", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "404": { "description": "record not found", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } }, "delete": { "security": [ { "BearerAuth": [] } ], "description": "Delete a file physically and keep the record with status 0; uploader or admin only. Files still referenced (ref_count \u003e 0) return 409.", "produces": [ "application/json" ], "tags": [ "user" ], "summary": "Delete a file", "parameters": [ { "type": "integer", "example": 1, "description": "File ID", "name": "id", "in": "path", "required": true } ], "responses": { "204": { "description": "Deleted" }, "400": { "description": "invalid id", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "permission denied or account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "404": { "description": "record not found", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "409": { "description": "file is in use", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } } }, "/health": { "get": { "description": "Check service and database connectivity; returns 503 when the database is unavailable.", "produces": [ "application/json" ], "tags": [ "public" ], "summary": "Health check", "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/api.HealthResponse" } }, "503": { "description": "Service Unavailable", "schema": { "$ref": "#/definitions/api.HealthResponse" } } } } }, "/me": { "get": { "security": [ { "BearerAuth": [] } ], "description": "Return the authenticated user's profile, including groups.", "produces": [ "application/json" ], "tags": [ "user" ], "summary": "Get current user profile", "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/model.User" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } }, "put": { "security": [ { "BearerAuth": [] } ], "description": "Update the authenticated user's nickname, gender, and birthday. birthday accepts YYYY-MM-DD, an empty string clears it, and omitting it keeps the current value.", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "user" ], "summary": "Update current user profile", "parameters": [ { "description": "Fields to update", "name": "profile", "in": "body", "required": true, "schema": { "$ref": "#/definitions/auth.UpdateProfileRequest" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/model.User" } }, "400": { "description": "invalid request", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } } }, "/me/avatar": { "put": { "security": [ { "BearerAuth": [] } ], "description": "Upload an image as the authenticated user's avatar (multipart field file, image only). The avatar URL is stored on the user and the file reference count is managed automatically.", "consumes": [ "multipart/form-data" ], "produces": [ "application/json" ], "tags": [ "user" ], "summary": "Update current user avatar", "parameters": [ { "type": "file", "description": "Avatar image", "name": "file", "in": "formData", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/model.User" } }, "400": { "description": "invalid request, empty file, or not an image", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "413": { "description": "file too large", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } }, "delete": { "security": [ { "BearerAuth": [] } ], "description": "Clear the authenticated user's avatar and release the file reference when it points to a local file.", "produces": [ "application/json" ], "tags": [ "user" ], "summary": "Delete current user avatar", "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/model.User" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } } }, "/nav-links": { "get": { "description": "Public site navigation links (header and footer, status enabled), ordered by sort ASC then id ASC, with translations and position.", "produces": [ "application/json" ], "tags": [ "public" ], "summary": "List nav links", "responses": { "200": { "description": "OK", "schema": { "type": "array", "items": { "$ref": "#/definitions/model.NavLink" } } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } }, "post": { "security": [ { "BearerAuth": [] } ], "description": "Admin only. Create a site navigation link (position: header or footer, defaults to header). url accepts site-relative paths (/...), http(s) URLs, and mailto links; translations must include at least one non-empty label.", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "admin" ], "summary": "Create a nav link", "parameters": [ { "description": "Nav link payload", "name": "link", "in": "body", "required": true, "schema": { "$ref": "#/definitions/nav.Request" } } ], "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/model.NavLink" } }, "400": { "description": "invalid request", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "admin permission required or account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } } }, "/nav-links/list": { "get": { "security": [ { "BearerAuth": [] } ], "description": "Admin only. List all site navigation links including disabled ones, with translations.", "produces": [ "application/json" ], "tags": [ "admin" ], "summary": "List all nav links", "responses": { "200": { "description": "OK", "schema": { "type": "array", "items": { "$ref": "#/definitions/model.NavLink" } } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "admin permission required or account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } } }, "/nav-links/{id}": { "put": { "security": [ { "BearerAuth": [] } ], "description": "Admin only. Update a site navigation link; position is kept when omitted; translations are replaced by the provided list.", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "admin" ], "summary": "Update a nav link", "parameters": [ { "type": "integer", "example": 1, "description": "Nav link ID", "name": "id", "in": "path", "required": true }, { "description": "Nav link payload", "name": "link", "in": "body", "required": true, "schema": { "$ref": "#/definitions/nav.Request" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/model.NavLink" } }, "400": { "description": "invalid request or id", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "admin permission required or account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "404": { "description": "record not found", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } }, "delete": { "security": [ { "BearerAuth": [] } ], "description": "Admin only. Delete a site navigation link and its translations.", "produces": [ "application/json" ], "tags": [ "admin" ], "summary": "Delete a nav link", "parameters": [ { "type": "integer", "example": 1, "description": "Nav link ID", "name": "id", "in": "path", "required": true } ], "responses": { "204": { "description": "Deleted" }, "400": { "description": "invalid id", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "admin permission required or account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "404": { "description": "record not found", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } } }, "/notes": { "get": { "security": [ { "BearerAuth": [] } ], "description": "List notes ordered by id DESC. page starts at 1; page_size is 1-100, default 20.", "produces": [ "application/json" ], "tags": [ "user" ], "summary": "List notes", "parameters": [ { "type": "integer", "example": 1, "description": "Page number, default 1", "name": "page", "in": "query" }, { "type": "integer", "example": 20, "description": "Page size, default 20, max 100", "name": "page_size", "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/note.ListResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } }, "post": { "security": [ { "BearerAuth": [] } ], "description": "Create a note. title is required (max 200 chars); content is optional.", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "user" ], "summary": "Create a note", "parameters": [ { "description": "Note payload", "name": "note", "in": "body", "required": true, "schema": { "$ref": "#/definitions/note.Request" } } ], "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/model.Note" } }, "400": { "description": "invalid request", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } } }, "/notes/{id}": { "get": { "security": [ { "BearerAuth": [] } ], "description": "Get a note by id.", "produces": [ "application/json" ], "tags": [ "user" ], "summary": "Get a note", "parameters": [ { "type": "integer", "example": 1, "description": "Note ID", "name": "id", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/model.Note" } }, "400": { "description": "invalid id", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "404": { "description": "record not found", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } }, "put": { "security": [ { "BearerAuth": [] } ], "description": "Update title and content; validation is the same as create.", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "user" ], "summary": "Update a note", "parameters": [ { "type": "integer", "example": 1, "description": "Note ID", "name": "id", "in": "path", "required": true }, { "description": "Note payload", "name": "note", "in": "body", "required": true, "schema": { "$ref": "#/definitions/note.Request" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/model.Note" } }, "400": { "description": "invalid request or id", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "404": { "description": "record not found", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } }, "delete": { "security": [ { "BearerAuth": [] } ], "description": "Delete a note by id; returns 204 with no body on success.", "produces": [ "application/json" ], "tags": [ "user" ], "summary": "Delete a note", "parameters": [ { "type": "integer", "example": 1, "description": "Note ID", "name": "id", "in": "path", "required": true } ], "responses": { "204": { "description": "Deleted" }, "400": { "description": "invalid id", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "404": { "description": "record not found", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } } }, "/site": { "get": { "description": "Public site settings: site name, logo URL, favicon URL, and footer text. Returns built-in defaults when the settings row is missing.", "produces": [ "application/json" ], "tags": [ "public" ], "summary": "Get site settings", "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/model.SiteSetting" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } }, "put": { "security": [ { "BearerAuth": [] } ], "description": "Admin only. Update the site name, logo URL, favicon URL, and footer text; logo and favicon files hosted on this site have their reference count managed automatically. Returns the updated settings.", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "admin" ], "summary": "Update site settings", "parameters": [ { "description": "Site settings", "name": "site", "in": "body", "required": true, "schema": { "$ref": "#/definitions/site.UpdateRequest" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/model.SiteSetting" } }, "400": { "description": "invalid request or file not found", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "admin permission required or account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } } }, "/site/favicon": { "put": { "security": [ { "BearerAuth": [] } ], "description": "Admin only. Upload an image (raster or SVG) as the site favicon (multipart field file); takes effect immediately and file references are managed automatically. SVG is served inline with a restrictive Content-Security-Policy.", "consumes": [ "multipart/form-data" ], "produces": [ "application/json" ], "tags": [ "admin" ], "summary": "Upload site favicon", "parameters": [ { "type": "file", "description": "Favicon image", "name": "file", "in": "formData", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/model.SiteSetting" } }, "400": { "description": "invalid request, empty file, or not an image", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "admin permission required or account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "413": { "description": "file too large", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } }, "delete": { "security": [ { "BearerAuth": [] } ], "description": "Admin only. Clear the site favicon and release the reference of the locally stored favicon file.", "produces": [ "application/json" ], "tags": [ "admin" ], "summary": "Delete site favicon", "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/model.SiteSetting" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "admin permission required or account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } } }, "/site/logo": { "put": { "security": [ { "BearerAuth": [] } ], "description": "Admin only. Upload a raster image as the site logo (multipart field file); the logo takes effect immediately and file references are managed automatically.", "consumes": [ "multipart/form-data" ], "produces": [ "application/json" ], "tags": [ "admin" ], "summary": "Upload site logo", "parameters": [ { "type": "file", "description": "Logo image", "name": "file", "in": "formData", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/model.SiteSetting" } }, "400": { "description": "invalid request, empty file, or not an image", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "admin permission required or account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "413": { "description": "file too large", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } }, "delete": { "security": [ { "BearerAuth": [] } ], "description": "Admin only. Clear the site logo and release the reference of the locally stored logo file.", "produces": [ "application/json" ], "tags": [ "admin" ], "summary": "Delete site logo", "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/model.SiteSetting" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "admin permission required or account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } } }, "/user-groups": { "get": { "security": [ { "BearerAuth": [] } ], "description": "List user groups ordered by id ASC. page starts at 1; page_size is 1-100, default 20.", "produces": [ "application/json" ], "tags": [ "admin" ], "summary": "List user groups", "parameters": [ { "type": "integer", "example": 1, "description": "Page number, default 1", "name": "page", "in": "query" }, { "type": "integer", "example": 20, "description": "Page size, default 20, max 100", "name": "page_size", "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/usergroup.ListResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "admin permission required or account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } }, "post": { "security": [ { "BearerAuth": [] } ], "description": "Create a user group. name is required and unique (max 50 chars); description is optional (max 255 chars); id is assigned by the server.", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "admin" ], "summary": "Create a user group", "parameters": [ { "description": "User group payload", "name": "group", "in": "body", "required": true, "schema": { "$ref": "#/definitions/usergroup.Request" } } ], "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/model.UserGroup" } }, "400": { "description": "invalid request", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "admin permission required or account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "409": { "description": "user group name already exists", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } } }, "/user-groups/{id}": { "get": { "security": [ { "BearerAuth": [] } ], "description": "Get a user group by id; id 0 is the built-in admin group.", "produces": [ "application/json" ], "tags": [ "admin" ], "summary": "Get a user group", "parameters": [ { "type": "integer", "example": 1, "description": "User group ID", "name": "id", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/model.UserGroup" } }, "400": { "description": "invalid id", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "admin permission required or account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "404": { "description": "record not found", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } }, "put": { "security": [ { "BearerAuth": [] } ], "description": "Update a user group's name and description; name is required and unique.", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "admin" ], "summary": "Update a user group", "parameters": [ { "type": "integer", "example": 1, "description": "User group ID", "name": "id", "in": "path", "required": true }, { "description": "User group payload", "name": "group", "in": "body", "required": true, "schema": { "$ref": "#/definitions/usergroup.Request" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/model.UserGroup" } }, "400": { "description": "invalid request or id", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "admin permission required or account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "404": { "description": "record not found", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "409": { "description": "user group name already exists", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } }, "delete": { "security": [ { "BearerAuth": [] } ], "description": "Delete a user group by id; returns 204 with no body on success. Returns 409 for system groups or when the group still has members.", "produces": [ "application/json" ], "tags": [ "admin" ], "summary": "Delete a user group", "parameters": [ { "type": "integer", "example": 2, "description": "User group ID", "name": "id", "in": "path", "required": true } ], "responses": { "204": { "description": "Deleted" }, "400": { "description": "invalid id", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "admin permission required or account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "404": { "description": "record not found", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "409": { "description": "system group cannot be deleted or group still has members", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } } }, "/users": { "get": { "security": [ { "BearerAuth": [] } ], "description": "List users with their groups, ordered by id DESC. page starts at 1; page_size is 1-100, default 20.", "produces": [ "application/json" ], "tags": [ "admin" ], "summary": "List users", "parameters": [ { "type": "integer", "example": 1, "description": "Page number, default 1", "name": "page", "in": "query" }, { "type": "integer", "example": 20, "description": "Page size, default 20, max 100", "name": "page_size", "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/user.ListResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "admin permission required or account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } }, "post": { "security": [ { "BearerAuth": [] } ], "description": "Create a user and assign groups. username and email are unique; password is 6-72 chars; gender is male/female/other; birthday is YYYY-MM-DD and cannot be in the future; defaults to the regular user group (id 1) when group_ids is omitted.", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "admin" ], "summary": "Create a user", "parameters": [ { "description": "User payload", "name": "user", "in": "body", "required": true, "schema": { "$ref": "#/definitions/user.CreateRequest" } } ], "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/model.User" } }, "400": { "description": "invalid request or user group not found", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "admin permission required or account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "409": { "description": "username or email already exists", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } } }, "/users/{id}": { "get": { "security": [ { "BearerAuth": [] } ], "description": "Get a user by id, including groups.", "produces": [ "application/json" ], "tags": [ "admin" ], "summary": "Get a user", "parameters": [ { "type": "integer", "example": 1, "description": "User ID", "name": "id", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/model.User" } }, "400": { "description": "invalid id", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "admin permission required or account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "404": { "description": "record not found", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } }, "put": { "security": [ { "BearerAuth": [] } ], "description": "Update user fields. group_ids replaces all groups; a non-empty password resets the password; birthday accepts YYYY-MM-DD, an empty string clears it, and omitting it keeps the current value.", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "admin" ], "summary": "Update a user", "parameters": [ { "type": "integer", "example": 1, "description": "User ID", "name": "id", "in": "path", "required": true }, { "description": "Fields to update", "name": "user", "in": "body", "required": true, "schema": { "$ref": "#/definitions/user.UpdateRequest" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/model.User" } }, "400": { "description": "invalid request, id, or user group not found", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "admin permission required or account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "404": { "description": "record not found", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } }, "delete": { "security": [ { "BearerAuth": [] } ], "description": "Delete a user and their group memberships; returns 204 with no body on success.", "produces": [ "application/json" ], "tags": [ "admin" ], "summary": "Delete a user", "parameters": [ { "type": "integer", "example": 1, "description": "User ID", "name": "id", "in": "path", "required": true } ], "responses": { "204": { "description": "Deleted" }, "400": { "description": "invalid id", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "401": { "description": "unauthorized or session expired", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "403": { "description": "admin permission required or account disabled", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "404": { "description": "record not found", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/httpx.ErrorResponse" } } } } } }, "definitions": { "api.HealthResponse": { "type": "object", "properties": { "error": { "type": "string", "example": "database unavailable" }, "status": { "type": "string", "example": "ok" } } }, "auth.LoginRequest": { "type": "object", "required": [ "account", "password" ], "properties": { "account": { "type": "string", "example": "alice" }, "password": { "type": "string", "example": "secret123" } } }, "auth.LoginResponse": { "type": "object", "properties": { "expires_at": { "type": "string", "example": "2026-09-21T10:00:00+08:00" }, "token": { "type": "string", "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }, "user": { "$ref": "#/definitions/model.User" } } }, "auth.RegisterRequest": { "type": "object", "required": [ "email", "password", "username" ], "properties": { "email": { "type": "string", "maxLength": 255, "example": "alice@example.com" }, "password": { "type": "string", "maxLength": 72, "minLength": 6, "example": "secret123" }, "username": { "type": "string", "maxLength": 50, "minLength": 3, "example": "alice" } } }, "auth.UpdateProfileRequest": { "type": "object", "properties": { "birthday": { "type": "string", "example": "1995-06-15" }, "gender": { "type": "string", "example": "male" }, "nickname": { "type": "string", "maxLength": 50, "example": "Alice" } } }, "httpx.ErrorResponse": { "type": "object", "properties": { "error": { "type": "string", "example": "record not found" } } }, "model.File": { "type": "object", "properties": { "created_at": { "type": "string" }, "extension": { "type": "string" }, "hash": { "type": "string" }, "id": { "type": "integer" }, "last_referenced_at": { "type": "string" }, "metadata": { "type": "string" }, "mime_type": { "type": "string" }, "name": { "type": "string" }, "path": { "type": "string" }, "ref_count": { "type": "integer" }, "size": { "type": "integer" }, "status": { "type": "integer" }, "storage": { "type": "string" }, "updated_at": { "type": "string" }, "uploader_id": { "type": "integer" } } }, "model.NavLink": { "type": "object", "properties": { "created_at": { "type": "string" }, "id": { "type": "integer" }, "open_in_new_window": { "type": "boolean" }, "position": { "type": "string" }, "sort": { "type": "integer" }, "status": { "type": "integer" }, "translations": { "type": "array", "items": { "$ref": "#/definitions/model.NavLinkTranslation" } }, "updated_at": { "type": "string" }, "url": { "type": "string" } } }, "model.NavLinkTranslation": { "type": "object", "properties": { "label": { "type": "string" }, "locale": { "type": "string" }, "nav_link_id": { "type": "integer" } } }, "model.Note": { "type": "object", "properties": { "content": { "type": "string" }, "created_at": { "type": "string" }, "id": { "type": "integer" }, "title": { "type": "string" }, "updated_at": { "type": "string" } } }, "model.SiteSetting": { "type": "object", "properties": { "favicon": { "type": "string", "example": "https://example.com/favicon.ico" }, "footer": { "type": "string", "example": "Copyright © Rill" }, "logo": { "type": "string", "example": "https://example.com/logo.png" }, "site_name": { "type": "string", "example": "Rill" }, "updated_at": { "type": "string" } } }, "model.User": { "type": "object", "properties": { "avatar": { "type": "string" }, "birthday": { "type": "string", "example": "1995-06-15" }, "created_at": { "type": "string" }, "email": { "type": "string" }, "gender": { "type": "string", "example": "male" }, "groups": { "type": "array", "items": { "$ref": "#/definitions/model.UserGroup" } }, "id": { "type": "integer" }, "nickname": { "type": "string" }, "status": { "type": "integer" }, "updated_at": { "type": "string" }, "username": { "type": "string" } } }, "model.UserGroup": { "type": "object", "properties": { "created_at": { "type": "string" }, "description": { "type": "string" }, "id": { "type": "integer" }, "is_system": { "type": "boolean" }, "name": { "type": "string" }, "updated_at": { "type": "string" } } }, "nav.Request": { "type": "object", "required": [ "translations", "url" ], "properties": { "open_in_new_window": { "type": "boolean", "example": false }, "position": { "type": "string", "enum": [ "header", "footer" ], "example": "header" }, "sort": { "type": "integer", "example": 0 }, "status": { "type": "integer", "enum": [ 0, 1 ], "example": 1 }, "translations": { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/nav.TranslationRequest" } }, "url": { "type": "string", "maxLength": 512, "example": "/profile" } } }, "nav.TranslationRequest": { "type": "object", "required": [ "label", "locale" ], "properties": { "label": { "type": "string", "maxLength": 100, "example": "首页" }, "locale": { "type": "string", "maxLength": 10, "example": "zh-CN" } } }, "note.ListResponse": { "type": "object", "properties": { "items": { "type": "array", "items": { "$ref": "#/definitions/model.Note" } }, "page": { "type": "integer", "example": 1 }, "page_size": { "type": "integer", "example": 20 }, "total": { "type": "integer", "example": 42 } } }, "note.Request": { "type": "object", "required": [ "title" ], "properties": { "content": { "type": "string", "example": "Milk, eggs" }, "title": { "type": "string", "maxLength": 200, "example": "Shopping list" } } }, "site.UpdateRequest": { "type": "object", "required": [ "site_name" ], "properties": { "favicon": { "type": "string", "maxLength": 500, "example": "https://example.com/favicon.ico" }, "footer": { "type": "string", "maxLength": 1000, "example": "Copyright © Rill" }, "logo": { "type": "string", "maxLength": 500, "example": "https://example.com/logo.png" }, "site_name": { "type": "string", "maxLength": 100, "example": "Rill" } } }, "user.CreateRequest": { "type": "object", "required": [ "email", "password", "username" ], "properties": { "avatar": { "type": "string", "maxLength": 255, "example": "https://example.com/avatar.png" }, "birthday": { "type": "string", "example": "1995-06-15" }, "email": { "type": "string", "maxLength": 255, "example": "alice@example.com" }, "gender": { "type": "string", "enum": [ "male", "female", "other" ], "example": "male" }, "group_ids": { "type": "array", "items": { "type": "integer" }, "example": [ 1 ] }, "nickname": { "type": "string", "maxLength": 50, "example": "Alice" }, "password": { "type": "string", "maxLength": 72, "minLength": 6, "example": "secret123" }, "status": { "type": "integer", "enum": [ 0, 1 ], "example": 1 }, "username": { "type": "string", "maxLength": 50, "example": "alice" } } }, "user.ListResponse": { "type": "object", "properties": { "items": { "type": "array", "items": { "$ref": "#/definitions/model.User" } }, "page": { "type": "integer", "example": 1 }, "page_size": { "type": "integer", "example": 20 }, "total": { "type": "integer", "example": 42 } } }, "user.UpdateRequest": { "type": "object", "properties": { "avatar": { "type": "string", "maxLength": 255, "example": "https://example.com/avatar.png" }, "birthday": { "type": "string", "example": "1995-06-15" }, "gender": { "type": "string", "enum": [ "male", "female", "other" ], "example": "male" }, "group_ids": { "type": "array", "items": { "type": "integer" }, "example": [ 1 ] }, "nickname": { "type": "string", "maxLength": 50, "example": "Alice" }, "password": { "type": "string", "maxLength": 72, "minLength": 6, "example": "secret123" }, "status": { "type": "integer", "enum": [ 0, 1 ], "example": 1 } } }, "usergroup.ListResponse": { "type": "object", "properties": { "items": { "type": "array", "items": { "$ref": "#/definitions/model.UserGroup" } }, "page": { "type": "integer", "example": 1 }, "page_size": { "type": "integer", "example": 20 }, "total": { "type": "integer", "example": 42 } } }, "usergroup.Request": { "type": "object", "required": [ "name" ], "properties": { "description": { "type": "string", "maxLength": 255, "example": "Handles daily operations" }, "name": { "type": "string", "maxLength": 50, "example": "Operations" } } } }, "securityDefinitions": { "BearerAuth": { "description": "Bearer JWT, format: Bearer {token}, obtained from /auth/login", "type": "apiKey", "name": "Authorization", "in": "header" } }, "tags": [ { "description": "No authentication required", "name": "public" }, { "description": "Requires a logged-in user (Bearer JWT)", "name": "user" }, { "description": "Requires an admin user (Bearer JWT + admin group)", "name": "admin" } ] }` // SwaggerInfo holds exported Swagger Info so clients can modify it var SwaggerInfo = &swag.Spec{ Version: "1.0", Host: "", BasePath: "/api", Schemes: []string{}, Title: "Rill API", Description: "Rill server HTTP API documentation. All endpoints are prefixed with api.prefix (default /api); requests and responses are JSON.\nSwagger UI: {prefix}/swagger/index.html; OpenAPI JSON: {prefix}/swagger/doc.json.\nEndpoints are grouped by required permission: public needs no authentication, user needs a Bearer JWT obtained from /auth/login, admin needs an admin user.", InfoInstanceName: "swagger", SwaggerTemplate: docTemplate, LeftDelim: "{{", RightDelim: "}}", } func init() { swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) }