Files
rill/docs/swagger.yaml
T
kevin 4449250e97 新增头部导航链接配置与多语言支持
- 迁移 v10 新增 nav_links 与 nav_link_translations 两张表,文案按语言存储
- 公开 GET /api/nav-links 返回启用链接(按 sort/id 排序);管理员可增删改查与启停
- URL 仅允许站内路径、http(s) 与 mailto,拒绝 javascript: 等危险协议;译文替换与校验
- 前端删除写死的“主页”按钮,头部按当前语言渲染动态链接,新窗口加 rel=noopener noreferrer
- 后台管理页新增“头部导航链接”卡片(三语文案、URL、打开方式、排序、状态),改动即时生效
- 补充 nav 接口与迁移测试、三语文案,重新生成 Swagger 文档
2026-09-21 21:26:30 +08:00

1764 lines
46 KiB
YAML

basePath: /api
definitions:
api.HealthResponse:
properties:
error:
example: database unavailable
type: string
status:
example: ok
type: string
type: object
auth.LoginRequest:
properties:
account:
example: alice
type: string
password:
example: secret123
type: string
required:
- account
- password
type: object
auth.LoginResponse:
properties:
expires_at:
example: "2026-09-21T10:00:00+08:00"
type: string
token:
example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
type: string
user:
$ref: '#/definitions/model.User'
type: object
auth.RegisterRequest:
properties:
email:
example: alice@example.com
maxLength: 255
type: string
password:
example: secret123
maxLength: 72
minLength: 6
type: string
username:
example: alice
maxLength: 50
minLength: 3
type: string
required:
- email
- password
- username
type: object
auth.UpdateProfileRequest:
properties:
birthday:
example: "1995-06-15"
type: string
gender:
example: male
type: string
nickname:
example: Alice
maxLength: 50
type: string
type: object
httpx.ErrorResponse:
properties:
error:
example: record not found
type: string
type: object
model.File:
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
type: object
model.NavLink:
properties:
created_at:
type: string
id:
type: integer
open_in_new_window:
type: boolean
sort:
type: integer
status:
type: integer
translations:
items:
$ref: '#/definitions/model.NavLinkTranslation'
type: array
updated_at:
type: string
url:
type: string
type: object
model.NavLinkTranslation:
properties:
label:
type: string
locale:
type: string
nav_link_id:
type: integer
type: object
model.Note:
properties:
content:
type: string
created_at:
type: string
id:
type: integer
title:
type: string
updated_at:
type: string
type: object
model.SiteSetting:
properties:
footer:
example: Copyright © Rill
type: string
logo:
example: https://example.com/logo.png
type: string
site_name:
example: Rill
type: string
updated_at:
type: string
type: object
model.User:
properties:
avatar:
type: string
birthday:
example: "1995-06-15"
type: string
created_at:
type: string
email:
type: string
gender:
example: male
type: string
groups:
items:
$ref: '#/definitions/model.UserGroup'
type: array
id:
type: integer
nickname:
type: string
status:
type: integer
updated_at:
type: string
username:
type: string
type: object
model.UserGroup:
properties:
created_at:
type: string
description:
type: string
id:
type: integer
is_system:
type: boolean
name:
type: string
updated_at:
type: string
type: object
nav.Request:
properties:
open_in_new_window:
example: false
type: boolean
sort:
example: 0
type: integer
status:
enum:
- 0
- 1
example: 1
type: integer
translations:
items:
$ref: '#/definitions/nav.TranslationRequest'
minItems: 1
type: array
url:
example: /profile
maxLength: 512
type: string
required:
- translations
- url
type: object
nav.TranslationRequest:
properties:
label:
example: 首页
maxLength: 100
type: string
locale:
example: zh-CN
maxLength: 10
type: string
required:
- label
- locale
type: object
note.ListResponse:
properties:
items:
items:
$ref: '#/definitions/model.Note'
type: array
page:
example: 1
type: integer
page_size:
example: 20
type: integer
total:
example: 42
type: integer
type: object
note.Request:
properties:
content:
example: Milk, eggs
type: string
title:
example: Shopping list
maxLength: 200
type: string
required:
- title
type: object
site.UpdateRequest:
properties:
footer:
example: Copyright © Rill
maxLength: 1000
type: string
logo:
example: https://example.com/logo.png
maxLength: 500
type: string
site_name:
example: Rill
maxLength: 100
type: string
required:
- site_name
type: object
user.CreateRequest:
properties:
avatar:
example: https://example.com/avatar.png
maxLength: 255
type: string
birthday:
example: "1995-06-15"
type: string
email:
example: alice@example.com
maxLength: 255
type: string
gender:
enum:
- male
- female
- other
example: male
type: string
group_ids:
example:
- 1
items:
type: integer
type: array
nickname:
example: Alice
maxLength: 50
type: string
password:
example: secret123
maxLength: 72
minLength: 6
type: string
status:
enum:
- 0
- 1
example: 1
type: integer
username:
example: alice
maxLength: 50
type: string
required:
- email
- password
- username
type: object
user.ListResponse:
properties:
items:
items:
$ref: '#/definitions/model.User'
type: array
page:
example: 1
type: integer
page_size:
example: 20
type: integer
total:
example: 42
type: integer
type: object
user.UpdateRequest:
properties:
avatar:
example: https://example.com/avatar.png
maxLength: 255
type: string
birthday:
example: "1995-06-15"
type: string
gender:
enum:
- male
- female
- other
example: male
type: string
group_ids:
example:
- 1
items:
type: integer
type: array
nickname:
example: Alice
maxLength: 50
type: string
password:
example: secret123
maxLength: 72
minLength: 6
type: string
status:
enum:
- 0
- 1
example: 1
type: integer
type: object
usergroup.ListResponse:
properties:
items:
items:
$ref: '#/definitions/model.UserGroup'
type: array
page:
example: 1
type: integer
page_size:
example: 20
type: integer
total:
example: 42
type: integer
type: object
usergroup.Request:
properties:
description:
example: Handles daily operations
maxLength: 255
type: string
name:
example: Operations
maxLength: 50
type: string
required:
- name
type: object
info:
contact: {}
description: |-
Rill server HTTP API documentation. All endpoints are prefixed with api.prefix (default /api); requests and responses are JSON.
Swagger UI: {prefix}/swagger/index.html; OpenAPI JSON: {prefix}/swagger/doc.json.
Endpoints are grouped by required permission: public needs no authentication, user needs a Bearer JWT obtained from /auth/login, admin needs an admin user.
title: Rill API
version: "1.0"
paths:
/auth/login:
post:
consumes:
- application/json
description: Login with username or email; returns a JWT (TTL from auth.token_ttl)
and the user.
parameters:
- description: Login credentials
in: body
name: credentials
required: true
schema:
$ref: '#/definitions/auth.LoginRequest'
produces:
- application/json
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'
summary: Login
tags:
- public
/auth/register:
post:
consumes:
- application/json
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.
parameters:
- description: Registration payload
in: body
name: user
required: true
schema:
$ref: '#/definitions/auth.RegisterRequest'
produces:
- application/json
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'
summary: Register
tags:
- public
/files:
post:
consumes:
- multipart/form-data
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.
parameters:
- description: File content
in: formData
name: file
required: true
type: file
produces:
- application/json
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'
security:
- BearerAuth: []
summary: Upload a file
tags:
- user
/files/{id}:
delete:
description: Delete a file physically and keep the record with status 0; uploader
or admin only. Files still referenced (ref_count > 0) return 409.
parameters:
- description: File ID
example: 1
in: path
name: id
required: true
type: integer
produces:
- application/json
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'
security:
- BearerAuth: []
summary: Delete a file
tags:
- user
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.
parameters:
- description: File ID
example: 1
in: path
name: id
required: true
type: integer
produces:
- application/octet-stream
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'
summary: Get file content
tags:
- public
/health:
get:
description: Check service and database connectivity; returns 503 when the database
is unavailable.
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/api.HealthResponse'
"503":
description: Service Unavailable
schema:
$ref: '#/definitions/api.HealthResponse'
summary: Health check
tags:
- public
/me:
get:
description: Return the authenticated user's profile, including groups.
produces:
- application/json
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'
security:
- BearerAuth: []
summary: Get current user profile
tags:
- user
put:
consumes:
- application/json
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.
parameters:
- description: Fields to update
in: body
name: profile
required: true
schema:
$ref: '#/definitions/auth.UpdateProfileRequest'
produces:
- application/json
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'
security:
- BearerAuth: []
summary: Update current user profile
tags:
- user
/me/avatar:
delete:
description: Clear the authenticated user's avatar and release the file reference
when it points to a local file.
produces:
- application/json
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'
security:
- BearerAuth: []
summary: Delete current user avatar
tags:
- user
put:
consumes:
- multipart/form-data
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.
parameters:
- description: Avatar image
in: formData
name: file
required: true
type: file
produces:
- application/json
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'
security:
- BearerAuth: []
summary: Update current user avatar
tags:
- user
/nav-links:
get:
description: Public header navigation links (status enabled), ordered by sort
ASC then id ASC, with translations.
produces:
- application/json
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/model.NavLink'
type: array
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/httpx.ErrorResponse'
summary: List nav links
tags:
- public
post:
consumes:
- application/json
description: Admin only. Create a header navigation link. url accepts site-relative
paths (/...), http(s) URLs, and mailto links; translations must include at
least one non-empty label.
parameters:
- description: Nav link payload
in: body
name: link
required: true
schema:
$ref: '#/definitions/nav.Request'
produces:
- application/json
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'
security:
- BearerAuth: []
summary: Create a nav link
tags:
- admin
/nav-links/{id}:
delete:
description: Admin only. Delete a header navigation link and its translations.
parameters:
- description: Nav link ID
example: 1
in: path
name: id
required: true
type: integer
produces:
- application/json
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'
security:
- BearerAuth: []
summary: Delete a nav link
tags:
- admin
put:
consumes:
- application/json
description: Admin only. Update a header navigation link; translations are replaced
by the provided list.
parameters:
- description: Nav link ID
example: 1
in: path
name: id
required: true
type: integer
- description: Nav link payload
in: body
name: link
required: true
schema:
$ref: '#/definitions/nav.Request'
produces:
- application/json
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'
security:
- BearerAuth: []
summary: Update a nav link
tags:
- admin
/nav-links/list:
get:
description: Admin only. List all header navigation links including disabled
ones, with translations.
produces:
- application/json
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/model.NavLink'
type: array
"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'
security:
- BearerAuth: []
summary: List all nav links
tags:
- admin
/notes:
get:
description: List notes ordered by id DESC. page starts at 1; page_size is 1-100,
default 20.
parameters:
- description: Page number, default 1
example: 1
in: query
name: page
type: integer
- description: Page size, default 20, max 100
example: 20
in: query
name: page_size
type: integer
produces:
- application/json
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'
security:
- BearerAuth: []
summary: List notes
tags:
- user
post:
consumes:
- application/json
description: Create a note. title is required (max 200 chars); content is optional.
parameters:
- description: Note payload
in: body
name: note
required: true
schema:
$ref: '#/definitions/note.Request'
produces:
- application/json
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'
security:
- BearerAuth: []
summary: Create a note
tags:
- user
/notes/{id}:
delete:
description: Delete a note by id; returns 204 with no body on success.
parameters:
- description: Note ID
example: 1
in: path
name: id
required: true
type: integer
produces:
- application/json
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'
security:
- BearerAuth: []
summary: Delete a note
tags:
- user
get:
description: Get a note by id.
parameters:
- description: Note ID
example: 1
in: path
name: id
required: true
type: integer
produces:
- application/json
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'
security:
- BearerAuth: []
summary: Get a note
tags:
- user
put:
consumes:
- application/json
description: Update title and content; validation is the same as create.
parameters:
- description: Note ID
example: 1
in: path
name: id
required: true
type: integer
- description: Note payload
in: body
name: note
required: true
schema:
$ref: '#/definitions/note.Request'
produces:
- application/json
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'
security:
- BearerAuth: []
summary: Update a note
tags:
- user
/site:
get:
description: 'Public site settings: site name, logo URL, and footer text. Returns
built-in defaults when the settings row is missing.'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/model.SiteSetting'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/httpx.ErrorResponse'
summary: Get site settings
tags:
- public
put:
consumes:
- application/json
description: Admin only. Update the site name, logo URL, and footer text; logo
files hosted on this site have their reference count managed automatically.
Returns the updated settings.
parameters:
- description: Site settings
in: body
name: site
required: true
schema:
$ref: '#/definitions/site.UpdateRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/model.SiteSetting'
"400":
description: invalid request or logo 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'
security:
- BearerAuth: []
summary: Update site settings
tags:
- admin
/site/logo:
delete:
description: Admin only. Clear the site logo and release the reference of the
locally stored logo file.
produces:
- application/json
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'
security:
- BearerAuth: []
summary: Delete site logo
tags:
- admin
put:
consumes:
- multipart/form-data
description: Admin only. Upload an image as the site logo (multipart field file,
image only); the logo takes effect immediately and file references are managed
automatically.
parameters:
- description: Logo image
in: formData
name: file
required: true
type: file
produces:
- application/json
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'
security:
- BearerAuth: []
summary: Upload site logo
tags:
- admin
/user-groups:
get:
description: List user groups ordered by id ASC. page starts at 1; page_size
is 1-100, default 20.
parameters:
- description: Page number, default 1
example: 1
in: query
name: page
type: integer
- description: Page size, default 20, max 100
example: 20
in: query
name: page_size
type: integer
produces:
- application/json
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'
security:
- BearerAuth: []
summary: List user groups
tags:
- admin
post:
consumes:
- application/json
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.
parameters:
- description: User group payload
in: body
name: group
required: true
schema:
$ref: '#/definitions/usergroup.Request'
produces:
- application/json
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'
security:
- BearerAuth: []
summary: Create a user group
tags:
- admin
/user-groups/{id}:
delete:
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.
parameters:
- description: User group ID
example: 2
in: path
name: id
required: true
type: integer
produces:
- application/json
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'
security:
- BearerAuth: []
summary: Delete a user group
tags:
- admin
get:
description: Get a user group by id; id 0 is the built-in admin group.
parameters:
- description: User group ID
example: 1
in: path
name: id
required: true
type: integer
produces:
- application/json
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'
security:
- BearerAuth: []
summary: Get a user group
tags:
- admin
put:
consumes:
- application/json
description: Update a user group's name and description; name is required and
unique.
parameters:
- description: User group ID
example: 1
in: path
name: id
required: true
type: integer
- description: User group payload
in: body
name: group
required: true
schema:
$ref: '#/definitions/usergroup.Request'
produces:
- application/json
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'
security:
- BearerAuth: []
summary: Update a user group
tags:
- admin
/users:
get:
description: List users with their groups, ordered by id DESC. page starts at
1; page_size is 1-100, default 20.
parameters:
- description: Page number, default 1
example: 1
in: query
name: page
type: integer
- description: Page size, default 20, max 100
example: 20
in: query
name: page_size
type: integer
produces:
- application/json
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'
security:
- BearerAuth: []
summary: List users
tags:
- admin
post:
consumes:
- application/json
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.
parameters:
- description: User payload
in: body
name: user
required: true
schema:
$ref: '#/definitions/user.CreateRequest'
produces:
- application/json
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'
security:
- BearerAuth: []
summary: Create a user
tags:
- admin
/users/{id}:
delete:
description: Delete a user and their group memberships; returns 204 with no
body on success.
parameters:
- description: User ID
example: 1
in: path
name: id
required: true
type: integer
produces:
- application/json
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'
security:
- BearerAuth: []
summary: Delete a user
tags:
- admin
get:
description: Get a user by id, including groups.
parameters:
- description: User ID
example: 1
in: path
name: id
required: true
type: integer
produces:
- application/json
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'
security:
- BearerAuth: []
summary: Get a user
tags:
- admin
put:
consumes:
- application/json
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.
parameters:
- description: User ID
example: 1
in: path
name: id
required: true
type: integer
- description: Fields to update
in: body
name: user
required: true
schema:
$ref: '#/definitions/user.UpdateRequest'
produces:
- application/json
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'
security:
- BearerAuth: []
summary: Update a user
tags:
- admin
securityDefinitions:
BearerAuth:
description: 'Bearer JWT, format: Bearer {token}, obtained from /auth/login'
in: header
name: Authorization
type: apiKey
swagger: "2.0"
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