# Lyra 技术选型与架构讨论记录 日期:2026-10-16 状态:HTTP 路由、数据访问、数据库迁移工具与目标目录结构已确认(结构见 [architecture.md](../architecture.md));本文档方案已获文档层面批准,代码实施尚未批准。 ## 已确认 - Lyra 是个人 Go 后端,先承接 Polaris,未来承接其他项目接口。 - Polaris 采用一人管理、匿名公开浏览的模式。 - 已有服务器和 PostgreSQL;具体部署与连接配置尚未核实。 - 数据访问选择 Squirrel + sqlx,PostgreSQL 驱动使用 pgx stdlib。 - HTTP 路由选择 Gin;用户无明显接口风格偏好,结合文档与开发便利性作出选择。 - 数据库迁移工具选择 Goose。 - 本次确认仅涉及选型,不代表批准搭建代码或接入真实数据库。 ## 数据访问约定 - 固定查询直接写 SQL,动态查询使用 Squirrel,统一由 sqlx 执行。 - Squirrel 使用 Dollar 占位符,普通值使用参数绑定,动态标识符采用服务端白名单。 - 使用带 Context 的执行方法;需要原子性的业务操作使用事务。 - 显式声明查询字段,处理可空值和 JOIN 列名冲突。 - 不同时引入 sqlc 或 golang-migrate。 - 已讨论的取舍:无代码生成步骤,但查询与结果映射主要在运行时校验;上游维护低频。 ## 当前实现状态 - Lyra 仅有 go.mod 与 docs/ 下的文档,尚无接口、数据库或业务代码。 - Polaris 的 services 仍同步读取本地 JSON,未接入 Lyra。 - 未进行数据库连接或数据库结构修改。 ## 架构建议(尚未定案) - 一个 Go 服务;根据用户不希望按 Polaris 建立独立项目目录的偏好,调整为按技术职责组织代码,项目在 HTTP 路由上使用不同前缀。 - 各项目使用独立 HTTP 前缀,共享配置、日志、连接池等基础设施。 - PostgreSQL 可按项目划分 schema;这是组织边界,不等于权限隔离。 - 不提前建设微服务、统一用户中心或通用 CRUD 框架。 - 日志候选为标准库 slog,具体中间件与日志集成方式另行确认。 ## 目录结构与边界(已确认) 2026-10-16 用户确认以下目标组织方式;同日确认将数据访问职责并入 model,不再设独立 internal/store 目录。完整结构记录见 [architecture.md](../architecture.md)。确认的是结构与职责划分,不代表立即创建所有文件或占位目录,代码实施仍需另行批准。 ```text lyra/ ├── cmd/lyra/main.go ├── internal/ │ ├── api/ │ │ ├── links.go │ │ ├── categories.go │ │ └── settings.go │ ├── config/ │ │ └── config.go │ ├── postgres/ │ │ └── postgres.go │ ├── router/ │ │ └── router.go │ ├── handler/ │ │ └── links.go │ ├── service/ │ │ ├── links.go │ │ └── links_test.go │ ├── model/ │ │ ├── link.go │ │ ├── link_model.go │ │ └── link_model_test.go │ └── httpx/ │ └── response.go ├── migrations/ │ └── 00001_polaris_create_tables.sql ├── docs/plans/ ├── README.md ├── go.mod └── go.sum ``` - cmd/lyra 负责启动、依赖组装、调用路由注册和退出清理,不放业务规则。 - 用户提出统一管理接口请求与响应;推荐 internal/api,只放 HTTP 请求与响应 DTO 及其字段标签,按资源组织文件,不放 handler、业务逻辑或数据库查询。 - internal/router 注册路由与项目路径前缀;handler 处理参数绑定、DTO 转换与响应输出;service 管理业务规则;model 承载数据结构定义与数据访问(Squirrel/SQL 构造、sqlx 执行与结果映射),驱动为 pgx stdlib。测试与被测文件同目录。 - 树中 handler/service/model 仅列出链接资源示例;model/link.go 定义 Link 数据结构,model/link_model.go 定义数据访问与 SQL,model/link_model_test.go 测试查询,均为示例,实际文件随实现新增,不创建空占位目录或文件。 - handler 引用 API DTO 并转换为业务输入或响应;service/model 不依赖 API DTO 包,API DTO 包不引用 handler/service/model,避免传输契约和实现相互耦合或循环引用。 - 请求、响应与数据库模型职责分开,即使初期字段相近,也不默认直接把数据库模型暴露为响应;接受必要的显式转换代码。 - 主调用链为 handler→service→model→PostgreSQL;service 负责业务规则及需要的事务协调,model 支持同一事务内的数据库操作,不将跨多次写入各自独立提交当成原子业务。 - 上述文件是职责划分建议,不要求简单接口机械地走完整三层,也不按每张表或每种类型机械复制一套层级与文件。 - HTTP 层可以依赖 Gin;service 和 model 使用标准 context.Context,不接收 gin.Context。 - 移除 platform 和 modules 分类层;配置、连接和 HTTP 辅助直接位于 internal/config、internal/postgres、internal/httpx,减少无必要的路径深度。httpx 只在需要统一响应输出时实现,不提前抽象用户、设置、通用 CRUD 等业务。 - go.sum 在引入依赖后由 Go 工具生成;测试文件随实际功能编写,不创建空占位文件。 - 新项目可以在路由上增加独立前缀并复用上述技术层目录,不强制增加项目目录。不同领域的同名类型需要明确命名;文件名本身不提供 Go 包级符号隔离。 - 路由前缀只区分 HTTP 入口,不自动隔离代码依赖、数据库或权限;业务所有权与鉴权仍需显式设计,不能因路径不同就假定隔离成立。 - PostgreSQL 按项目划分 schema 仍为建议,尚未确认;schema 不自动提供权限隔离。 ### 外部示例参考 - 参考 https://github.com/vespeng/gin-pathway ,读取 main 分支 commit 67582d1。 - 借鉴其薄启动入口、显式依赖组装与统一错误处理思路;曾考虑其按业务分组,后按用户偏好改为技术分层,不直接复制具体代码或全部依赖。 - 该示例没有独立 API DTO 目录,部分数据库模型直接作为响应,本方案不沿用这一点。 - 不沿用其启动时同步表结构的机制;Lyra 仍使用已确认的 Goose 管理迁移,具体执行方式待确认。 - 不预建空 pkg、scripts、tests 等目录,不引入当前无需求的 Redis、ORM 或全局数据库单例。 - internal/api 与根 api 都是可行布局,小写 api 是命名习惯;推荐 internal/api 是因为当前 DTO 仅供 Lyra 内部使用,而非 Go 语言强制要求。 - 另参考 https://github.com/llmons/go-dianping ,读取 main 分支 commit cc7fbcf9:借鉴其独立 API 响应定义、技术分层与构造函数注入依赖;不照搬 ORM 生成层及缓存设施。 - go-dianping 的部分请求与响应复用数据库模型,Lyra 的独立请求/响应 DTO 方案不沿用这一做法。 ## 推荐迁移执行方式(待用户确认) - 起步采用 Goose CLI,在独立部署步骤中显式执行 SQL 迁移;Web 服务启动时不自动迁移。 - 迁移成功后再启动或更新服务;迁移失败则停止后续发布,检查实际状态。 - 同一个 Lyra 数据库初期使用一个 migrations 目录和统一版本序列,文件名标注所属模块;不让不同模块共用版本表却各自维护重复版本号。 - 部署流程保证同一数据库的迁移串行执行;如以后存在多个迁移入口或并发发布,再选择带数据库锁的迁移执行入口,不假定事务本身能防止并发迁移。 - 优先 SQL 迁移,非事务 DDL 单独设计;生产回退需要评估数据影响,不自动执行 Down。 - 表结构迁移与 Polaris JSON 初次导入分开设计,不能把 Goose 等同于业务数据导入工具。 ## 后续讨论顺序 1. 确认 Goose 的执行入口、串行执行或数据库锁方案(技术分层与路由前缀组织已确认,见 [architecture.md](../architecture.md))。 2. 确认首阶段范围:建议先做 JSON 导入、只读 API 和 Polaris 接入;管理写入另行确定认证方式。 3. 编写实施与验证方案,获得明确批准后再实施。 ## 后续实施方案必须覆盖的验证 - 使用隔离的 PostgreSQL 测试环境验证迁移、核心查询与事务,不默认操作现有真实数据。 - 核对导入前后的分类、链接、排序和置顶语义。 - 接入 Polaris 时验证 service 异步化、动态分类路由、缓存与后端故障处理。 - 管理写接口上线前验证鉴权,不能以隐藏入口代替权限控制。