Agent Skillsrommapp/romm › backend-development

backend-development

GitHub

指导 RomM Python 后端开发,涵盖 FastAPI 端点、SQLAlchemy ORM、业务逻辑、认证授权、后台任务及数据库迁移。适用于后端功能实现与架构遵循。

.claude/skills/backend-development/SKILL.md rommapp/romm

Trigger Scenarios

添加或修改 API 端点 编写或调整 SQLAlchemy ORM 模型 执行数据库迁移 (Alembic) 实现后台任务 (RQ/Redis) 处理认证与权限逻辑

Install

npx skills add rommapp/romm --skill backend-development -g -y
More Options

Non-standard path

npx skills add https://github.com/rommapp/romm/tree/master/.claude/skills/backend-development -g -y

Use without installing

npx skills use rommapp/romm@backend-development

指定 Agent (Claude Code)

npx skills add rommapp/romm --skill backend-development -a claude-code -g -y

安装 repo 全部 skill

npx skills add rommapp/romm --all -g -y

预览 repo 内 skill

npx skills add rommapp/romm --list

SKILL.md

Frontmatter
{
    "name": "backend-development",
    "description": "Working on the RomM Python backend (backend\/) — a FastAPI app with SQLAlchemy 2.0, Alembic, RQ\/Redis, and Socket.IO. Use when adding or changing API endpoints, handlers, ORM models, response schemas, metadata-provider adapters, background tasks, database migrations, or backend tests. Covers the layered architecture, conventions, auth\/scopes, the OpenAPI→frontend type pipeline, and the uv\/pytest\/alembic\/trunk workflow. Trigger on any work under backend\/."
}

RomM Backend — FastAPI / SQLAlchemy

Python 3.13+, FastAPI, SQLAlchemy 2.0 (MariaDB default; MySQL/PostgreSQL supported), Alembic, Redis + RQ for jobs/cache/sessions, Socket.IO for real-time. Managed with uv.

Full reference: docs/BACKEND_ARCHITECTURE.md (directory map, ER diagram, every endpoint, auth flows). Read it before non-trivial changes.


Layered architecture — where code goes

endpoints/        FastAPI routers: request validation, response schemas, @protected_route scopes
endpoints/responses/  Pydantic response schemas (these shape the OpenAPI → frontend types)
endpoints/sockets/    Socket.IO event handlers
handler/          Business logic, decoupled from HTTP
  ├ auth/         HybridAuthBackend (session/basic/bearer/OIDC/client-token), scopes, CSRF/session middleware
  ├ database/     Per-entity CRUD handlers (db_rom_handler, db_user_handler, …), engine/session factory
  ├ metadata/     One handler per provider; normalizes + ranks by priority
  └ filesystem/   ROM/asset/firmware file I/O, hashing, archive extraction
adapters/services/  Typed external API clients (igdb.py + igdb_types.py, screenscraper.py, …)
models/           SQLAlchemy ORM models (BaseModel adds created_at/updated_at)
tasks/            RQ jobs — scheduled/ (cron) and manual/ (on-demand); base classes in tasks.py
config/           Env-var loading (__init__.py) + YAML config manager (singleton)
decorators/       @begin_session (DB session), @protected_route (auth + scopes)
exceptions/       Custom exception hierarchy
utils/ logger/    Shared helpers, structured logging
alembic/          Migrations (env.py + versions/)

Endpoint → handler → (database | metadata | filesystem) → models/adapters. Endpoints stay thin: validate, enforce scopes, call handlers, serialize via a response schema. Don't put business logic or raw queries in endpoints.

Conventions

  • Naming: Classes PascalCase; functions/vars snake_case; constants UPPER_SNAKE_CASE; private _prefixed.
  • DB sessions: decorate handler methods with @begin_session; it injects and manages the SQLAlchemy session/transaction. Don't open sessions ad hoc.
  • Async: I/O-bound endpoints and tasks use async/await. Per-request httpx/aiohttp clients come from context vars (utils/context.py), not new clients per call.
  • Imports: stdlib → third-party → local; explicit (no wildcards); TYPE_CHECKING blocks to break circular imports.
  • Errors: raise the custom exceptions in exceptions/ (e.g. RomNotFoundInDatabaseException), not bare HTTPException, where a typed one exists.
  • Validation/SSRF: sanitize filenames/paths before filesystem use (utils/); paths are rooted at LIBRARY_BASE_PATH/RESOURCES_BASE_PATH/ASSETS_BASE_PATH from config.

Auth & scopes

  • Roles: VIEWER (read), EDITOR (+write roms/platforms/assets), ADMIN (+users/tasks/logs). Defined on models/user.py; scope tiers in handler/auth/constants.py.
  • Granular scopes: me.read/write, roms.read/write, platforms.*, assets.*, devices.*, firmware.*, collections.*, users.*, tasks.run, logs.read.
  • Protect routes with @protected_route(router.<method>, "<path>", [Scope.X]). The frontend mirrors these scopes — keep them aligned.

Adding things

  • Endpoint: add the route in the right endpoints/* router, a response schema in endpoints/responses/, enforce scopes, delegate to a handler. If the response shape changes, the frontend must regenerate types (below).
  • Model / schema change: edit models/, then create a migration (below). Update the matching response schema so OpenAPI stays accurate.
  • Metadata provider: add a typed client in adapters/services/<name>.py (+ <name>_types.py) and a handler/metadata/<name>_handler.py that normalizes into the common shape and slots into the priority order.
  • Background job: subclass Task/PeriodicTask in tasks/scheduled/ or tasks/manual/; register scheduled jobs in startup.py.

Database migrations (Alembic)

Migrations must work on MariaDB, MySQL, and PostgreSQL (CI runs alembic upgrade head on Postgres and MariaDB — .github/workflows/migrations.yml). Use batch mode / DB-specific SQL where needed; mirror existing migrations in alembic/versions/.

cd backend
uv run alembic revision --autogenerate -m "short description"   # generate, then HAND-REVIEW the file
uv run alembic upgrade head                                     # apply
uv run alembic downgrade -1                                     # verify the downgrade works

Always review autogenerated migrations — they miss server-default/enum/index nuances and cross-dialect differences. The virtual_collections DB view is excluded from migrations.

Migration hygiene (recurring review fixes)

  • Numbering collides on rebase. Two open branches both pick the next number. When you rebase onto master and find your 0102_* already taken, rename the file, update revision, and re-chain down_revision onto the migration that actually precedes it now. Then run alembic upgrade head on a fresh DB to confirm the chain is linear.
  • Use the builtin idempotency flags, not manual introspection. op.create_table(..., if_not_exists=True) and create_index(..., if_not_exists=True) over inspect(conn).get_table_names() guards wrapping the whole block. Reserve inspect() for what the flags can't express.
  • Edit an unreleased migration in place. If the migration hasn't shipped in a tag yet, change it rather than stacking a fixup migration on top. Only released migrations are immutable.
  • Don't ship a data backfill you can avoid. A rewrite-every-row migration to normalize values the parser now handles is a maintenance liability. Prefer fixing the parser and letting the next scan converge, unless stale rows are actually user-visible and unrecoverable.
  • Prefer a generated column plus an index over a join when a field exists only to sort or filter (see generated_first_release_date), and say so in the model's __table_args__ rather than in prose.

OpenAPI → frontend types

FastAPI serves the schema at GET /openapi.json. The frontend regenerates its TypeScript types from it:

# backend running on :3000, then in frontend/
npm run generate     # writes src/__generated__/ via openapi-typescript-codegen

Any change to a response schema or route signature should be followed by npm run generate + a frontend typecheck.

Run, test, lint

cd backend
uv run python3 main.py            # run (migrations auto-apply on startup)
uv run pytest [path/file]         # tests (subset by path); uv run pytest -vv for all
  • Tests: pytest + pytest-asyncio, isolated per pytest-xdist worker (per-worker DBs); fakeredis; pytest-recording VCR cassettes mock external APIs; Hypothesis for property tests. Mirror the backend/<area>/ layout under backend/tests/. First-time test DB setup: docker exec -i romm-db-dev mariadb -uroot -p<pw> < backend/romm_test/setup.sql.
  • Lint / format / type-check run through Trunk (ruff, black, isort, mypy, bandit): trunk fmt && trunk check. CI enforces Trunk on every PR. Never bypass with --no-verify.
  • New/changed logic needs a test; new endpoints need endpoint tests.

Version History

  • 5b82462 Current 2026-08-29 04:26

    新增 review-polish skill 以规范 PR 中的注释和文档修剪;将 alembic 编号冲突等特定模式归入此 skill。

  • 42e8043 2026-08-20 16:50

Same Skill Collection

.claude/skills/frontend-i18n/SKILL.md
.claude/skills/frontend-v2-components/SKILL.md
.claude/skills/frontend-v2-input/SKILL.md
.claude/skills/frontend-v2-patterns/SKILL.md
.claude/skills/frontend-v2-theming/SKILL.md
.claude/skills/pre-pr-verification/SKILL.md
.claude/skills/security-audit/SKILL.md
.claude/skills/review-polish/SKILL.md

Metadata

Files
0
Version
5b82462
Hash
e747c102
Indexed
2026-08-20 16:50

Accueil - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-31 23:42
浙ICP备14020137号-1 $Carte des visiteurs$