pdf-forge
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesepdf-forge
pdf-forge
Go module for multi-tenant document templates with PDF generation via Typst.
一个基于Typst的多租户文档模板PDF生成Go模块。
Installation
安装
bash
npx skills add https://github.com/rendis/pdf-forge --skill pdf-forgebash
npx skills add https://github.com/rendis/pdf-forge --skill pdf-forgeHow It Works
工作原理
plaintext
Tenant → Workspace → Template → Version (DRAFT→PUBLISHED)
↓
Injectables (variables)
↓
Render → PDFplaintext
Tenant → Workspace → Template → Version (DRAFT→PUBLISHED)
↓
Injectables (variables)
↓
Render → PDFQuick Start
快速开始
go
// core/extensions/register.go
func Register(engine *sdk.Engine) {
engine.RegisterInjector(&CustomerNameInjector{})
engine.SetMapper(&MyMapper{})
engine.SetInitFunc(MyInit())
}
// core/cmd/api/main.go
func main() {
engine := sdk.NewWithConfig("settings/app.yaml").
SetI18nFilePath("settings/injectors.i18n.yaml")
extensions.Register(engine)
if err := engine.Run(); err != nil {
slog.Error("failed to run engine", slog.String("error", err.Error()))
os.Exit(1)
}
}go
// core/extensions/register.go
func Register(engine *sdk.Engine) {
engine.RegisterInjector(&CustomerNameInjector{})
engine.SetMapper(&MyMapper{})
engine.SetInitFunc(MyInit())
}
// core/cmd/api/main.go
func main() {
engine := sdk.NewWithConfig("settings/app.yaml").
SetI18nFilePath("settings/injectors.i18n.yaml")
extensions.Register(engine)
if err := engine.Run(); err != nil {
slog.Error("failed to run engine", slog.String("error", err.Error()))
os.Exit(1)
}
}Creating an Injector
创建注入器
go
type CustomerNameInjector struct{}
func (i *CustomerNameInjector) Code() string { return "customer_name" }
func (i *CustomerNameInjector) Resolve() (sdk.ResolveFunc, []string) {
return func(ctx context.Context, injCtx *sdk.InjectorContext) (*sdk.InjectorResult, error) {
payload := injCtx.RequestPayload().(map[string]any)
return &sdk.InjectorResult{Value: sdk.StringValue(payload["name"].(string))}, nil
}, nil // dependencies
}
func (i *CustomerNameInjector) IsCritical() bool { return true }
func (i *CustomerNameInjector) Timeout() time.Duration { return 5 * time.Second }
func (i *CustomerNameInjector) DataType() sdk.ValueType { return sdk.ValueTypeString }
func (i *CustomerNameInjector) DefaultValue() *sdk.InjectableValue { return nil }
func (i *CustomerNameInjector) Formats() *sdk.FormatConfig { return nil }go
type CustomerNameInjector struct{}
func (i *CustomerNameInjector) Code() string { return "customer_name" }
func (i *CustomerNameInjector) Resolve() (sdk.ResolveFunc, []string) {
return func(ctx context.Context, injCtx *sdk.InjectorContext) (*sdk.InjectorResult, error) {
payload := injCtx.RequestPayload().(map[string]any)
return &sdk.InjectorResult{Value: sdk.StringValue(payload["name"].(string))}, nil
}, nil // dependencies
}
func (i *CustomerNameInjector) IsCritical() bool { return true }
func (i *CustomerNameInjector) Timeout() time.Duration { return 5 * time.Second }
func (i *CustomerNameInjector) DataType() sdk.ValueType { return sdk.ValueTypeString }
func (i *CustomerNameInjector) DefaultValue() *sdk.InjectableValue { return nil }
func (i *CustomerNameInjector) Formats() *sdk.FormatConfig { return nil }Value Types
数据类型
| Type | Constructor | Constant |
|---|---|---|
| Text | | |
| Number | | |
| Boolean | | |
| Date/Time | | |
| Image | | |
| Table | | |
| List | | |
See types-reference.md for Tables, Lists, InjectorContext, FormatConfig.
| 类型 | 构造函数 | 常量 |
|---|---|---|
| 文本 | | |
| 数字 | | |
| 布尔值 | | |
| 日期/时间 | | |
| 图片 | | |
| 表格 | | |
| 列表 | | |
关于表格、列表、InjectorContext、FormatConfig的详细信息,请查看types-reference.md。
Built-in Injectors
内置注入器
| Code | Type | Formats |
|---|---|---|
| TIME | DD/MM/YYYY, MM/DD/YYYY, YYYY-MM-DD |
| TIME | HH:mm, HH:mm:ss, hh:mm a |
| TIME | Combined |
| NUMBER | - |
| NUMBER | number, name, short_name |
| NUMBER | - |
| 标识码 | 类型 | 格式 |
|---|---|---|
| TIME | DD/MM/YYYY, MM/DD/YYYY, YYYY-MM-DD |
| TIME | HH:mm, HH:mm:ss, hh:mm a |
| TIME | 组合格式 |
| NUMBER | - |
| NUMBER | number, name, short_name |
| NUMBER | - |
Error Handling
错误处理
| On Error |
|---|---|
| Aborts render |
| Uses |
| 错误时行为 |
|---|---|
| 终止渲染流程 |
| 使用 |
Extension Points
扩展点
| Extension | Purpose | Register |
|---|---|---|
| Injector | Data resolvers | |
| Mapper | Request parsing | |
| InitFunc | Shared setup | |
| Provider | Dynamic injectables | |
| Auth | Custom render auth | |
| Middleware | Request handling | |
| Frontend | Embedded SPA | |
| Lifecycle | Startup/shutdown | |
See extensions-reference.md for implementation examples.
| 扩展类型 | 用途 | 注册方式 |
|---|---|---|
| Injector | 数据解析器 | |
| Mapper | 请求解析器 | |
| InitFunc | 全局初始化 | |
| Provider | 动态注入项 | |
| Auth | 自定义渲染认证 | |
| Middleware | 请求处理中间件 | |
| Frontend | 嵌入式SPA | |
| Lifecycle | 启动/关闭钩子 | |
实现示例请参考extensions-reference.md。
Configuration
配置
See config-reference.md for all YAML keys, env vars, and auth setup.
Dummy auth: Omit config entirely for development mode.
auth所有YAML配置项、环境变量和认证设置请参考config-reference.md。
虚拟认证:开发模式下可完全省略配置。
authCLI Commands
CLI命令
bash
make build # Build frontend + embed + Go binary (single binary)
make embed-app # Build frontend and copy to Go embed location
make run # Run API server (with embedded frontend)
make dev # Hot reload backend (air)
make migrate # Apply database migrations
make test # Run tests
make lint # Run linter
make swagger # Regenerate OpenAPI spec
make doctor # Check system dependenciesbash
make build # Build frontend + embed + Go binary (single binary)
make embed-app # Build frontend and copy to Go embed location
make run # Run API server (with embedded frontend)
make dev # Hot reload backend (air)
make migrate # Apply database migrations
make test # Run tests
make lint # Run linter
make swagger # Regenerate OpenAPI spec
make doctor # Check system dependenciesCommon Mistakes
常见错误
| Wrong | Correct |
|---|---|
| |
| |
| Forgetting dependencies | |
| Provide |
| 错误做法 | 正确做法 |
|---|---|
| |
| |
| 忘记声明依赖项 | |
| 提供 |
API Headers
API请求头
| Header | Purpose | Used By |
|---|---|---|
| | All auth routes |
| Tenant UUID | Panel routes |
| Workspace UUID | Panel routes |
| Tenant code (e.g. | Render routes |
| Workspace code (e.g. | Render routes |
| 请求头 | 用途 | 适用场景 |
|---|---|---|
| | 所有认证路由 |
| 租户UUID | 面板路由 |
| 工作区UUID | 面板路由 |
| 租户编码(例如 | 渲染路由 |
| 工作区编码(例如 | 渲染路由 |
References
参考文档
- config-reference.md - YAML keys, env vars, auth, performance
- types-reference.md - Tables, Lists, FormatConfig, InjectorContext
- extensions-reference.md - Middleware, Lifecycle, Provider, Auth examples
- patterns-reference.md - Logging, error handling, context, anti-patterns
- enterprise-scenarios.md - CRM integration, Vault, validation patterns
- domain-reference.md - Tenants, workspaces, roles, render flow
- config-reference.md - YAML配置项、环境变量、认证、性能优化
- types-reference.md - 表格、列表、FormatConfig、InjectorContext
- extensions-reference.md - 中间件、生命周期、Provider、Auth实现示例
- patterns-reference.md - 日志、错误处理、上下文、反模式
- enterprise-scenarios.md - CRM集成、Vault、验证模式
- domain-reference.md - 租户、工作区、角色、渲染流程