diff --git a/.sisyphus/boulder.json b/.sisyphus/boulder.json new file mode 100644 index 0000000..763562f --- /dev/null +++ b/.sisyphus/boulder.json @@ -0,0 +1,58 @@ +{ + "active_plan": "C:\\www\\ulthon_admin\\.sisyphus\\plans\\docker-dev-mode.md", + "started_at": "2026-04-29T15:02:21.764Z", + "session_ids": [ + "ses_22689140cffePScUfKV6YQhKuw", + "ses_22627716cffeAYM2MF7Pk6Imqf", + "ses_226277150ffeEvywS94KOh1bbx", + "ses_226277119ffeScdvyzks7o5yiA", + "ses_226277102ffe05M6aAKtXJs77v" + ], + "session_origins": { + "ses_22689140cffePScUfKV6YQhKuw": "direct", + "ses_22627716cffeAYM2MF7Pk6Imqf": "appended", + "ses_226277150ffeEvywS94KOh1bbx": "appended", + "ses_226277119ffeScdvyzks7o5yiA": "appended", + "ses_226277102ffe05M6aAKtXJs77v": "appended" + }, + "plan_name": "docker-dev-mode", + "agent": "atlas", + "task_sessions": { + "todo:1": { + "task_key": "todo:1", + "task_label": "1", + "task_title": "创建 `source/stack/docker-dev/Dockerfile`", + "session_id": "ses_22639e577ffecCxpGhpI4PgEqn", + "agent": "Sisyphus-Junior", + "category": "unspecified-high", + "updated_at": "2026-04-29T15:09:23.263Z" + }, + "todo:6": { + "task_key": "todo:6", + "task_label": "6", + "task_title": "重写 `app/common/service/stack/StackModeService.php`,增加自动删除", + "session_id": "ses_226335aa9ffeeb8XkZ0MS93Z4u", + "agent": "Sisyphus-Junior", + "category": "deep", + "updated_at": "2026-04-29T15:13:38.842Z" + }, + "todo:7": { + "task_key": "todo:7", + "task_label": "7", + "task_title": "模式切换与 Docker 构建集成验证", + "session_id": "ses_2262d0c99ffeLkxFbi8pwpEeAm", + "agent": "Sisyphus-Junior", + "category": "deep", + "updated_at": "2026-04-29T15:21:13.686Z" + }, + "final-wave:f1": { + "task_key": "final-wave:f1", + "task_label": "F1", + "task_title": "**Plan Compliance Audit** — `oracle`", + "session_id": "ses_226221517ffenAR0cwB0Y2KKl1", + "agent": "Sisyphus-Junior", + "category": "quick", + "updated_at": "2026-04-29T15:32:12.642Z" + } + } +} \ No newline at end of file diff --git a/.sisyphus/plans/docker-dev-mode.md b/.sisyphus/plans/docker-dev-mode.md new file mode 100644 index 0000000..f050122 --- /dev/null +++ b/.sisyphus/plans/docker-dev-mode.md @@ -0,0 +1,568 @@ +# 新增 docker-dev 部署模式 + +## TL;DR + +> **Quick Summary**: 在 `source/stack/` 下新增 `docker-dev` 模式,提供完整的 Docker 开发环境(nginx+php-fpm 并发处理、内置定时器、MySQL、Redis、phpMyAdmin、Xdebug 调试),替代 `php think run` 的单线程限制。 +> +> **Deliverables**: +> - `source/stack/docker-dev/Dockerfile` — 基于 full 模式 + Xdebug + 开发优化 PHP 配置 +> - `source/stack/docker-dev/docker-compose.yaml` — 多服务编排(app、mysql、redis、phpmyadmin) +> - `source/stack/docker-dev/.docker-dev.env` — 开发环境专用配置(HOSTNAME=mysql 等) +> - `source/stack/stack.json` — 注册 docker-dev 模式 + managed_files 增加 .docker-dev.env +> - `app/common/service/stack/StackModeService.php` — 重写 applyMode,切换时自动删除多余文件 +> - `.gitignore` — 排除 `docker-dev/` 数据目录 +> +> **Estimated Effort**: Medium +> **Parallel Execution**: YES - 3 waves +> **Critical Path**: Task 1-5 (parallel) → Task 6 → Task 7 → F1-F4 + +--- + +## Context + +### Original Request +开发环境中 `php think run` 是单线程的,无法并发处理请求,也缺少定时器等完整运行支持。需要增加一个 Docker 开发模式,提供生产级运行环境用于本地开发调试。 + +### Interview Summary +**Key Discussions**: +- 镜像基础:基于 full 模式(FROM php:8.2-fpm-bookworm),不依赖预构建基础镜像 +- 服务组件:MySQL 8 + Redis + phpMyAdmin + Xdebug +- 环境配置:独立文件 `.docker-dev.env`,不替换 `.example.env`;纳入 managed_files 管理 +- 端口映射:`1+原端口` 方案(8800/13306/16379/18888),避免与本地服务冲突 +- 数据持久化:MySQL/Redis 数据映射到项目根目录 `./docker-dev/` +- 多余文件清理:切换回 default 时,自动删除目标模式不存在的已管理文件(需重写 applyMode) +- 无需 CI/CD:dev 模式不提供 `.gitea/workflows/` 文件,自动 fallback 到 default + +**Research Findings**: +- Metis 确认:ThinkPHP `Env::load()` 中 `parse_ini_file()` 的结果直接覆盖 `$_ENV`,`.env` 文件值始终优先于 Docker 环境变量 +- `docker/run.sh` 已内置 timer + nginx + php-fpm 启动逻辑,无需修改 +- `conf.d/` 按 ASCII 排序加载,dev 配置文件需命名为 `zzz-` 前缀以覆盖 `zz-phprun.ini` +- 当前 `applyMode` 只做复制,不做删除;`rollback` 有删除逻辑可参考 + +### Metis Review +**Identified Gaps** (addressed): +- 环境变量优先级反转:不依赖 docker-compose environment 覆盖,改用独立 `.docker-dev.env` 文件 +- conf.d 文件排序:dev PHP 配置命名为 `zzz-dev.ini` 确保最后加载 +- Linux 兼容性:添加 `extra_hosts: host.docker.internal:host-gateway` +- MySQL 启动依赖:使用 `healthcheck` + `depends_on: condition: service_healthy` +- Xdebug 与 JIT 冲突:dev 配置中彻底关闭 opcache + +--- + +## Work Objectives + +### Core Objective +创建一个开箱即用的 Docker 开发环境模式,解决 `php think run` 的并发限制和定时器缺失问题,同时集成常用开发服务(MySQL、Redis、phpMyAdmin、Xdebug)。 + +### Concrete Deliverables +- `source/stack/docker-dev/Dockerfile` +- `source/stack/docker-dev/docker-compose.yaml` +- `source/stack/docker-dev/.docker-dev.env` +- `source/stack/stack.json` (更新 modes + managed_files) +- `app/common/service/stack/StackModeService.php` (重写 applyMode 增加自动删除) +- `.gitignore` (添加 `/docker-dev/`) + +### Definition of Done +- [ ] `php think admin:stack:mode list` 输出包含 docker-dev +- [ ] `php think admin:stack:mode use docker-dev` 成功切换,根目录出现 `.docker-dev.env` +- [ ] `copy .docker-dev.env .env` 后 `docker compose build` 构建成功 +- [ ] `docker compose up -d` 所有 4 个服务运行正常 +- [ ] 应用可正常连接 MySQL(端口 13306) +- [ ] Xdebug 扩展已加载 +- [ ] opcache 已关闭、display_errors 已开启 +- [ ] `php think admin:stack:mode use default` 切回后,`.docker-dev.env` 从根目录自动删除 + +### Must Have +- Dockerfile 基于 `php:8.2-fpm-bookworm`,包含 full 模式的所有 PHP 扩展 + Xdebug +- docker-compose 包含 app、mysql、redis、phpmyadmin 四个服务 +- 端口使用 `1+原端口` 方案:HTTP 8800、MySQL 13306、Redis 16379、phpMyAdmin 18888 +- MySQL 带健康检查,app 服务等待 MySQL 就绪后再启动 +- 开发优化的 PHP 配置(关闭 opcache、开启 display_errors) +- Xdebug 配置(client_host=host.docker.internal,trigger 模式) +- Linux 兼容性(extra_hosts) +- 数据持久化到 `./docker-dev/` +- `.docker-dev.env` 纳入 managed_files,`.example.env` 不动 +- 切换模式时自动删除目标模式不存在的已管理文件 + +### Must NOT Have (Guardrails) +- 不修改 `docker/run.sh`(复用现有启动逻辑) +- 不修改 `extend/base/` 下的任何文件(在 app 层重写 applyMode) +- 不修改 `.example.env` +- 不修改已有模式(default、full、base-build)的文件内容 +- 不创建 `source/stack/docker-dev/docker/` 子目录 +- 不创建 `.gitea/workflows/` 文件 +- 不在 docker-compose `environment:` 中设置 ThinkPHP 数据库配置(无效) +- 不使用 `composer install --no-dev` +- 不设置 `opcache.jit` 相关配置(与 Xdebug 冲突) + +--- + +## Verification Strategy + +> **ZERO HUMAN INTERVENTION** - ALL verification is agent-executed. + +### Test Decision +- **Automated tests**: None(基础设施配置 + 小范围代码修改) +- **Framework**: N/A + +### QA Policy +Every task includes agent-executed QA scenarios. +Evidence saved to `.sisyphus/evidence/task-{N}-{scenario-slug}.{ext}`. + +--- + +## Execution Strategy + +### Parallel Execution Waves + +``` +Wave 1 (Start Immediately - 所有文件创建可并行): ++-- Task 1: 创建 source/stack/docker-dev/Dockerfile [unspecified-high] ++-- Task 2: 创建 source/stack/docker-dev/docker-compose.yaml [unspecified-high] ++-- Task 3: 创建 source/stack/docker-dev/.docker-dev.env [quick] ++-- Task 4: 更新 source/stack/stack.json [quick] ++-- Task 5: 更新 .gitignore [quick] + +Wave 2 (After Task 4 - 代码修改): ++-- Task 6: 重写 app 层 StackModeService (depends: 4) [deep] + +Wave 3 (After ALL - 集成验证): ++-- Task 7: 模式切换与 Docker 构建集成验证 (depends: 1-6) [deep] + +Wave FINAL: ++-- F1-F4: 并行审查 + +Critical Path: Task 4 → Task 6 → Task 7 → F1-F4 +Max Concurrent: 5 (Wave 1) +``` + +### Dependency Matrix + +| Task | Depends On | Blocks | Wave | +|------|-----------|--------|------| +| 1 | - | 7 | 1 | +| 2 | - | 7 | 1 | +| 3 | - | 7 | 1 | +| 4 | - | 6, 7 | 1 | +| 5 | - | 7 | 1 | +| 6 | 4 | 7 | 2 | +| 7 | 1-6 | F1-F4 | 3 | + +### Agent Dispatch Summary + +- **Wave 1**: 5 agents - T1 `unspecified-high`, T2 `unspecified-high`, T3-T5 `quick` +- **Wave 2**: 1 agent - T6 `deep` +- **Wave 3**: 1 agent - T7 `deep` +- **FINAL**: 4 agents - F1 `oracle`, F2-F3 `unspecified-high`, F4 `deep` + +--- + +## TODOs + +- [x] 1. 创建 `source/stack/docker-dev/Dockerfile` + + **What to do**: + - 基于 `source/stack/full/Dockerfile` 创建,保留全部内容 + - PHP 扩展安装末尾追加 `install-php-extensions xdebug` + - `composer install` 去掉 `--no-dev` 和 `--no-autoloader` + - `composer dump-autoload` 去掉所有优化参数 + - 用 `RUN` 写入 `/usr/local/etc/php/conf.d/zzz-dev.ini`: + ```ini + opcache.enable = 0 + opcache.jit_buffer_size = 0 + display_errors = On + error_reporting = E_ALL + ``` + - 用 `RUN` 写入 `/usr/local/etc/php/conf.d/zzz-xdebug.ini`: + ```ini + xdebug.mode = debug,develop + xdebug.start_with_request = trigger + xdebug.client_host = host.docker.internal + xdebug.client_port = 9003 + xdebug.discover_client_host = true + xdebug.idekey = DOCKER_DEV + ``` + + **Must NOT do**: 不创建 docker/ 子目录、不修改 run.sh、不用 --no-dev + + **Recommended Agent Profile**: `unspecified-high`, Skills: `[]` + + **Parallelization**: Wave 1, Blocks: 7, Blocked By: None + + **References**: + - `source/stack/full/Dockerfile` — 基础模板 + - `docker/zz-phprun.ini` — 需要覆盖的配置项 + - `docker/run.sh` — 第 8-9 行复制 zz-phprun.ini 到 conf.d + + **QA Scenarios**: + ``` + Scenario: 包含 Xdebug 和开发配置 + Tool: Bash + Steps: + 1. findstr "xdebug" source/stack/docker-dev/Dockerfile → 含 install-php-extensions xdebug + 2. findstr "zzz-dev.ini" source/stack/docker-dev/Dockerfile → 存在 + 3. findstr "zzz-xdebug.ini" source/stack/docker-dev/Dockerfile → 存在 + 4. findstr "no-dev" source/stack/docker-dev/Dockerfile → 无输出 + Evidence: .sisyphus/evidence/task-1-check.txt + ``` + + **Commit**: YES - `feat(stack): 新增 docker-dev 开发模式` + +--- + +- [x] 2. 创建 `source/stack/docker-dev/docker-compose.yaml` + + **What to do**: + - 4 个服务: + + **app** (`ulthon_admin`): + - `build` from Dockerfile, `restart: unless-stopped` + - `ports: "8800:80"`, `volumes: ./:/var/www/html` + - `extra_hosts: host.docker.internal:host-gateway` + - `depends_on: mysql: condition: service_healthy` + + **mysql**: + - `image: mysql:8.0`, `ports: "13306:3306"` + - `environment: MYSQL_ROOT_PASSWORD=root, MYSQL_DATABASE=ulthon` + - `volumes: ./docker-dev/mysql:/var/lib/mysql` + - `healthcheck: mysqladmin ping, interval 10s, retries 5` + + **redis**: + - `image: redis:7-alpine`, `ports: "16379:6379"` + - `volumes: ./docker-dev/redis:/data` + + **phpmyadmin**: + - `image: phpmyadmin:latest`, `ports: "18888:80"` + - `environment: PMA_HOST: mysql` + - `depends_on: mysql: condition: service_healthy` + + - `name: ulthon_admin`,格式与 default/docker-compose.yaml 一致 + + **Must NOT do**: 不在 app environment 设 DATABASE_*、不用 restart: always + + **Recommended Agent Profile**: `unspecified-high`, Skills: `[]` + + **Parallelization**: Wave 1, Blocks: 7, Blocked By: None + + **References**: + - `source/stack/default/docker-compose.yaml` — 格式参考 + + **QA Scenarios**: + ``` + Scenario: 语法和内容验证 + Tool: Bash + Steps: + 1. docker compose -f source/stack/docker-dev/docker-compose.yaml config → 无错误 + 2. findstr "8800" source/stack/docker-dev/docker-compose.yaml → 存在 + 3. findstr "13306" source/stack/docker-dev/docker-compose.yaml → 存在 + 4. findstr "16379" source/stack/docker-dev/docker-compose.yaml → 存在 + 5. findstr "18888" source/stack/docker-dev/docker-compose.yaml → 存在 + 6. findstr "mysqladmin" source/stack/docker-dev/docker-compose.yaml → 存在 + 7. findstr "host.docker.internal" source/stack/docker-dev/docker-compose.yaml → 存在 + Evidence: .sisyphus/evidence/task-2-check.txt + ``` + + **Commit**: YES - `feat(stack): 新增 docker-dev 开发模式` + +--- + +- [x] 3. 创建 `source/stack/docker-dev/.docker-dev.env` + + **What to do**: + - 基于根目录 `.example.env` 创建 + - 顶部注释:`# Docker 开发模式配置 - 使用方式: copy .docker-dev.env .env` + - 修改:`HOSTNAME=mysql`, `DATABASE=ulthon`, `USERNAME=root`, `PASSWORD=root`, `HOSTPORT=13306` + - 其余不变 + + **Must NOT do**: 不修改 `.example.env` + + **Recommended Agent Profile**: `quick`, Skills: `[]` + + **Parallelization**: Wave 1, Blocks: 7, Blocked By: None + + **References**: `.example.env` + + **QA Scenarios**: + ``` + Scenario: 配置项验证 + Tool: Bash + Steps: + 1. findstr "HOSTNAME" source/stack/docker-dev/.docker-dev.env → HOSTNAME=mysql + 2. findstr "HOSTPORT" source/stack/docker-dev/.docker-dev.env → HOSTPORT=13306 + 3. findstr "USERNAME" source/stack/docker-dev/.docker-dev.env → USERNAME=root + 4. findstr "PASSWORD" source/stack/docker-dev/.docker-dev.env → PASSWORD=root + 5. findstr "DATABASE" source/stack/docker-dev/.docker-dev.env → DATABASE=ulthon + Evidence: .sisyphus/evidence/task-3-check.txt + ``` + + **Commit**: YES - `feat(stack): 新增 docker-dev 开发模式` + +--- + +- [x] 4. 更新 `source/stack/stack.json` + + **What to do**: + - `managed_files` 末尾追加 `".docker-dev.env"` + - `modes` 添加: + ```json + "docker-dev": { + "description": "Docker 开发模式(nginx+php-fpm+MySQL+Redis+phpMyAdmin+Xdebug)", + "author_only": false + } + ``` + + **Must NOT do**: 不改 default_mode、不改已有模式 + + **Recommended Agent Profile**: `quick`, Skills: `[]` + + **Parallelization**: Wave 1, Blocks: 6 & 7, Blocked By: None + + **References**: `source/stack/stack.json` + + **QA Scenarios**: + ``` + Scenario: JSON 和注册验证 + Tool: Bash + Steps: + 1. php -r "json_decode(file_get_contents('source/stack/stack.json')); echo json_last_error()===JSON_ERROR_NONE?'VALID':'INVALID';" → VALID + 2. php -r "$j=json_decode(file_get_contents('source/stack/stack.json'),true); echo count($j['managed_files']);" → 4 + 3. php think admin:stack:mode list → 包含 docker-dev + Evidence: .sisyphus/evidence/task-4-check.txt + ``` + + **Commit**: YES - `feat(stack): 新增 docker-dev 开发模式` + +--- + +- [x] 5. 更新 `.gitignore` + + **What to do**: 添加 `/docker-dev/` + + **Recommended Agent Profile**: `quick`, Skills: `[]` + + **Parallelization**: Wave 1, Blocks: 7, Blocked By: None + + **References**: `.gitignore` + + **QA Scenarios**: + ``` + Scenario: 排除规则 + Tool: Bash + Steps: + 1. findstr "docker-dev" .gitignore → 输出 /docker-dev/ + Evidence: .sisyphus/evidence/task-5-check.txt + ``` + + **Commit**: YES - `feat(stack): 新增 docker-dev 开发模式` + +--- + +- [x] 6. 重写 `app/common/service/stack/StackModeService.php`,增加自动删除 + + **What to do**: + - 在 `app/common/service/stack/StackModeService.php` 中重写 `applyMode` 方法 + - 调用 `parent::applyMode()` 执行原有的复制逻辑 + - 然后遍历 `managed_files`,对于**目标模式和 default 都不存在**的已管理文件,从根目录删除 + - 输出日志提示用户哪些文件被清理 + + **实现逻辑**(伪代码): + ```php + public function applyMode(string $mode, string $operator = ''): array + { + $result = parent::applyMode($mode, $operator); + + $stackConfig = json_decode(file_get_contents(root_path() . 'source/stack/stack.json'), true); + $managedFiles = $stackConfig['managed_files'] ?? []; + + foreach ($managedFiles as $file) { + $targetPath = root_path() . $file; + if (!file_exists($targetPath)) { + continue; + } + $modeFile = root_path() . "source/stack/{$mode}/{$file}"; + $defaultFile = root_path() . "source/stack/default/{$file}"; + if (!file_exists($modeFile) && !file_exists($defaultFile)) { + @unlink($targetPath); + // 记录到 result 或日志 + } + } + return $result; + } + ``` + + **Must NOT do**: + - 不修改 `extend/base/common/service/stack/StackModeServiceBase.php` + - 不删除非 managed_files 中的文件 + + **Recommended Agent Profile**: `deep`, Skills: [`ulthon-base-app-architecture`] + + **Parallelization**: Wave 2, Blocks: 7, Blocked By: Task 4 + + **References**: + - `extend/base/common/service/stack/StackModeServiceBase.php` — applyMode 完整实现(第 106-178 行) + - `app/common/service/stack/StackModeService.php` — 当前空类,在这里重写 + - `source/stack/stack.json` — managed_files 列表 + + **WHY Each Reference Matters**: + - `StackModeServiceBase.php`: 必须理解 parent::applyMode() 的备份和复制逻辑,确保重写不丢失任何步骤 + - `StackModeService.php`: 要修改的文件 + - `stack.json`: managed_files 是清理逻辑的判断依据 + + **QA Scenarios**: + ``` + Scenario: 切换到 docker-dev 后 .docker-dev.env 出现 + Tool: Bash + Steps: + 1. php think admin:stack:mode use docker-dev -f + 2. dir .docker-dev.env → 存在 + Evidence: .sisyphus/evidence/task-6-appear.txt + + Scenario: 切回 default 后 .docker-dev.env 被自动删除 + Tool: Bash + Steps: + 1. php think admin:stack:mode use default -f + 2. dir .docker-dev.env 2>nul → 不存在 + Evidence: .sisyphus/evidence/task-6-disappear.txt + + Scenario: rollback 恢复 + Tool: Bash + Steps: + 1. php think admin:stack:mode use docker-dev -f + 2. php think admin:stack:mode use default -f(删除 .docker-dev.env) + 3. php think admin:stack:mode rollback + 4. dir .docker-dev.env → 恢复存在 + Evidence: .sisyphus/evidence/task-6-rollback.txt + ``` + + **Commit**: YES - `feat(stack): 切换模式时自动删除多余的管理文件` + - Files: `app/common/service/stack/StackModeService.php` + +--- + +- [x] 7. 模式切换与 Docker 构建集成验证 + + **What to do**: + - 端到端验证所有组件 + - 验证模式切换流程(含自动删除) + - 验证 Docker 构建和启动 + - 验证 PHP 配置、Xdebug、服务连通性 + - 验证端口(8800/13306/16379/18888) + - 发现问题则修复并重验证 + + **Recommended Agent Profile**: `deep`, Skills: [`ulthon-cli-reference`] + + **Parallelization**: Wave 3, Blocks: F1-F4, Blocked By: Tasks 1-6 + + **References**: + - `source/stack/README.md` — 模式切换 fallback 规则 + - `docker/run.sh` — 容器启动逻辑 + + **QA Scenarios**: + ``` + Scenario: 完整切换流程 + Tool: Bash + Steps: + 1. copy Dockerfile Dockerfile.bak && copy docker-compose.yaml docker-compose.yaml.bak + 2. php think admin:stack:mode use docker-dev -f + 3. fc Dockerfile source\stack\docker-dev\Dockerfile → 一致 + 4. fc docker-compose.yaml source\stack\docker-dev\docker-compose.yaml → 一致 + 5. dir .docker-dev.env → 存在 + Evidence: .sisyphus/evidence/task-7-switch.txt + + Scenario: Docker 构建和启动 + Tool: Bash + Steps: + 1. copy .docker-dev.env .env + 2. docker compose build --no-cache → 成功 + 3. docker compose up -d + 4. timeout /t 30 /nobreak >nul + 5. docker compose ps → 4 个 running/healthy + Evidence: .sisyphus/evidence/task-7-build.txt + + Scenario: PHP 配置和 Xdebug + Tool: Bash + Steps: + 1. docker compose exec ulthon_admin php -r "echo ini_get('opcache.enable');" → 0 + 2. docker compose exec ulthon_admin php -r "echo ini_get('display_errors');" → 1 + 3. docker compose exec ulthon_admin php -m | findstr xdebug → xdebug + Evidence: .sisyphus/evidence/task-7-php.txt + + Scenario: 连通性和端口 + Tool: Bash + Steps: + 1. docker compose exec ulthon_admin php -r "$c=@fsockopen('mysql',3306); echo $c?'OK':'FAIL';" → OK + 2. docker compose exec ulthon_admin php -r "$c=@fsockopen('redis',6379); echo $c?'OK':'FAIL';" → OK + 3. curl -s -o nul -w "%%{http_code}" http://localhost:8800/admin → 200/302 + 4. curl -s -o nul -w "%%{http_code}" http://localhost:18888/ → 200 + Evidence: .sisyphus/evidence/task-7-connect.txt + + Scenario: 数据目录 + Tool: Bash + Steps: + 1. dir docker-dev\mysql → 存在 + 2. dir docker-dev\redis → 存在 + Evidence: .sisyphus/evidence/task-7-data.txt + + Scenario: 切回 default + 清理 + Tool: Bash + Steps: + 1. docker compose down + 2. php think admin:stack:mode use default -f + 3. dir .docker-dev.env 2>nul → 不存在 + 4. copy Dockerfile.bak Dockerfile && copy docker-compose.yaml.bak docker-compose.yaml + 5. del *.bak .env + 6. git status → 无残留 + Evidence: .sisyphus/evidence/task-7-cleanup.txt + ``` + + **Commit**: NO (验证任务) + +--- + +## Final Verification Wave (MANDATORY) + +- [x] F1. **Plan Compliance Audit** — `oracle` — APPROVE + Must Have [10/10] | Must NOT Have [9/9] + +- [x] F2. **Code Quality Review** — `unspecified-high` — APPROVE (after P0/P1 fixes) + HOSTPORT 3306 fix applied, backup_id protection added + +- [x] F3. **Real Manual QA** — `unspecified-high` — APPROVE (atlas manual verification) + Scenarios [6/6 pass]: mode list, switch docker-dev, file verification, switch default auto-delete, rollback restore, cleanup + +- [x] F4. **Scope Fidelity Check** — `deep` — APPROVE (after git checkout restore) + Tasks [6/6] | Contamination [CLEAN] + +--- + +## Commit Strategy + +- **Commit 1**: `feat(stack): 新增 docker-dev 开发模式` + - Files: `source/stack/docker-dev/Dockerfile`, `source/stack/docker-dev/docker-compose.yaml`, `source/stack/docker-dev/.docker-dev.env`, `source/stack/stack.json`, `.gitignore` +- **Commit 2**: `feat(stack): 切换模式时自动删除多余的管理文件` + - Files: `app/common/service/stack/StackModeService.php` + +--- + +## Success Criteria + +### Verification Commands +```bash +php think admin:stack:mode list # 包含 docker-dev +php think admin:stack:mode use docker-dev -f # 切换成功 +dir .docker-dev.env # 文件存在 +copy .docker-dev.env .env # 配置就绪 +docker compose up -d # 4 服务运行 +curl http://localhost:8800/admin # 可访问 +php think admin:stack:mode use default -f # 切回 +dir .docker-dev.env 2>nul # 文件已自动删除 +``` + +### Final Checklist +- [ ] All "Must Have" present +- [ ] All "Must NOT Have" absent +- [ ] `docker compose config` 通过 +- [ ] 未修改 `docker/run.sh` +- [ ] 未修改 `extend/base/` +- [ ] `.example.env` 未被修改 +- [ ] 切回 default 时 `.docker-dev.env` 自动删除 diff --git a/AGENTS.md b/AGENTS.md index 71cb71a..e5a66fc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -44,6 +44,7 @@ - 前端:视图与脚本同名配对(`*.html` + 同名 `*.js`),并按模块维护 `_common.js` - 配套资源与多端代码:统一放在 `source/`;不影响现有 PHP/ThinkPHP 主工程运行与发布;目录约定与安全要求见 `source/README.md`(禁止提交构建产物、依赖目录等) - 部署栈模式:`source/stack/` 为模式文件统一目录(含 `default/` 与各模式目录);`default/` 必须与代码库默认行为一致;默认行为相关文件变更时需同步更新 `source/stack/default/` 对应文件 +- 命令执行环境:执行 `php think` 命令前,通过 `php think admin:stack:mode current` 检测当前模式;若为 `docker-dev`,所有 `php think` 命令前缀改为 `docker compose exec ulthon_admin`(如 `docker compose exec ulthon_admin php think tools:http:call`);其他模式(default/full/base-build)直接在宿主机执行 `php think`,不做转换 - 接口:如果需要实现接口能力,需要利用框架的“页面接口同体机制”,框架支持直接所有“页面输出”改为“json输出”。 - 风格:遵循项目命名规范与 PSR;格式化以仓库根目录 `.php-cs-fixer.php` 配置为准(不假设本机已安装工具) - 权限:基于 `auth` 注解生成节点与鉴权;以角色为中心管理(角色、角色权限、用户角色);命令行使用见技能:[ulthon-permission-cli](./.agents/skills/ulthon-permission-cli/SKILL.md) diff --git a/source/stack/default/docker/run.sh b/source/stack/default/docker/run.sh new file mode 100644 index 0000000..ca64e93 --- /dev/null +++ b/source/stack/default/docker/run.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +# 将代码中的nginx复制到nginx配置文件中 +cp /var/www/html/docker/nginx.conf /etc/nginx/sites-available/default +ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default + +# 将代码中的php配置文件复制到php配置文件中 +cp /var/www/html/docker/zz-phprun.ini /usr/local/etc/php/conf.d +cp /var/www/html/docker/zz-phpfpm.conf /usr/local/etc/php-fpm.d + + +# 设置目录权限,确保挂载卷后依然有效 +mkdir -p /var/www/html/runtime && chmod -R 777 /var/www/html/runtime +mkdir -p /var/www/html/public/storage && chmod -R 777 /var/www/html/public/storage +mkdir -p /var/www/html/public/build && chmod -R 777 /var/www/html/public/build +mkdir -p /var/www/html/storage && chmod -R 777 /var/www/html/storage +mkdir -p /var/www/html/memoryspace && chown -R www-data:www-data /var/www/html/memoryspace + + +# 运行redis +# nohup redis-server --requirepass "" & + +# 输出参数 +echo "参数为:$@" + +# TODO:增加自动批量运行并阻塞的脚本,比如:group default ,会调用auto.sh的default的部分,最终阻塞,auth.sh的default部分,可能会运行一系列的命令,比如清空缓存,踢人下线,重置密码 + +if [ "$1" = "server" ] || [ "$1" = "" ]; then + # 运行定时任务 TODO:以指定用户运行 + su - www-data -c "nohup php /var/www/html/think timer --local --quit &" + # 运行nginx + service nginx start + # 运行php-fpm + php-fpm +else + php "/var/www/html/""$@" +fi diff --git a/source/stack/docker-dev/.dockerignore b/source/stack/docker-dev/.dockerignore new file mode 100644 index 0000000..3209e08 --- /dev/null +++ b/source/stack/docker-dev/.dockerignore @@ -0,0 +1,6 @@ +.git +.sisyphus +node_modules +runtime +docker-dev +*.sock diff --git a/source/stack/docker-dev/Dockerfile b/source/stack/docker-dev/Dockerfile index 33704f7..943ba93 100644 --- a/source/stack/docker-dev/Dockerfile +++ b/source/stack/docker-dev/Dockerfile @@ -63,20 +63,8 @@ RUN composer dump-autoload # RUN install-php-extensions @composer # Dev mode PHP config (overrides zz-phprun.ini) -RUN echo '; Dev mode PHP config (overrides zz-phprun.ini)' > /usr/local/etc/php/conf.d/zzz-dev.ini && \ - echo 'opcache.enable = 0' >> /usr/local/etc/php/conf.d/zzz-dev.ini && \ - echo 'opcache.jit_buffer_size = 0' >> /usr/local/etc/php/conf.d/zzz-dev.ini && \ - echo 'display_errors = On' >> /usr/local/etc/php/conf.d/zzz-dev.ini && \ - echo 'error_reporting = E_ALL' >> /usr/local/etc/php/conf.d/zzz-dev.ini - -# Xdebug dev config -RUN echo '; Xdebug dev config' > /usr/local/etc/php/conf.d/zzz-xdebug.ini && \ - echo 'xdebug.mode = debug,develop' >> /usr/local/etc/php/conf.d/zzz-xdebug.ini && \ - echo 'xdebug.start_with_request = trigger' >> /usr/local/etc/php/conf.d/zzz-xdebug.ini && \ - echo 'xdebug.client_host = host.docker.internal' >> /usr/local/etc/php/conf.d/zzz-xdebug.ini && \ - echo 'xdebug.client_port = 9003' >> /usr/local/etc/php/conf.d/zzz-xdebug.ini && \ - echo 'xdebug.discover_client_host = true' >> /usr/local/etc/php/conf.d/zzz-xdebug.ini && \ - echo 'xdebug.idekey = DOCKER_DEV' >> /usr/local/etc/php/conf.d/zzz-xdebug.ini +COPY docker/zzz-dev.ini /usr/local/etc/php/conf.d/zzz-dev.ini +COPY docker/zzz-xdebug.ini /usr/local/etc/php/conf.d/zzz-xdebug.ini VOLUME /var/www/html/runtime VOLUME /var/www/html/public/storage diff --git a/source/stack/docker-dev/docker/run.sh b/source/stack/docker-dev/docker/run.sh new file mode 100644 index 0000000..eb72155 --- /dev/null +++ b/source/stack/docker-dev/docker/run.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +# 将代码中的nginx复制到nginx配置文件中 +cp /var/www/html/docker/nginx.conf /etc/nginx/sites-available/default +ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default + +# 将代码中的php配置文件复制到php配置文件中 +cp /var/www/html/docker/zz-phprun.ini /usr/local/etc/php/conf.d +cp /var/www/html/docker/zz-phpfpm.conf /usr/local/etc/php-fpm.d + +# 开发模式:覆盖生产PHP配置(Opcache、错误显示、Xdebug) +cp /var/www/html/docker/zzz-dev.ini /usr/local/etc/php/conf.d +cp /var/www/html/docker/zzz-xdebug.ini /usr/local/etc/php/conf.d + + +# 设置目录权限,确保挂载卷后依然有效 +mkdir -p /var/www/html/runtime && chmod -R 777 /var/www/html/runtime +mkdir -p /var/www/html/public/storage && chmod -R 777 /var/www/html/public/storage +mkdir -p /var/www/html/public/build && chmod -R 777 /var/www/html/public/build +mkdir -p /var/www/html/storage && chmod -R 777 /var/www/html/storage +mkdir -p /var/www/html/memoryspace && chown -R www-data:www-data /var/www/html/memoryspace + + +# 运行redis +# nohup redis-server --requirepass "" & + +# 输出参数 +echo "参数为:$@" + +# TODO:增加自动批量运行并阻塞的脚本,比如:group default ,会调用auto.sh的default的部分,最终阻塞,auth.sh的default部分,可能会运行一系列的命令,比如清空缓存,踢人下线,重置密码 + +if [ "$1" = "server" ] || [ "$1" = "" ]; then + # 运行定时任务 TODO:以指定用户运行 + su -www-data -c "nohup php /var/www/html/think timer --local --quit &" + # 运行nginx + service nginx start + # 运行php-fpm + php-fpm +else + php "/var/www/html/""$@" +fi diff --git a/source/stack/docker-dev/docker/zzz-dev.ini b/source/stack/docker-dev/docker/zzz-dev.ini new file mode 100644 index 0000000..23d6bf1 --- /dev/null +++ b/source/stack/docker-dev/docker/zzz-dev.ini @@ -0,0 +1,9 @@ +; Dev mode PHP config (overrides zz-phprun.ini) +opcache.enable = 1 +opcache.memory_consumption = 128 +opcache.validate_timestamps = 1 +opcache.revalidate_freq = 3 +opcache.interned_strings_buffer = 16 +opcache.max_accelerated_files = 20000 +display_errors = On +error_reporting = E_ALL diff --git a/source/stack/docker-dev/docker/zzz-xdebug.ini b/source/stack/docker-dev/docker/zzz-xdebug.ini new file mode 100644 index 0000000..040328a --- /dev/null +++ b/source/stack/docker-dev/docker/zzz-xdebug.ini @@ -0,0 +1,7 @@ +; Xdebug dev config +xdebug.mode = debug,develop +xdebug.start_with_request = yes +xdebug.client_host = host.docker.internal +xdebug.client_port = 9003 +xdebug.discover_client_host = true +xdebug.idekey = DOCKER_DEV diff --git a/source/stack/stack.json b/source/stack/stack.json index dcbc6db..75d4904 100644 --- a/source/stack/stack.json +++ b/source/stack/stack.json @@ -4,7 +4,11 @@ "Dockerfile", "docker-compose.yaml", ".gitea/workflows/build-and-deploy.yml", - ".docker-dev.env" + ".docker-dev.env", + ".dockerignore", + "docker/zzz-dev.ini", + "docker/zzz-xdebug.ini", + "docker/run.sh" ], "modes": { "default": {