k2gl/pragmatic-franken
GitHub: k2gl/pragmatic-franken
基于 FrankenPHP 与 Symfony 8 的生产级 PHP 起步模板,采用垂直切片+CQRS 架构,集成生产镜像、CI 验证和 AI agent 协作支持。
Stars: 3 | Forks: 1
# 实用 FrankenPHP
[](https://github.com/k2gl/pragmatic-franken/actions/workflows/ci.yml)
[](https://packagist.org/packages/k2gl/pragmatic-franken)
[](https://www.php.net/releases/8.5/)
[](https://frankenphp.dev/)
[](https://symfony.com/)
[](https://phpstan.org)
[](https://packagist.org/packages/k2gl/pragmatic-franken)
**实用 FrankenPHP** 是一个基于 PHP 8.5 / Symfony 8 / FrankenPHP 的起步模板,它脱胎于
真实的Production项目——并且将经验与教训反哺于此。它基于 Messenger 实现了垂直切片 + CQRS,采用 PostgreSQL 17,支持 worker 模式,提供真实的
Production镜像以及供应链证明。目标是:复刻它并在第一天就交付真实的
产品,由人类和 AI agent 共同运营。
**这些承诺均由 CI 验证,绝非空口无凭:**
- **Production镜像**会在每次 PR 时启动(`prod-image` 作业:构建 → 运行 → `/ready`);
- **脚手架生成的代码无需修改即可通过 PHPStan 10 + 测试**(`agent-smoke` 作业);
- 发布的镜像携带 **SLSA 构建来源证明**,并且部署门禁会对其进行校验(ADR-0014);
- 文档经过了**基于现实的校验**(`make docs-check`:路由、Makefile 目标、ADR 同步)。
有关架构规则和代码层面的指导,请参阅 **[AGENTS.md](AGENTS.md)** —— 这是唯一的真理来源,不超过 2 000 个 token,对开发者和 AI 工具同样适用。
## 技术栈
| 层级 | 选择 | 原因 |
|---|---|---|
| 应用服务器 | FrankenPHP 1.x (Caddy + worker 模式) | 单一二进制文件,HTTP/3,保持内核常驻 |
| 框架 | Symfony 8.0 | 成熟,基于 attribute 的装配 |
| 总线 | Symfony Messenger (CQRS) | 同步 command/query,异步事件 |
| 数据库 | PostgreSQL 17 | Doctrine ORM 3 |
| 队列 | 基于 Doctrine transport 的 Messenger | 无需额外扩展,可审查,经过Production验证 |
| 缓存 | Redis 7 (Predis) | 随时可用于缓存和自定义需求 |
| 前端(默认) | AssetMapper + Twig | HTML 优先,无需 Webpack/Vite |
| 代码风格 | Laravel Pint (PSR-12) | 一键自动修复 |
| 静态分析 | PHPStan level 10 | 在 CI 中强制执行 |
| 测试 | PHPUnit 12 + Zenstruck (Foundry, Browser, Messenger-Test) + DAMA + Faker + Fluent Assertions | 测试金字塔 60/30/10 |
## 快速开始
**路径 1 — 模板 + Docker**(只需要 Docker):
```
gh repo create my-app --template k2gl/pragmatic-franken --clone && cd my-app
# 或:git clone https://github.com/k2gl/pragmatic-franken.git my-app
make install # env, containers, deps, migrations
make init name=my-app # rename + real secrets (optionally: prune=1 reset-git=1)
make smoke # bin/console + /ready
```
**路径 2 — composer create-project**(宿主机需要 PHP ≥ 8.5):
```
composer create-project k2gl/pragmatic-franken my-app
cd my-app && make install && make init name=my-app
```
应用将通过 `https://my-app.localhost:${HTTPS_PORT:-4750}` 启动(浏览器
会自动解析 `*.localhost` —— 无需修改 `/etc/hosts`)。尝试以下示例
API:`POST /tasks`、`GET /tasks`、`POST /tasks/{id}/complete` —— 完成操作
会通过 Mercure 在 `/tasks` 推送实时更新。
## 为什么不直接用 symfony/skeleton?
| | **pragmatic-franken** | symfony/skeleton | dunglas/symfony-docker | API Platform |
|---|---|---|---|---|
| 架构理念 | 垂直切片 + CQRS,18 项 ADR | 无 | 无 | API 优先框架 |
| Production镜像 | 每次 PR 都会构建、启动并扫描 | — | 会构建 | 会构建 |
| 真实的垂直示例 | entity → migration → factory → tests | — | — | 生成的 CRUD |
| 部署方案 | VDS 上的蓝绿部署 + 备份 + DR 演练 | — | — | k8s helm |
| 供应链 | 来源证明 + 离线验证器 + 门禁 | — | — | — |
| Agent 支持 | AGENTS.md(≤2k token)+ 经 CI 验证的脚手架 | — | — | — |
| 最适用于 | 在单台 VDS 上运行且由 agent 参与流程的产品 API/应用 | 需要原生框架 | 需要原生 Docker | 你的产品本身就*是* API |
坦诚的非目标:核心不包含 auth(使用 recipe 替代),不捆绑 SPA,不包含
Kubernetes,不采用多数据库。
## 日常命令
| 命令 | 效果 |
|---|---|
| `make up` / `make down` | 启动 / 停止容器 |
| `make shell` (别名 `make e`) | 在应用容器内开启 shell |
| `make test` | 运行 PHPUnit,快速失败 |
| `make check` | Pint + PHPStan(pre-commit 门禁) |
| `make ci` | lint-check + 分析 + 测试(CI 一致性) |
| `make smoke` | 端到端冒烟测试 |
| `make slice context=Foo feature=Bar` | 搭建垂直切片脚手架 |
| `make adr title="My Decision"` | 搭建新的 ADR 脚手架 |
| `make docs-check` | 根据现实校验文档(路由、目标、预算) |
| `make agent-smoke` | 证明生成的脚手架代码无需修改即可通过所有门禁 |
| `make db-seed` | 演示数据(`app:seed`) |
## 项目布局
```
src/ # application code
Kernel.php # App\Kernel (Symfony MicroKernel)
SharedKernel/ # cross-context infra (repository base, problem+json listeners)
Context/{Name}/ # bounded contexts: Entity/, Repository/, Features/{Feature}/
Health/Features/Healthz/ # reference slice (JSON, /healthz + /ready)
Home/Features/Index/ # reference slice (Twig + AssetMapper, /)
config/ bin/ public/ assets/ # standard Symfony layout
migrations/ # Doctrine migrations
docs/ # ADRs and guides (Tier 2)
adr/ # ADRs with YAML front-matter
guides/ # development, testing, worker-mode, …
dev/ # codegen helpers (create-slice, new-adr, check-docs)
ops/ # deployment scripts
tests/ # mirrors src/ — tests/Context/{Name}/Features/{Feature}/
docker/ # Dockerfile, Caddyfile, php.ini
AGENTS.md # Tier-1 agent context, ≤ 2 000 tokens
```
示例切片(`Health/Healthz`、`Home/Index`、`Task`)是参考实现 —— `Healthz` 是 ADR-0005 健康检查的规范,`Task` 是完整的 entity → migration → factory → tests 垂直切片的规范;`Home/Index` 是非规范性的(对于纯 API 或 SPA 项目可以将其删除)。
## 架构决策
所有决策都存放在 [`docs/adr/`](docs/adr/) 中。每个 ADR 都带有 YAML front-matter(`status`、`date`、`audience`、`summary`),以便 agent 无需加载全部内容即可快速浏览。
| ADR | 主题 | 状态 |
|---|---|---|
| [0001](docs/adr/0001-vertical-slices.md) | 垂直切片 | 已接受 |
| [0002](docs/adr/0002-messenger-transport.md) | Messenger Transport | 已接受 |
| [0003](docs/adr/0003-pragmatic-symfony-architecture.md) | 实用主义宪章 | 已接受 |
| [0004](docs/adr/0004-frankenphp-runtime.md) | FrankenPHP Runtime | 已接受 |
| [0005](docs/adr/0005-health-checks.md) | 健康检查 | 已接受 |
| [0006](docs/adr/0006-memory-management.md) | 内存管理 | 已接受 |
| [0007](docs/adr/0007-asset-mapper.md) | AssetMapper | 已接受 |
| [0008](docs/adr/0008-testing-strategy.md) | 测试策略 | 已接受 |
| [0009](docs/adr/0009-shared-architecture.md) | 共享架构 | 已接受 |
| [0010](docs/adr/0010-documentation-and-ai-layout.md) | 文档与 AI 布局 | 已接受 |
| [0011](docs/adr/0011-event-sourcing-lite.md) | 事件溯源精简版 | 已接受 |
| [0012](docs/adr/0012-ubiquitous-language.md) | 统一语言与实体放置 | 已接受 |
| [0013](docs/adr/0013-doctrine-repository-pattern.md) | Doctrine Repository 模式 | 已接受 |
| [0014](docs/adr/0014-supply-chain-security.md) | 供应链安全 | 已接受 |
| [0015](docs/adr/0015-scheduler-and-periodic-tasks.md) | 调度器与定期任务 | 已接受 |
| [0016](docs/adr/0016-http-response-contract.md) | HTTP 响应契约 | 已接受 |
| [0017](docs/adr/0017-parallel-agent-sessions.md) | 并行 Agent 会话 | 已接受 |
| [0018](docs/adr/0018-input-validation-and-invariants.md) | 输入校验与领域不变式 | 已接受 |
## 指南
- [`docs/guides/development.md`](docs/guides/development.md) — 日常命令,切片脚手架详情
- [`docs/guides/testing.md`](docs/guides/testing.md) — 具体的 PHPUnit + Foundry + Messenger-Test 模式
- [`docs/guides/worker-mode.md`](docs/guides/worker-mode.md) — 调试 FrankenPHP worker 行为
- [`docs/guides/mercure-integration.md`](docs/guides/mercure-integration.md) — 通过 FrankenPHP 内置的 Mercure hub 实现实时 SSE
- [`docs/guides/sdk-generation.md`](docs/guides/sdk-generation.md) — 从 PHP Result DTO 自动生成 TypeScript 类型
- [`docs/guides/deployment.md`](docs/guides/deployment.md) — 单 VDS 拓扑结构,零停机部署
- [`docs/guides/disaster-recovery.md`](docs/guides/disaster-recovery.md) — 备份与恢复演练
- [`docs/guides/parallel-sessions.md`](docs/guides/parallel-sessions.md) — 为并行 agent 提供隔离的 worktree 堆栈
- [`docs/guides/supply-chain.md`](docs/guides/supply-chain.md) — 签名发布,部署前验证
## 配方(可选功能)
已在基于此骨架成长起来的真实Production项目中得到验证,以文档形式提供而非
直接捆绑:[JWT 认证](docs/recipes/jwt-auth.md) ·
[功能开关](docs/recipes/feature-flags.md) ·
[SPA 前端](docs/recipes/spa-frontend.md) ·
[预览环境](docs/recipes/preview-environments.md)。
## 紧跟模板
复刻的分支不会直接合并模板 —— 它们只应用变更。每次发布都会附带一个
[`UPGRADE.md`](UPGRADE.md) 条目,其中包含少数值得移植的更改;请参阅
[`docs/guides/fork-maintenance.md`](docs/guides/fork-maintenance.md)。
## AI agent
该仓库在根目录附带了一个 `AGENTS.md` 文件,按照约定,旨在供每个 AI 工具读取。不存在 `.cursorrules`、`.windsurfrules`、`.cursor/rules/*` 或特定工具的 prompt 文件 —— 其原理请参阅 [ADR-0010](docs/adr/0010-documentation-and-ai-layout.md)。
本地的 Claude Code 设置位于 `.claude/settings.local.json`(已添加到 gitignore)中;并行的 agent 会话通过 `dev/worktree.sh` 获得隔离的堆栈([ADR-0017](docs/adr/0017-parallel-agent-sessions.md))。
## 贡献
请参阅 [`.github/CONTRIBUTING.md`](.github/CONTRIBUTING.md)。消息头要求使用 Conventional Commits。CI 门禁包括:Pint、PHPStan level 10、PHPUnit。`make ci` 用于在本地模拟流水线。
## 许可证
MIT。
标签:CQRS, Docker, ffuf, OpenVAS, PHP, Symfony, Syscall, Web开发, 后端架构, 安全防御评估, 请求拦截