- 根因: CreditReservation.task 是 OneToOneField(CASCADE), AITask.project 也是 CASCADE
—— 删项目→级联删任务→ACTIVE 预留行被吞, 账户冻结份额永不归还(实测 4 账户漂移共 ¥42,
且随删项目持续增长)
- 修法: billing/signals.py 挂 AITask pre_delete, 删除前先 release_credit 释放(级联同样
触发, release 自带行锁+幂等); apps.py ready() 接线
- 回归测试 x3: 直删任务/删项目级联/已扣费不重复释放
- qa/repair_reserved_drift.py: 存量漂移回填脚本(dry-run 默认, --apply 落 RELEASE 流水),
已对线上 4 账户执行并复验清零
- qa/function-audit/output: 本轮 18 页模拟点击审计报告(0 真死按钮 0 JS 报错)
验证: 后端测试 213/213 通过, django check 无警告
补齐 aab4d7e: 该提交带走了 signals.py 之外的测试轮改动, 信号挂载点与回归测试在本提交收口
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
AirShelf Backend
All backend code lives under AirShelf/core/backend by project decision.
Local bootstrap
cd /Users/maidong/Desktop/zyc/qiyuan_gitea/AirShelf/core/backend
python3.12 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
python manage.py migrate
python manage.py runserver 0.0.0.0:8000
Start workers in separate terminals:
cd /Users/maidong/Desktop/zyc/qiyuan_gitea/AirShelf/core/backend
source .venv/bin/activate
celery -A airshelf worker -l info -P threads -c 4 # 线程池 4 并发(出图/视频可并行;勿用 -P solo 串行)
ffmpeg must be available on PATH for Stage5 export jobs.
Runtime layout
- Django project:
airshelf - Domain apps:
apps/* - Settings module:
airshelf.settings.development - Celery app:
airshelf.celery
Secrets must be supplied by environment variables or .env; never commit values from account.md.
Useful commands
python manage.py check
python manage.py makemigrations --check --dry-run
python manage.py migrate
python manage.py bootstrap_volcano_models
python manage.py test apps.accounts apps.projects apps.billing