doc: update backend doc

This commit is contained in:
2026-07-17 21:20:39 +08:00
parent 4893c8ddb0
commit 4c02b47620
3 changed files with 54 additions and 50 deletions
+8 -3
View File
@@ -1,10 +1,12 @@
# Driver: "sqlite" or "mysql"
[database]
driver = "sqlite"
# Path to the SQLite database file
[database.config]
path = "coconut-leaf.db"
# MySQL(占位,尚未实现)
# MySQL connection parameters (placeholder, not yet implemented)
# [database]
# driver = "mysql"
#
@@ -15,9 +17,12 @@ path = "coconut-leaf.db"
# password = "password"
# database = "coconut_leaf"
# HTTP listening port
[web]
port = 8848
[others]
auto-token-clean-duration = 86400 # 自动清理过期 token 的间隔(秒)
debug = true # 开启后日志级别降到 DEBUG
# Interval (in seconds) for automatic cleanup of expired tokens
auto-token-clean-duration = 86400
# Debug mode; must be set to false in production
debug = true
+38 -39
View File
@@ -1,70 +1,69 @@
# coconut-leaf 后端
# coconut-leaf Backend
coconut-leaf 的后端服务,使用 [Go](https://go.dev/) + [Gin](https://gin-gonic.com/) 实现,由旧版 Python Flask 后端迁移而来。
数据层直接执行 SQL(不使用 ORM),目前仅完整实现 SQLite,MySQL 接口为占位实现(全部接口返回 not implemented 错误)。
The backend service of coconut-leaf,
implemented with [Go](https://go.dev/) + [Gin](https://gin-gonic.com/),
migrated from the old Python Flask backend.
The data layer executes SQL directly (no ORM).
## 环境要求
> [!NOTE]
> Currently only SQLite is fully implemented.
> MySQL interfaces are placeholders (all endpoints return "not implemented" errors).
## Requirements
- **Go >= 1.26**
- **C 编译器(cgo**SQLite 驱动 [`mattn/go-sqlite3`](https://github.com/mattn/go-sqlite3) 依赖 cgo。
- Windows:推荐使用 MSYS2 gcc
- Linux / macOS:系统自带的 gcc / clang 即可。
- 构建前确保 `CGO_ENABLED=1`(有可用 C 编译器时通常默认开启)。
- **C compiler (cgo)**: The SQLite driver [`mattn/go-sqlite3`](https://github.com/mattn/go-sqlite3) requires CGO feature.
- Windows: MSYS2's gcc is recommended.
- Linux / macOS: System-provided gcc / clang works.
- Ensure `CGO_ENABLED=1` before building (usually enabled by default when a C compiler is available).
## 构建
## Build
`backend/` 目录下:
In the `backend/` directory:
```sh
go build -o coconut-leaf
```
> [!NOTE]
> 首次构建会编译 SQLite 的 C 源,耗时 1–3 分钟属正常。
>
> Windows 下用 MSYS2 编译出的可执行文件在运行时依赖 MSYS2 相关运行库(我这里是MSYS2 UCRT64,所以可能包含 `libgcc_s_*`、`libwinpthread-1.dll` 等)。
> 需让这些DLL所在文件夹处于 PATH 中,或将这些 DLL 拷贝到可执行文件旁。
> The first build compiles SQLite C source code; 13 minutes is normal.
>
> On Windows, executables built with MSYS2 depend on MSYS2 runtime libraries
> (I use MSYS2 UCRT64, so it may include `libgcc_s_*`, `libwinpthread-1.dll`, etc.).
> Either add the DLL directory to PATH or copy those DLLs next to the executable.
## 配置文件
## Configuration
采用 TOML 格式,通过 `--config` 指定路径。完整模板见 `assets` 文件夹下的 [coconut-leaf.template.toml](../assets/coconut-leaf.template.toml)。
Uses TOML format, specified via `-config` parameter.
See the full template at [coconut-leaf.template.toml](../assets/coconut-leaf.template.toml) in the `assets` directory.
字段说明:
## Command-line Arguments
| 字段 | 含义 |
| Argument | Description |
| --- | --- |
| `database.driver` | `"sqlite"``"mysql"` |
| `database.config.path` | SQLite 数据库文件路径 |
| `database.config.{host,port,user,password,database}` | MySQL 连接参数(未实现) |
| `web.port` | HTTP 监听端口 |
| `others.debug` | 调试模式(生产环境请务必设置为false) |
| `others.auto-token-clean-duration` | 过期 token 自动清理间隔(秒) |
| `-config <PATH>` | **Required**, path to the TOML configuration file |
| `-init` | Initialize the system: create tables and the first admin user |
| `-username <NAME>` | Used with `-init`, the initial admin username |
| `-password <PASS>` | Used with `-init`, the initial admin password |
## 命令行参数
`-username` / `-password` are required only when `-init` is specified and are validated
(username: `[0-9A-Za-z]+`, password: all visible ASCII characters, i.e., `[!-~]+`).
| 参数 | 说明 |
| --- | --- |
| `--config <PATH>` | **必填**,配置文件(TOML)路径 |
| `--init` | 初始化系统:建表并创建首个管理员用户 |
| `--username <NAME>` | 与 `--init` 配合,初始管理员的用户名 |
| `--password <PASS>` | 与 `--init` 配合,初始管理员的密码 |
## Initialization and Runtime
`--username` / `--password` 仅在 `--init` 时必填,并会做格式校验(用户名为 `[0-9A-Za-z]+`,密码为所有可见 ASCII 字符,即 `[!-~]+`)。
### First Deployment
## 初始化与运行
### 首次部署
首次部署包括:建表 + 创建管理员,随后如日常运行一般:
First deployment includes creating tables and the admin user, then running as usual:
```sh
./coconut-leaf --config coconut-leaf.toml --init --username admin --password "your-password"
```
### 日常运行
### Normal Runtime
```sh
./coconut-leaf --config coconut-leaf.toml
```
启动后会在 `web.port` 监听。调试日志会输出到 stderr,格式为 `[<时间>] [<级别>] <消息> [key=value ...]`
After starting, it listens on `web.port`.
Debug logs are written to stderr in the format `[<time>] [<level>] <message> [key=value ...]`.
+8 -8
View File
@@ -13,14 +13,14 @@ type CLIArgs struct {
Config string
// Init indicates whether to initialize the calendar system before running.
Init bool
// Username is the first admin user's name; required together with --init.
// Username is the first admin user's name; required together with -init.
Username string
// Password is the first admin user's password; required together with --init.
// Password is the first admin user's password; required together with -init.
Password string
}
// Parse parses the command-line arguments via the standard flag package and
// returns a *CLIArgs. When the required --config flag is missing, it prints the
// returns a *CLIArgs. When the required -config flag is missing, it prints the
// usage and exits with status 2 (matching argparse's exit code).
func Parse() *CLIArgs {
args := &CLIArgs{}
@@ -34,19 +34,19 @@ func Parse() *CLIArgs {
flag.PrintDefaults()
}
// --config maps to the legacy -c/--config (required), --init to -i/--init.
// --username/--password replace the legacy interactive GetUsernamePassword
// -config maps to the legacy -c/--config (required), -init to -i/--init.
// -username/-password replace the legacy interactive GetUsernamePassword
// prompt and are required together with --init.
flag.StringVar(&args.Config, "config", "", "The configuration file `CONFIG_TOML` for coconut-leaf")
flag.BoolVar(&args.Init, "init", false, "Set for initialize the calendar system")
flag.StringVar(&args.Username, "username", "", "The first admin user's name (required with --init)")
flag.StringVar(&args.Password, "password", "", "The first admin user's password (required with --init)")
flag.StringVar(&args.Username, "username", "", "The first admin user's name (required with -init)")
flag.StringVar(&args.Password, "password", "", "The first admin user's password (required with -init)")
flag.Parse()
// The standard flag package has no built-in "required", so validate manually.
if args.Config == "" {
fmt.Fprintln(os.Stderr, "error: the required flag --config is not provided")
fmt.Fprintln(os.Stderr, "error: the required flag -config is not provided")
flag.Usage()
os.Exit(2)
}