- 新增迁移回滚、AppData 退场、小宝后台任务 runbook\n- 新增生产 readiness 证据清单和 runbook placeholder 扫描\n- 更新部署文档与路线图到 V2.8 运维闭环阶段\n\nCo-Authored-By: GPT-5 Codex <codex@openai.com>
73 lines
3.9 KiB
Markdown
73 lines
3.9 KiB
Markdown
# AppData Retirement Runbook
|
|
|
|
Use this when retiring an AppData key after its domain writes have moved to relation-table APIs. The order is fixed: backup, measure, freeze writes, compare, remove fallback, archive.
|
|
|
|
## Scope Gate
|
|
|
|
Retire one AppData key family at a time. Good candidates have domain CRUD writes, read APIs, pagination boundaries, audit events, and a rollback path.
|
|
|
|
## Preparation
|
|
|
|
```bash
|
|
pnpm backup:postgres -- --env-file .env.production
|
|
pnpm backup:server-data -- --env-file .env.production
|
|
pnpm deploy:smoke -- --base-url http://localhost
|
|
```
|
|
|
|
Record the key family being retired, the owning domain API, and the relation tables that replace it.
|
|
|
|
## Count And Consistency Checks
|
|
|
|
Run counts before disabling writes.
|
|
|
|
```bash
|
|
docker compose --env-file .env.production -f docker-compose.prod.yml exec postgres psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "select key, jsonb_array_length(value) as appdata_rows from app_data where key in ('products-overview','requirements','version-plans','dev-tasks','test-cases','bugs','members','task-categories','task-worklogs','overtime') order by key;"
|
|
docker compose --env-file .env.production -f docker-compose.prod.yml exec postgres psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "select 'requirements' as table_name, count(*) from requirements union all select 'version_plans', count(*) from version_plans union all select 'dev_tasks', count(*) from dev_tasks union all select 'test_cases', count(*) from test_cases union all select 'bugs', count(*) from bugs;"
|
|
```
|
|
|
|
For partitioned entities, also check missing partition keys.
|
|
|
|
```bash
|
|
docker compose --env-file .env.production -f docker-compose.prod.yml exec postgres psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "select 'requirements_missing_product' as check_name, count(*) from requirements where product_id is null union all select 'dev_tasks_missing_version', count(*) from dev_tasks where version_id is null union all select 'test_cases_missing_version', count(*) from test_cases where version_id is null union all select 'bugs_missing_version', count(*) from bugs where version_id is null;"
|
|
```
|
|
|
|
## Disable AppData Writes
|
|
|
|
1. Merge the domain-specific frontend store change that stops calling `saveServerData` for the retired key.
|
|
2. Keep AppData read fallback for one release while relation reads are verified.
|
|
3. Deploy and run smoke tests.
|
|
|
|
```bash
|
|
pnpm deploy:smoke -- --base-url http://localhost --expected-version "$APP_VERSION"
|
|
```
|
|
|
|
## Remove Fallback
|
|
|
|
Remove AppData read fallback only after one successful release where:
|
|
|
|
- Domain writes went through relation APIs.
|
|
- AppData row counts did not grow for the retired key.
|
|
- V2.2 read paths and page workflows returned expected data.
|
|
- No `AppData relation sync failed` logs appeared during the observation window.
|
|
|
|
## Archive
|
|
|
|
Export retired keys before any later table cleanup.
|
|
|
|
```bash
|
|
docker compose --env-file .env.production -f docker-compose.prod.yml exec postgres psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "copy (select key, value, updated_at from app_data where key in ('dev-tasks','test-cases','bugs')) to stdout with csv header" > backups/postgres/appdata-retired-executions-20260708.csv
|
|
```
|
|
|
|
## Rollback
|
|
|
|
- If relation writes fail but AppData still has fresh data, roll back to the previous app image that still writes AppData.
|
|
- If AppData writes were already disabled and relation writes are bad, restore PostgreSQL from the backup made at the start of this runbook.
|
|
- If only read fallback removal caused the issue, roll back app images first and leave the database unchanged.
|
|
|
|
## Data Risks
|
|
|
|
- Removing fallback too early can hide valid historical JSON rows that were never mapped into relation tables.
|
|
- Re-enabling old AppData writes after relation writes have accepted new edits can overwrite newer relation state through compatibility sync.
|
|
- AppData exports can contain business-sensitive text; store backup CSV files in the same restricted location as database dumps.
|
|
|