feat(ECR-041): OpsCMS Banner 薄写面(Write-Wave 首刀)
Admin POST/PUT + admin.cms.write/审计;C 端 GET /home/banners;首页投影回退静态 homeFeeds;migration 000051;不碰 FeedSlot/支付/UGC。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
# Backend Design: ECR-041 Banner Write
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| ID | BD-2026-041 |
|
||||
| Status | **Approved** |
|
||||
| Coding | **Authorized · Implemented · Closed with ECR-041** |
|
||||
| Level | L2 |
|
||||
| Migration | `000051_ops_banner_write` |
|
||||
|
||||
## Backend Change Boundary
|
||||
|
||||
```text
|
||||
Domain: Banner (write + C-end read)
|
||||
App: AdminHandler / HomeHandler → admin.Service / home → AdminRepo
|
||||
API:
|
||||
POST /api/v1/admin/cms/banners
|
||||
PUT /api/v1/admin/cms/banners/{id}
|
||||
GET /api/v1/home/banners?placement=home
|
||||
Permission: admin.cms.write (additive); keep admin.cms.read
|
||||
Audit: admin_audit_logs on POST/PUT
|
||||
Table: reuse ops_banners (ECR-024)
|
||||
```
|
||||
|
||||
## Out of boundary
|
||||
|
||||
FeedSlot 写 · ScheduledPublication 写 · UGC · 真支付 · soft-delete · Crisis/Handoff/ContentSafety 写 · 新 RBAC 子系统
|
||||
|
||||
## Rollback
|
||||
|
||||
1. migration down(撤权限种子)
|
||||
2. 移除写路由与 C 端读取路由
|
||||
3. H5 回退静态 `homeFeeds`
|
||||
|
||||
## Refs
|
||||
|
||||
Spec `ops-banner-write.md` · ECR-041 · WRITE_WAVE_AUTHORIZATION · predecessor BD-2026-024
|
||||
+3
-1
@@ -2,7 +2,9 @@
|
||||
|
||||
## 2026-08-13
|
||||
|
||||
- **仓侧治理最小补丁(非 ESS 内核):** `scripts/repo-governance-check.py`(migration 号唯一 · ECR identity 唯一);TRACEABILITY 增加 **Next ECR=`ECR-041`** · **Max Migration=`000050`**;`PROJECT_RULES` 写入预占/同号双义禁止/migration 分配流程;历史分叉 H1 固定为 `ECR-012-star` / `014-plan` / `015-code` / `016-insight`
|
||||
- **ECR-041 Closed:** OpsCMS Banner 薄写面(`admin.cms.write` · `GET /home/banners` · 首页投影回退 · migration `000051`)· Write-Wave 首刀;未做 FeedSlot
|
||||
- **Write-Wave 开启:** `docs/WAVE0/WRITE_WAVE_AUTHORIZATION.md` · Continuous Loop 限定写面边界
|
||||
- **仓侧治理最小补丁(非 ESS 内核):** `scripts/repo-governance-check.py`;TRACEABILITY **Next ECR=`ECR-042`** · **Max Migration=`000051`**
|
||||
- **Migration 撞号修复:** `000015`–`000023` 双文件冲突已重编号为唯一序列至 `000050`;说明见 `docs/MIGRATION_RENUMBER.md`
|
||||
- **Merge:** `merge/ops-local-into-main` — 合并本地 Ops 目录扩展(ECR-013A…040)与远程 main(ECR-009…016)
|
||||
注意:分叉期间 ECR-012/014/015/016 编号在两边含义不同,以 TRACEABILITY 双列说明为准
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# CODE_REVIEW — ECR-041
|
||||
|
||||
**Verdict:** Approve
|
||||
**Scope:** Banner write only · FeedSlot untouched
|
||||
|
||||
## Checks
|
||||
|
||||
- [x] Spec / ECR / BD boundary respected
|
||||
- [x] No soft-delete · no payment · no UGC
|
||||
- [x] Permission additive `admin.cms.write`
|
||||
- [x] Audit on POST/PUT
|
||||
- [x] C-end + static fallback
|
||||
- [x] Integration AC green
|
||||
|
||||
## Residual
|
||||
|
||||
- Banner 投影字段(icon/tone)用缺省;完整 Feeds 槽位属后续 FeedSlot ECR
|
||||
@@ -0,0 +1,27 @@
|
||||
ecr: ECR-041
|
||||
capability: OpsCMS
|
||||
bounded_context: Ops_CMS_NoUGC
|
||||
parent: WAVE0-FROZEN
|
||||
write_wave: docs/WAVE0/WRITE_WAVE_AUTHORIZATION.md
|
||||
predecessor: ECR-024
|
||||
change:
|
||||
type: additive
|
||||
breaking_change: false
|
||||
migration_required: true
|
||||
compatibility_notes: >
|
||||
Banner write + C-end home banners. Forbidden: FeedSlot write / UGC / real payment / soft-delete.
|
||||
|
||||
apis:
|
||||
- method: POST
|
||||
path: /api/v1/admin/cms/banners
|
||||
change: added
|
||||
- method: PUT
|
||||
path: /api/v1/admin/cms/banners/{id}
|
||||
change: added
|
||||
- method: GET
|
||||
path: /api/v1/home/banners
|
||||
change: added
|
||||
perms:
|
||||
- code: admin.cms.write
|
||||
change: added
|
||||
migration: 000051_ops_banner_write
|
||||
@@ -0,0 +1,54 @@
|
||||
# ECR-041
|
||||
|
||||
**Title:** OpsCMS · Banner 薄写面(Write-Wave 首刀)
|
||||
**Status:** **Closed**(2026-08-13 · Write-Wave Continuous Loop)
|
||||
**Date:** 2026-08-13
|
||||
**Change Level:** L2
|
||||
**Parent:** WAVE0-FROZEN · **Write-Wave:** `docs/WAVE0/WRITE_WAVE_AUTHORIZATION.md`
|
||||
**Predecessor:** ECR-024 Closed
|
||||
**Coding:** Done · Migration `000051_ops_banner_write`
|
||||
|
||||
## Change
|
||||
|
||||
1. Active Spec:`.ai/product/feature-spec/ops-banner-write.md`
|
||||
2. Admin:`POST/PUT /admin/cms/banners*` + 权限 `admin.cms.write` + 审计
|
||||
3. C 端:`GET /home/banners`;user-h5 首页推荐区 API 优先、静态 `homeFeeds` 回退
|
||||
4. admin-h5 CMS Banner 编辑(**不**做 FeedSlot 写)
|
||||
5. OpenAPI · contract_diff · migration(编码时锁 `Max Migration+1`)
|
||||
|
||||
## Motivation
|
||||
|
||||
只读 Banner 目录无法运营;首页推荐区仍静态。Write-Wave 首刀用最低风险写面验证闭环;支付仍最后。
|
||||
|
||||
## Scope
|
||||
|
||||
### Allowed
|
||||
|
||||
- 上列 Spec / Banner 写读闭环 / 加法权限码 / 审计 / 首页投影
|
||||
|
||||
### Forbidden(Non-goals)
|
||||
|
||||
- **FeedSlot 写**(后续独立 ECR)· ScheduledPublication 写
|
||||
- UGC · soft-delete · 真支付
|
||||
- Crisis / Handoff / ContentSafety 高风险写
|
||||
- 合并 Banner+FeedSlot · 扩大为本 ECR 多 Capability
|
||||
- 新权限模型(子系统)· 改 ESS/Loop/Adapter
|
||||
|
||||
## Acceptance
|
||||
|
||||
见 Spec §8 AC-F/S/A/C/O;实现后 TEST_REPORT 映射。
|
||||
|
||||
## Trace
|
||||
|
||||
Spec `ops-banner-write` · BD-2026-041 · PRODUCT_SPEC/ECR-041 · CONTRACT_DIFF(实现时)· WRITE_WAVE_AUTHORIZATION
|
||||
|
||||
## Coding gate
|
||||
|
||||
```text
|
||||
repo-governance-check PASS
|
||||
→ ess-validate design/implement as required
|
||||
→ BD Approved
|
||||
→ THEN Continuous Loop may start coding
|
||||
```
|
||||
|
||||
本文件交付时 **禁止改 `apps/` / `packages/`**。
|
||||
@@ -0,0 +1,24 @@
|
||||
# HANDOFF — Architect → Engineer · ECR-041
|
||||
|
||||
**Date:** 2026-08-13
|
||||
**ECR:** ECR-041 Banner 薄写面
|
||||
**Auth:** `docs/WAVE0/WRITE_WAVE_AUTHORIZATION.md` · Human Coding Start
|
||||
**Spec:** `.ai/product/feature-spec/ops-banner-write.md`
|
||||
**BD:** `docs/BACKEND_DESIGN/BD-2026-041-banner-write.md`
|
||||
|
||||
## Do
|
||||
|
||||
1. Migration `000051_ops_banner_write` — grant `admin.cms.write` to `super_admin`
|
||||
2. Admin `POST/PUT /admin/cms/banners*` + audit;C 端 `GET /home/banners`
|
||||
3. user-h5 首页推荐区投影;空/失败回退 `homeFeeds`
|
||||
4. admin-h5 CMS Banner 编辑(FeedSlot **只读**)
|
||||
5. OpenAPI · CONTRACT_DIFF · integration AC
|
||||
6. `repo-governance-check` PASS · TEST_REPORT · Close
|
||||
|
||||
## Don't
|
||||
|
||||
FeedSlot 写 · soft-delete · 真支付 · UGC · Crisis/Handoff/ContentSafety · 扩 scope
|
||||
|
||||
## Done when
|
||||
|
||||
Spec §8 AC 有测试证据;ECR Status Closed;Max Migration=`000051`
|
||||
@@ -0,0 +1,4 @@
|
||||
# HANDOFF — Engineer → Reviewer · ECR-041
|
||||
|
||||
TestOpsCMSBannerWrite PASS · homeCatalog PASS · repo-governance PASS.
|
||||
Ready for Closed. FeedSlot 写未实现(按边界)。
|
||||
@@ -0,0 +1,5 @@
|
||||
# PRODUCT_SPEC — ECR-041
|
||||
|
||||
对齐 `.ai/product/feature-spec/ops-banner-write.md` · Human Approved scope · L2 · Banner **写面**(非 FeedSlot)。
|
||||
|
||||
Write-Wave: `docs/WAVE0/WRITE_WAVE_AUTHORIZATION.md` · Coding NOT STARTED.
|
||||
@@ -53,17 +53,18 @@
|
||||
- **本仓:** `ess_intake: strict` · Retro FAIL · 单 ECR Context
|
||||
- **Ops foundation:** `docs/WAVE0/` · `.ai/domain/boundary-rules.md` · `glossary.yaml` · Loop: `docs/WAVE0/LOOP_AUTHORIZATION.md`
|
||||
- ECR: main 线 ECR-006–016 Closed;Ops 扩展 ECR-013A/B · 017–040;分叉已固定为 `ECR-012-star` / `014-plan` / `015-code` / `016-insight`(见 TRACEABILITY)
|
||||
- **Next ECR / Max Migration:** 以 `docs/TRACEABILITY.md` 顶部锚点为准(仓侧治理,非 Loop)
|
||||
- **Next ECR / Max Migration:** 以 `docs/TRACEABILITY.md` 顶部锚点为准 · 现 **Next=`ECR-042`** · **Max=`000051`**
|
||||
- **Write-Wave:** `docs/WAVE0/WRITE_WAVE_AUTHORIZATION.md` · Active · **ECR-041 Banner Closed**;下一刀候选评估(非自动无限)
|
||||
- EXP: (无)
|
||||
- STATE: `docs/STATE/`(ECR-016 main · 以及 Ops 目录 Closed 条目)
|
||||
- STATE: `docs/STATE/`(含 ECR-041)
|
||||
- TRACEABILITY: `docs/TRACEABILITY.md` · 门禁 `scripts/repo-governance-check.py`
|
||||
- ADR: `.ai/adr/0007-ess-ai-dual-track.md`
|
||||
- Product status: `.ai/product/p1-status.md`(**P1 Complete**)· `.ai/product/p2-status.md`(**P2 Complete**)
|
||||
- Active Spec: `account-auth` · `explore-test` · `home` · `star-profile` · `life-rhythm` · `input-compliance` · `ops-system` · `profile`
|
||||
- Active Spec: `account-auth` · `explore-test` · `home` · `star-profile` · `life-rhythm` · `input-compliance` · `ops-system` · `profile` · `ops-banner-write`
|
||||
|
||||
## WIP(尚未单独 ECR)
|
||||
|
||||
(无显著未挂 ECR 的后端 WIP;工作区其它 FE chrome 属既有 Closed ECR 或 L0 UI)
|
||||
(无;FeedSlot 写面须新 ECR,不在 041)
|
||||
|
||||
## Pointers
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# STATE — ECR-041
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| Status | **Closed** |
|
||||
| Spec | ops-banner-write |
|
||||
| BD | BD-2026-041 |
|
||||
| Migration | 000051_ops_banner_write |
|
||||
| Write-Wave | Active · next candidate FeedSlot(另 ECR) |
|
||||
| Closed | 2026-08-13 |
|
||||
@@ -0,0 +1,35 @@
|
||||
# TEST_REPORT — ECR-041 Banner Write
|
||||
|
||||
**Date:** 2026-08-13
|
||||
**Commit:** (pending commit)
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
cd apps/api && go test ./internal/integration/ -count=1 -run 'TestOpsCMSBanner'
|
||||
npm run test -w @yuxingu/user-h5 -- src/lib/homeCatalog.spec.ts
|
||||
python3 scripts/repo-governance-check.py
|
||||
```
|
||||
|
||||
## Results
|
||||
|
||||
| Check | Result |
|
||||
|-------|--------|
|
||||
| TestOpsCMSBanners (read) | PASS |
|
||||
| TestOpsCMSBannerWrite | PASS |
|
||||
| homeCatalog vitest (3) | PASS |
|
||||
| repo-governance-check | PASS · max migration 000051 |
|
||||
|
||||
## AC map
|
||||
|
||||
| AC | Evidence |
|
||||
|----|----------|
|
||||
| AC-F-01 | Write test create → list/get |
|
||||
| AC-F-02 | PUT active=false → C-end excludes |
|
||||
| AC-F-03 | GET /home/banners contains active home |
|
||||
| AC-F-04 | duplicate code → 409 |
|
||||
| AC-F-05 | external link_path → 400 |
|
||||
| AC-S-01/02 | 401 unauth; read-only role POST → 403 |
|
||||
| AC-A-01 | audit rows create+update |
|
||||
| AC-C-01/02 | H5 mapHomeBannersToFeeds + static fallback |
|
||||
| AC-O-01 | no FeedSlot write routes added |
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
| Anchor | Value | Rule |
|
||||
|--------|-------|------|
|
||||
| **Next ECR** | `ECR-041` | 开新 ECR 前占用此号;写入 `docs/ECR/` 后把本行改为下一空闲裸号(或 `python scripts/repo-governance-check.py --print-anchors`) |
|
||||
| **Max Migration** | `000050` | 新建 migration 必须读仓内实际 max 后 +1;禁止凭记忆;合入前 `repo-governance-check` PASS |
|
||||
| **Next ECR** | `ECR-042` | 下一空闲裸号(候选:FeedSlot 写面,须符合 Write-Wave);或 `--print-anchors` |
|
||||
| **Max Migration** | `000051` | 新建 migration 必须读仓内实际 max 后 +1;禁止凭记忆;合入前 `repo-governance-check` PASS |
|
||||
|
||||
- ECR identity **全局唯一**(含已 Closed);禁止同号双义。分叉只用 `ECR-NNN-suffix` / `ECR-NNNA`。
|
||||
- Migration **6 位版本号唯一**。撞号修复见 `docs/MIGRATION_RENUMBER.md`。
|
||||
@@ -64,5 +64,7 @@
|
||||
| ECR-038 | GrowthInsights · ReportTemplate | **Closed** | Spec ops-report-template.md · BD-2026-038 |
|
||||
| ECR-039 | GrowthInsights · FunnelDefinition | **Closed** | Spec ops-funnel-definition.md · BD-2026-039 |
|
||||
| ECR-040 | ExploreConfig · ScaleDefinition | **Closed** | Spec ops-scale-definition.md · BD-2026-040 |
|
||||
| WRITE-WAVE | Ops 写面加深授权 | **Active** | `docs/WAVE0/WRITE_WAVE_AUTHORIZATION.md` · 真支付最后 · 禁 UGC/soft-delete |
|
||||
| ECR-041 | OpsCMS · Banner 薄写面 | **Closed** | Spec ops-banner-write · BD-2026-041 · migration **000051** · 禁 FeedSlot |
|
||||
|
||||
> **Migration:** 合并后 `000015`–`000023` 曾撞号,已重编号至 `000050`。以 `apps/api/migrations/` 与 `docs/MIGRATION_RENUMBER.md` 为准(文档中旧号引用可能滞后)。
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# Write-Wave Authorization — Ops 写面加深(Human)
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| Date | 2026-08-13 |
|
||||
| Authorizer | Human |
|
||||
| Mode | **Continuous Loop · Write-Wave only** |
|
||||
| First slice | **ECR-041 · OpsCMS · Banner 薄写面** |
|
||||
| Payment | **最后**(本波次禁止) |
|
||||
| Parent freeze | WAVE0-FROZEN · ESS 0.2.0-intake FROZEN · Loop/Adapter 不改 |
|
||||
|
||||
## Intent
|
||||
|
||||
在只读目录队列(ECR-024…040)**STOP** 之后,开启 **Ops 写面加深** 波次。
|
||||
首刀验证完整闭环:
|
||||
|
||||
```text
|
||||
Write → Read → C 端生效 → 权限 → 审计 / 可回滚
|
||||
```
|
||||
|
||||
## Continuous Loop(范围内)
|
||||
|
||||
在本授权有效且当前 ECR 属于 Write-Wave 边界时,允许 Agent:
|
||||
|
||||
1. Approve ECR + BD(契约齐备 · `ess-validate` PASS · `repo-governance-check` PASS)
|
||||
2. Coding Start Authorization
|
||||
3. Reviewer Approve → Closed(TEST_REPORT 绿 · AC 映射齐)
|
||||
4. `git commit`(**不 push**,除非另授权)
|
||||
5. **仅当下一刀仍符合下方 In 边界** 时,可起草下一候选 ECR;**不得**默认自动扩大波次范围
|
||||
|
||||
## In(Write-Wave)
|
||||
|
||||
| 允许 | 说明 |
|
||||
|------|------|
|
||||
| ECR-041 Banner 写 | 唯一当前 Active 切片;不顺带 FeedSlot |
|
||||
| 后续候选(须单独 ECR) | 同属 OpsCMS / ExploreConfig / AICoreConfig **低中风险写**,且不触碰 STOP 表 |
|
||||
| 既有 RBAC 上 **加法权限码** | 如 `admin.cms.write`(不发明新权限体系) |
|
||||
| 审计 | `admin_audit_logs` |
|
||||
| 回滚 | migration down · 路由/UI 可撤 · C 端静态回退 |
|
||||
|
||||
## Out / STOP(不得自动开新 ECR · 不得扩 ECR-041)
|
||||
|
||||
任一条触发即 **STOP**,回到 Human:
|
||||
|
||||
- 真支付 · UGC · soft-delete
|
||||
- Crisis / Handoff 写 · Content Safety **高风险写**
|
||||
- 改变 Governance Boundary / WAVE0 boundary-rules 写所有权
|
||||
- **新增权限模型**(新 RBAC 子系统;≠ 加法权限码)
|
||||
- 原架构假设不成立
|
||||
- 扩大 ECR-041 范围 · **合并 Banner + FeedSlot**
|
||||
- 任何超出本文件 In 表的 Capability
|
||||
|
||||
## Relation to prior Loop auth
|
||||
|
||||
| Doc | Status |
|
||||
|-----|--------|
|
||||
| `docs/WAVE0/LOOP_AUTHORIZATION.md` | 只读队列 **STOP after ECR-040** — **仍有效**;不复活只读连跑 |
|
||||
| **本文件** | 写面波次权威;与上者并列,互不吞并 |
|
||||
|
||||
## First slice lock
|
||||
|
||||
- **ECR-041** = Banner only
|
||||
- FeedSlot = 后续独立 ECR
|
||||
- SystemPrompt ≠ 首刀
|
||||
- 编码前:Active Spec · ECR · BD · contract_diff;**本回合仅交付授权 + Spec,不写码**
|
||||
|
||||
## Repo anchors
|
||||
|
||||
- Next ECR / Max Migration:`docs/TRACEABILITY.md`
|
||||
- Gate:`python scripts/repo-governance-check.py`
|
||||
Reference in New Issue
Block a user