chore: agentic upgrade
This commit is contained in:
@@ -0,0 +1,45 @@
|
|||||||
|
---
|
||||||
|
name: infra-best-practices
|
||||||
|
description: Use when changing, reviewing, or debugging CI, deployment, environment configuration, secrets, observability, generated artifacts, or infrastructure workflows in ui_harness_manager.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Infra Best Practices
|
||||||
|
|
||||||
|
## Project Guidance
|
||||||
|
|
||||||
|
Treat infrastructure as a small, explicit support layer for the Bun, React, Elysia, and Tauri surfaces. Prefer boring, reproducible workflows over clever automation.
|
||||||
|
|
||||||
|
Configuration that varies by deploy belongs in environment variables. Use `API_HOST` and `API_PORT` as granular, orthogonal settings; do not hardcode deploy hosts, ports, credentials, or machine-local paths into source. The repo should remain safe to open-source without exposing secrets.
|
||||||
|
|
||||||
|
Use Bun as the package and CI runtime. Keep `bun.lock` committed, install with `bun ci` in CI, and avoid adding npm, Yarn, or pnpm lockfiles unless the repo intentionally changes package managers.
|
||||||
|
|
||||||
|
For CI, prove build health before adding release complexity: run `bun run check`, then `bun run build`; use `bun run tauri:build` when native packaging, Tauri config, permissions, Rust commands, or desktop release behavior changes. Install/cache Tauri system and Rust prerequisites on each platform runner before expecting native packaging to work.
|
||||||
|
|
||||||
|
Packaged desktop builds do not automatically include the local Elysia dev server. Before release work, decide whether backend behavior moves into Rust commands, a Tauri sidecar, or an external service, then verify the packaged app can reach it.
|
||||||
|
|
||||||
|
Use IaC or checked-in config for new infrastructure changes when possible. Keep manual console steps as temporary exceptions and document the owner, reason, and rollback path.
|
||||||
|
|
||||||
|
Keep logs and observability useful but proportional. Capture startup config shape, API bind failures, build/package failures, and deployment errors without logging secrets or flooding small-app workflows with heavyweight telemetry.
|
||||||
|
|
||||||
|
## Quick Reference
|
||||||
|
|
||||||
|
| Area | Default |
|
||||||
|
| --- | --- |
|
||||||
|
| Deploy config | Env vars, especially `API_HOST` and `API_PORT` |
|
||||||
|
| Secrets | Secret manager or CI secrets, never source files |
|
||||||
|
| CI install | `bun ci` with committed `bun.lock` |
|
||||||
|
| First CI checks | `bun run check`, then `bun run build` |
|
||||||
|
| Desktop release check | Install Tauri prerequisites, then `bun run tauri:build` |
|
||||||
|
| Generated dirs | Do not treat `dist`, `node_modules`, `src-tauri/gen`, or `src-tauri/target` as source |
|
||||||
|
| Infra changes | Prefer IaC or reviewed config over undocumented manual changes |
|
||||||
|
|
||||||
|
## Common Mistakes
|
||||||
|
|
||||||
|
- Using `bun install` in reproducible CI instead of `bun ci`.
|
||||||
|
- Adding deploy-specific constants when `API_HOST` or `API_PORT` should be env-driven.
|
||||||
|
- Committing credentials, tokens, private URLs, or local absolute paths.
|
||||||
|
- Editing or reviewing generated output in `dist`, `node_modules`, `src-tauri/gen`, or `src-tauri/target` as if it were source.
|
||||||
|
- Shipping a packaged desktop build that still assumes the local Bun/Elysia dev server is running.
|
||||||
|
- Building release pipelines before CI reliably checks and builds the app.
|
||||||
|
- Adding observability that hides the important failure path behind noisy dashboards.
|
||||||
|
- Making manual infra changes without a rollback note or future IaC/config follow-up.
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
---
|
||||||
|
name: python-practices
|
||||||
|
description: Use when writing, reviewing, refactoring, or debugging Python code in this repository, including style, typing, error handling, async work, tests, packaging, security, and verification.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Python Practices
|
||||||
|
|
||||||
|
## Core Rule
|
||||||
|
|
||||||
|
Write Python that is boring to maintain: explicit, typed, small, tested, and easy
|
||||||
|
to inspect in production. Prefer this repository's existing conventions over
|
||||||
|
generic advice. When a library, framework, SDK, CLI, or cloud-service detail
|
||||||
|
matters, fetch current docs with Context7; use Tavily for broader ecosystem
|
||||||
|
practice research.
|
||||||
|
|
||||||
|
## Source Priority
|
||||||
|
|
||||||
|
1. Project files: `AGENTS.md`, `pyproject.toml`, existing `cpv3/` code, tests.
|
||||||
|
2. Current official docs and PEPs.
|
||||||
|
3. High-quality community research for trade-offs, checked against project needs.
|
||||||
|
4. Memory or intuition, only after the above.
|
||||||
|
|
||||||
|
## Readability
|
||||||
|
|
||||||
|
- Keep functions small enough to read in one pass. Extract helpers when branching,
|
||||||
|
parsing, or side effects start competing for attention.
|
||||||
|
- Use intention-revealing names: `snake_case` for functions and variables,
|
||||||
|
`CapWords` for classes, `UPPER_SNAKE_CASE` for constants.
|
||||||
|
- Prefer direct control flow, early returns, and clear condition names over nested
|
||||||
|
cleverness.
|
||||||
|
- Avoid ad hoc string parsing when Python, Pydantic, SQLAlchemy, JSON, pathlib,
|
||||||
|
or another structured API can express the operation.
|
||||||
|
- Comments should explain non-obvious reasons, not repeat the code.
|
||||||
|
|
||||||
|
## Types And Data
|
||||||
|
|
||||||
|
- Annotate public functions, service/repository boundaries, async helpers, and
|
||||||
|
values that cross module boundaries.
|
||||||
|
- Prefer precise built-in generics such as `list[str]`, `dict[str, Any]`, and
|
||||||
|
`tuple[int, int]`; avoid bare `dict`, `list`, or `Any` unless the shape is
|
||||||
|
genuinely unknown.
|
||||||
|
- Use Pydantic schemas for API and validation boundaries. Use dataclasses or small
|
||||||
|
typed objects for internal value bundles when Pydantic validation is not needed.
|
||||||
|
- Do not mutate default containers. Use `None` plus initialization or a factory.
|
||||||
|
- Convert external data at the boundary, then keep internal code working with typed
|
||||||
|
values instead of raw payload dictionaries.
|
||||||
|
|
||||||
|
## Errors And Logging
|
||||||
|
|
||||||
|
- Catch specific exceptions. Avoid bare `except`, silent fallbacks, and swallowing
|
||||||
|
errors without observability.
|
||||||
|
- Preserve context with exception chaining: `raise DomainError(...) from exc`.
|
||||||
|
- Define reusable user-facing or domain error strings as `ERROR_...` constants.
|
||||||
|
- Use `logging.getLogger(__name__)` for diagnostics. Do not use `print` in
|
||||||
|
application code.
|
||||||
|
- Error messages should help the next maintainer find the failing input, dependency,
|
||||||
|
or state without leaking secrets.
|
||||||
|
|
||||||
|
## Async And Resources
|
||||||
|
|
||||||
|
- Do not block the event loop. Use async APIs, subprocess APIs, or
|
||||||
|
`anyio.to_thread.run_sync` for sync I/O and CPU-bound library calls.
|
||||||
|
- Use context managers for files, sessions, locks, temporary resources, and network
|
||||||
|
clients. Cleanup must be visible in normal and exceptional paths.
|
||||||
|
- Add timeouts around network, subprocess, and external-service operations when the
|
||||||
|
called API supports them.
|
||||||
|
- Do not share mutable state across concurrent tasks unless access is synchronized.
|
||||||
|
- For this backend, do not share one SQLAlchemy `AsyncSession` across concurrent
|
||||||
|
tasks; use a session per task/request.
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
- Test behavior, not implementation details. Name tests after the observable rule.
|
||||||
|
- Prefer deterministic fixtures, explicit inputs, and parametrized edge cases.
|
||||||
|
- Cover failure paths for parsing, permissions, missing data, external services,
|
||||||
|
and persistence boundaries.
|
||||||
|
- Use unit tests for pure helpers and service/repository rules. Use integration tests
|
||||||
|
for endpoint contracts and dependency overrides.
|
||||||
|
- For bug fixes, write or update the failing test first when practical, then make
|
||||||
|
the smallest code change that proves the fix.
|
||||||
|
|
||||||
|
## Security And Configuration
|
||||||
|
|
||||||
|
- Keep secrets in environment-backed settings, never source files, tests, fixtures,
|
||||||
|
generated docs, or logs.
|
||||||
|
- Validate paths, object keys, URLs, filenames, and user-controlled identifiers at
|
||||||
|
the boundary.
|
||||||
|
- Prefer allowlists for modes, providers, file types, and status transitions.
|
||||||
|
- Treat serialization as a boundary: expose only fields that should leave the module
|
||||||
|
or API.
|
||||||
|
|
||||||
|
## Project Tooling
|
||||||
|
|
||||||
|
Use the repository's Python 3.11+ and `uv` workflow. Keep Ruff formatting with the
|
||||||
|
configured 100-character line length.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv run ruff format cpv3 tests
|
||||||
|
uv run ruff check cpv3 tests
|
||||||
|
uv run pytest
|
||||||
|
```
|
||||||
|
|
||||||
|
Run narrower checks while iterating, then broaden when the change touches shared
|
||||||
|
behavior. If verification cannot run, record the exact blocker.
|
||||||
|
|
||||||
|
## Project Overlay
|
||||||
|
|
||||||
|
- FastAPI HTTP concerns belong in `router.py`.
|
||||||
|
- Pydantic DTOs belong in `schemas.py` and usually inherit
|
||||||
|
`cpv3.common.schemas.Schema`.
|
||||||
|
- Business orchestration belongs in `service.py`.
|
||||||
|
- SQLAlchemy statements belong in `repository.py`.
|
||||||
|
- Database shape changes need Alembic migrations and tests.
|
||||||
|
- Do not rely on `.claude/` directory contents.
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
interface:
|
||||||
|
display_name: "Python Practices"
|
||||||
|
short_description: "Python quality practices for this repo"
|
||||||
|
default_prompt: "Use $python-practices to guide Python changes in this repository."
|
||||||
|
dependencies:
|
||||||
|
tools:
|
||||||
|
- type: "mcp"
|
||||||
|
value: "context7"
|
||||||
|
description: "Fetch current documentation for library, framework, SDK, API, CLI, and cloud-service details."
|
||||||
|
transport: "streamable_http"
|
||||||
|
url: "https://mcp.context7.com/mcp"
|
||||||
|
- type: "mcp"
|
||||||
|
value: "tavily_search"
|
||||||
|
description: "Search the web for current Python ecosystem practices and trade-offs."
|
||||||
|
transport: "streamable_http"
|
||||||
|
url: "https://mcp.tavily.com/mcp/"
|
||||||
|
policy:
|
||||||
|
allow_implicit_invocation: true
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
name: rest-api-best-practices
|
||||||
|
description: Use when designing, reviewing, or changing REST HTTP API routes, request and response shapes, status codes, idempotency, versioning, CORS, or Elysia handlers in this project.
|
||||||
|
---
|
||||||
|
|
||||||
|
# REST API Best Practices
|
||||||
|
|
||||||
|
## Project Guidance
|
||||||
|
|
||||||
|
Treat HTTP semantics as part of the contract. Resource URLs should name things, while methods describe intentions. Keep the local Elysia API predictable for both the renderer and future Tauri callers.
|
||||||
|
|
||||||
|
Current routes include `/health`, `/api/status`, and `/api/echo`; preserve simple health/status behavior and use `/api/*` for application API surface unless the surrounding code establishes otherwise. Use JSON bodies and Elysia validation schemas at route boundaries. Return a consistent error envelope for validation and domain errors.
|
||||||
|
|
||||||
|
Prefer least-open CORS. `origin: true` is acceptable only for local development or clearly trusted callers. For production-facing API behavior, restrict origins to the renderer/Tauri app needs.
|
||||||
|
|
||||||
|
Version only when the public contract breaks. Do not add `/v2` for additive fields, new endpoints, or internal refactors.
|
||||||
|
|
||||||
|
## Quick Reference
|
||||||
|
|
||||||
|
- `GET`: transfer the current representation. It is safe and should not mutate server state.
|
||||||
|
- `POST`: process the enclosed representation. Use for creation under a collection or workflows where the server chooses the result URI. On successful creation, return `201 Created` and `Location` when a stable resource URL exists.
|
||||||
|
- `PUT`: create or replace the target resource state at the request URI. Use when the client knows the target URI and repeated requests should have the same effect.
|
||||||
|
- `PATCH`: partial update only when the patch format and merge semantics are explicit.
|
||||||
|
- `DELETE`: remove the URI association. Repeated deletes should be safe to retry by outcome.
|
||||||
|
- `200 OK`: successful response with a body.
|
||||||
|
- `201 Created`: new resource created; include `Location` when applicable.
|
||||||
|
- `202 Accepted`: work accepted but not finished.
|
||||||
|
- `204 No Content`: success with no response body.
|
||||||
|
- `400 Bad Request`: malformed syntax, invalid JSON, framing, or request structure.
|
||||||
|
- `422 Unprocessable Content`: well-formed input that fails schema or semantic validation, when this project chooses to expose that distinction.
|
||||||
|
- `401`: authentication required. `403`: authenticated caller lacks permission. `404`: resource not found.
|
||||||
|
- `409`: request conflicts with current state.
|
||||||
|
- `500`: unexpected server fault; do not expose internals.
|
||||||
|
|
||||||
|
Use idempotency keys for duplicate-prone `POST` workflows such as purchases, imports, job creation, or retry-heavy Tauri/native operations.
|
||||||
|
|
||||||
|
## Common Mistakes
|
||||||
|
|
||||||
|
- Using verbs in paths like `/api/createUser` instead of resource paths like `/api/users`.
|
||||||
|
- Mutating data in `GET` handlers.
|
||||||
|
- Returning `200` for every outcome and hiding failures in JSON fields.
|
||||||
|
- Creating resources with `POST` but omitting `201` and `Location` when the new URL is known.
|
||||||
|
- Treating `POST` and `PUT` as interchangeable.
|
||||||
|
- Returning different error shapes from validation, auth, and domain logic.
|
||||||
|
- Adding API versions before there is a breaking contract change.
|
||||||
|
- Leaving permissive CORS in code intended for non-local use.
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
---
|
|
||||||
name: codex
|
|
||||||
description: "Use the `codex exec` CLI to consult an OpenAI-powered codebase oracle. Trigger this skill whenever Claude Code would benefit from a second opinion on the current codebase — architecture questions, debugging strategies, implementation alternatives, understanding unfamiliar code patterns, or when the user explicitly asks to 'ask codex', 'check with codex', 'consult codex', or 'codex exec'. Also trigger when Claude is uncertain about a complex codebase decision, needs to understand legacy code, or wants to validate an approach before executing. The codex command scans the current codebase and sends context + the question to an OpenAI model, returning an independent analysis."
|
|
||||||
---
|
|
||||||
|
|
||||||
# Codex — Codebase Oracle via OpenAI
|
|
||||||
|
|
||||||
`codex` is a CLI tool that scans the current project and answers questions about it using an OpenAI model. Claude Code can shell out to it for a second perspective.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```bash
|
|
||||||
codex exec "<your question here>"
|
|
||||||
```
|
|
||||||
|
|
||||||
The command automatically:
|
|
||||||
1. Scans the current working directory for codebase context
|
|
||||||
2. Sends the question + context to an OpenAI model
|
|
||||||
3. Returns the answer to stdout
|
|
||||||
|
|
||||||
## When to use codex
|
|
||||||
|
|
||||||
- **Architecture decisions** — "What pattern is this codebase using for state management?"
|
|
||||||
- **Debugging help** — "Why might the auth middleware be failing silently?"
|
|
||||||
- **Code understanding** — "Explain the data flow in the payments module"
|
|
||||||
- **Implementation review** — "What's the best way to add caching to this service?"
|
|
||||||
- **Second opinion** — When you want to validate your approach before making changes
|
|
||||||
- **Legacy code** — When encountering unfamiliar patterns or undocumented code
|
|
||||||
- **User asks directly** — Any time the user says "ask codex" or "check with codex"
|
|
||||||
|
|
||||||
## How to call it
|
|
||||||
|
|
||||||
Run it as a bash command. The question should be specific and self-contained — codex already has codebase context, so focus the question on what you need to know.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Ask about architecture
|
|
||||||
codex exec "What design patterns are used in the src/services directory?"
|
|
||||||
|
|
||||||
# Ask for debugging help
|
|
||||||
codex exec "The /api/users endpoint returns 500 when called with a missing email field. What could cause this based on the route handler and validation logic?"
|
|
||||||
|
|
||||||
# Ask for implementation guidance
|
|
||||||
codex exec "What's the best way to add rate limiting to the existing Express middleware chain?"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Reading the response
|
|
||||||
|
|
||||||
The answer comes back as plain text on stdout. Read it, weigh it against your own analysis, and use the best parts. Codex is a consultant, not an authority — if its suggestion conflicts with what you know about the codebase, trust your direct analysis of the code.
|
|
||||||
|
|
||||||
## Tips for good questions
|
|
||||||
|
|
||||||
- Be specific: "Why does UserService.create() call normalize() twice?" beats "What's wrong with user creation?"
|
|
||||||
- Include symptoms when debugging: mention error messages, failing tests, unexpected behavior
|
|
||||||
- Scope it: ask about a specific module or file path rather than the entire codebase at once
|
|
||||||
- One question at a time: don't bundle multiple unrelated questions into a single exec call
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
- The `codex` CLI must be installed and on PATH
|
|
||||||
- An OpenAI API key must be configured (codex handles this internally)
|
|
||||||
- Run from within a project directory so codex can scan the codebase
|
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#:schema https://developers.openai.com/codex/config-schema.json
|
||||||
|
|
||||||
|
project_doc_max_bytes = 65536
|
||||||
|
|
||||||
|
[features]
|
||||||
|
hooks = true
|
||||||
|
|
||||||
|
[agents]
|
||||||
|
max_threads = 6
|
||||||
|
max_depth = 1
|
||||||
|
|
||||||
|
[mcp_servers.tavily_search]
|
||||||
|
url = "https://mcp.tavily.com/mcp/?tavilyApiKey=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"
|
||||||
|
enabled = true
|
||||||
|
http_headers = { Authorization = "Bearer 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" }
|
||||||
|
|
||||||
|
[mcp_servers.tavily_search.tools.tavily_extract]
|
||||||
|
approval_mode = "approve"
|
||||||
|
|
||||||
|
[mcp_servers.tavily_search.tools.tavily_search]
|
||||||
|
approval_mode = "approve"
|
||||||
|
|
||||||
|
[mcp_servers.context7]
|
||||||
|
url = "https://mcp.context7.com/mcp"
|
||||||
|
enabled = true
|
||||||
|
|
||||||
|
[mcp_servers.context7.http_headers]
|
||||||
|
CONTEXT7_API_KEY = "ctx7sk-57f06da8-ba55-44d4-9b71-ce8e1640b0e2"
|
||||||
@@ -17,3 +17,5 @@ dist/
|
|||||||
# OS / editor
|
# OS / editor
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,59 @@
|
|||||||
# AGENTS.md — Coffee Project Backend
|
# Repository Guidelines
|
||||||
|
|
||||||
Primary workflow guidance lives in `../AGENTS.md`.
|
## Project Structure & Module Organization
|
||||||
|
|
||||||
Use `./CLAUDE.md` as the service-specific source of truth for:
|
This FastAPI backend lives in `cpv3/`. The app entry point is `cpv3/main.py`;
|
||||||
|
versioned routes are collected in `cpv3/api/v1/router.py`. Feature code lives in
|
||||||
|
`cpv3/modules/<feature>/` and should stay flat: `models.py`, `schemas.py`,
|
||||||
|
`repository.py`, `service.py`, and `router.py`. Shared infrastructure is in
|
||||||
|
`cpv3/infrastructure/`, database setup in `cpv3/db/`, migrations in `alembic/`,
|
||||||
|
docs in `docs/`, and tests in `tests/unit/` and `tests/integration/`.
|
||||||
|
|
||||||
- backend commands
|
## Build, Test, and Development Commands
|
||||||
- module architecture
|
|
||||||
- backend patterns and gotchas
|
|
||||||
|
|
||||||
OpenCode/Codex notes:
|
- `uv sync` installs locked dependencies.
|
||||||
|
- `uv run uvicorn cpv3.main:app --reload` runs the API on `localhost:8000`.
|
||||||
|
- `docker compose -f docker-compose.local.yml up --build` starts Postgres, Redis,
|
||||||
|
MinIO, the API, and the Dramatiq worker.
|
||||||
|
- `uv run dramatiq cpv3.modules.tasks.service` starts the worker without Docker.
|
||||||
|
- `uv run alembic upgrade head` applies database migrations.
|
||||||
|
- `uv run alembic revision --autogenerate -m "add table"` creates a migration.
|
||||||
|
|
||||||
- Keep `../AGENTS.md` as the workflow and delegation source of truth.
|
## Coding Style & Naming Conventions
|
||||||
- Treat `CLAUDE.md` as architecture, commands, and conventions only.
|
|
||||||
- Do not rely on `.claude/` directory contents.
|
Use Python 3.11+ with absolute imports such as
|
||||||
|
`from cpv3.modules.media.schemas import MediaRead`. Keep Ruff formatting with a
|
||||||
|
100-character line length: `uv run ruff format cpv3 tests` and
|
||||||
|
`uv run ruff check cpv3 tests`. Put HTTP concerns in `router.py`, DTOs in
|
||||||
|
`schemas.py`, business orchestration in `service.py`, and SQLAlchemy queries in
|
||||||
|
`repository.py`. Pydantic schemas should inherit from `cpv3.common.schemas.Schema`.
|
||||||
|
Define reusable error strings as module-level `ERROR_...` constants.
|
||||||
|
|
||||||
|
## Testing Guidelines
|
||||||
|
|
||||||
|
Pytest is configured in `pyproject.toml` with `pytest-asyncio` auto mode. Name test
|
||||||
|
files `test_*.py`, classes `Test*`, and functions `test_*`. Run all tests with
|
||||||
|
`uv run pytest`; run a slice with `uv run pytest tests/unit/test_task_service.py`.
|
||||||
|
Prefer unit tests for service/repository logic and integration tests for endpoint
|
||||||
|
contracts. Shared async clients, users, storage mocks, and SQLite fixtures live in
|
||||||
|
`tests/conftest.py`.
|
||||||
|
|
||||||
|
## Commit & Pull Request Guidelines
|
||||||
|
|
||||||
|
Recent history uses short imperative subjects, often with Conventional Commit
|
||||||
|
prefixes: `fix: add cors endpoints`, `feat: add swagger auth`, `chore: add pipeline`.
|
||||||
|
Keep commits focused and mention migrations or config changes in the body. Pull
|
||||||
|
requests should include a summary, linked issue or task, test results, and notes for
|
||||||
|
API, migration, Docker, or environment-variable changes.
|
||||||
|
|
||||||
|
## Security & Configuration Tips
|
||||||
|
|
||||||
|
Runtime settings come from `.env` through `cpv3/infrastructure/settings.py`. Do not
|
||||||
|
commit real secrets, service keys, or certificates. Local defaults expose Postgres on
|
||||||
|
`5332`, Redis on `6379`, MinIO on `9000/9001`, and the API on `8000`.
|
||||||
|
|
||||||
|
## Agent-Specific Instructions
|
||||||
|
|
||||||
|
Use Context7 for current library, SDK, CLI, framework, or cloud-service documentation.
|
||||||
|
Treat committed project files as source of truth when available, and do not rely on
|
||||||
|
`.claude/` directory contents.
|
||||||
|
|||||||
@@ -1,58 +0,0 @@
|
|||||||
# CLAUDE.md — Coffee Project Backend
|
|
||||||
|
|
||||||
See also the monorepo-level `../CLAUDE.md` for full architecture overview.
|
|
||||||
|
|
||||||
## Commands
|
|
||||||
|
|
||||||
```bash
|
|
||||||
uv sync # Install dependencies
|
|
||||||
uv run uvicorn cpv3.main:app --reload # Dev server (localhost:8000)
|
|
||||||
uv run pytest # Run all tests
|
|
||||||
uv run pytest tests/integration/<file>.py # Single test file
|
|
||||||
uv run alembic revision --autogenerate -m "msg" # Create migration
|
|
||||||
uv run alembic upgrade head # Apply migrations
|
|
||||||
uv run dramatiq cpv3.modules.tasks.service # Start background worker
|
|
||||||
uv run ruff check cpv3/ # Lint
|
|
||||||
uv run ruff format cpv3/ # Auto-format
|
|
||||||
docker-compose up # Full stack (DB, Redis, MinIO, API, Worker)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
Layered module pattern. Each module has exactly 5-6 files (`__init__.py`, `models.py`, `schemas.py`, `repository.py`, `service.py`, `router.py`). No subdirectories within modules. When in doubt, put logic in `service.py`.
|
|
||||||
|
|
||||||
```
|
|
||||||
cpv3/
|
|
||||||
├── main.py # FastAPI app, CORS, router registration
|
|
||||||
├── api/v1/router.py # Aggregates all module routers
|
|
||||||
├── common/schemas.py # Base Schema class (Pydantic, from_attributes=True)
|
|
||||||
├── db/ # Base, session, model imports
|
|
||||||
├── infrastructure/ # Auth, security, settings, storage
|
|
||||||
└── modules/ # Feature modules (users, projects, media, files, etc.)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Key Patterns
|
|
||||||
|
|
||||||
- **Database**: PostgreSQL 16, async SQLAlchemy (`AsyncSession`), all models inherit `Base` + `BaseModelMixin`.
|
|
||||||
- **Soft deletes**: `is_deleted` flag — repositories filter by default.
|
|
||||||
- **Auth**: JWT access + refresh tokens in HTTP-only cookies. Use `get_current_user` dependency.
|
|
||||||
- **Config**: `get_settings()` from `cpv3/infrastructure/settings.py` (cached with `@lru_cache`).
|
|
||||||
- **Background tasks**: Dramatiq with Redis broker. Actors live in `cpv3/modules/tasks/service.py`.
|
|
||||||
- **Package manager**: **uv** only — `uv sync`, `uv add <pkg>`, `uv run <cmd>`.
|
|
||||||
- **Linting**: Ruff (line length 100, config in `pyproject.toml`).
|
|
||||||
|
|
||||||
## Common Gotchas
|
|
||||||
|
|
||||||
- **Async sessions**: Never mix sync and async DB operations. Use `await` on all session calls.
|
|
||||||
- **Module structure**: Do not create extra files or subdirectories. Standard files only: `models.py`, `schemas.py`, `repository.py`, `service.py`, `router.py`.
|
|
||||||
- **Schemas**: Always inherit from `cpv3.common.schemas.Schema`, not raw Pydantic `BaseModel`.
|
|
||||||
- **Imports**: Use absolute paths (`from cpv3.modules.media.schemas import ...`), not relative.
|
|
||||||
- **Error messages**: Store as module-level constants with `ERROR_` prefix, not inline strings.
|
|
||||||
- **CPU-bound work**: Use `anyio.to_thread.run_sync()` to avoid blocking the event loop.
|
|
||||||
|
|
||||||
## Docker Services
|
|
||||||
|
|
||||||
```
|
|
||||||
postgres → localhost:5332 minio → localhost:9000 (console: 9001)
|
|
||||||
redis → localhost:6379 api → localhost:8000 (OpenAPI at /api/schema/)
|
|
||||||
```
|
|
||||||
@@ -1,393 +0,0 @@
|
|||||||
# CODEX Refactor Plan
|
|
||||||
|
|
||||||
## Chosen direction
|
|
||||||
|
|
||||||
This plan adopts **Option 1: in-place cleanup inside current boundaries**.
|
|
||||||
|
|
||||||
The goal is to make backend feature work safer and the code easier to read **without moving far from the current implementation**.
|
|
||||||
|
|
||||||
This means:
|
|
||||||
|
|
||||||
- keep the existing module structure (`models.py`, `schemas.py`, `repository.py`, `service.py`, `router.py`)
|
|
||||||
- keep public HTTP routes and response contracts stable
|
|
||||||
- avoid hidden abstractions, base classes, registries, or plugin-style indirection
|
|
||||||
- prefer explicit, local helpers over framework-like refactors
|
|
||||||
- optimize first for **developer readability and safer future changes**
|
|
||||||
|
|
||||||
## Why this option
|
|
||||||
|
|
||||||
The biggest current readability and change-risk hotspot is `cpv3/modules/tasks/service.py`.
|
|
||||||
|
|
||||||
Right now it mixes several responsibilities in one place:
|
|
||||||
|
|
||||||
- broker/bootstrap concerns
|
|
||||||
- Dramatiq actor definitions
|
|
||||||
- task submission flow
|
|
||||||
- job lifecycle side effects
|
|
||||||
- webhook application
|
|
||||||
- artifact persistence
|
|
||||||
- notification sending
|
|
||||||
- cancellation side effects
|
|
||||||
|
|
||||||
The highest concentration of risk is in:
|
|
||||||
|
|
||||||
- `cpv3/modules/tasks/service.py` — especially `TaskService` and `record_webhook_event()`
|
|
||||||
- `cpv3/modules/jobs/router.py` — cancellation path delegates into task orchestration
|
|
||||||
- `cpv3/modules/captions/service.py` — already contains both preset CRUD and Remotion client logic
|
|
||||||
|
|
||||||
A bigger ownership move would be possible later, but it is not the safest first step.
|
|
||||||
|
|
||||||
## Primary objectives
|
|
||||||
|
|
||||||
1. Make task/job orchestration easier to understand.
|
|
||||||
2. Reduce the blast radius of changes in `TaskService`.
|
|
||||||
3. Replace raw internal JSON/dict handling with typed, explicit internal contracts.
|
|
||||||
4. Keep behavior stable for current API consumers and existing module boundaries.
|
|
||||||
5. Improve confidence with focused unit and integration coverage before and during refactoring.
|
|
||||||
|
|
||||||
## Constraints
|
|
||||||
|
|
||||||
### Must keep
|
|
||||||
|
|
||||||
- Current backend module structure.
|
|
||||||
- Current route layout and public API behavior.
|
|
||||||
- Current job types and overall task flow.
|
|
||||||
- Current ownership model at module level.
|
|
||||||
- Explicit code over clever abstractions.
|
|
||||||
|
|
||||||
### Allowed
|
|
||||||
|
|
||||||
- Small internal contract cleanup.
|
|
||||||
- Small private helper extraction inside existing files.
|
|
||||||
- Better naming, smaller methods, and clearer sequencing.
|
|
||||||
- Add or expand tests.
|
|
||||||
|
|
||||||
### Not allowed in this phase
|
|
||||||
|
|
||||||
- New module subdirectories or extra architecture layers.
|
|
||||||
- Generic handler registries.
|
|
||||||
- Base service hierarchies.
|
|
||||||
- Large movement of lifecycle ownership from `tasks` into `jobs`.
|
|
||||||
- Pushing more orchestration into `captions`, `media`, or `transcription` before task contracts are cleaned up.
|
|
||||||
- Broad request/response or frontend-facing contract changes.
|
|
||||||
|
|
||||||
## Refactor scope
|
|
||||||
|
|
||||||
### In scope
|
|
||||||
|
|
||||||
- `cpv3/modules/tasks/service.py`
|
|
||||||
- `cpv3/modules/tasks/schemas.py`
|
|
||||||
- `cpv3/modules/tasks/router.py` where needed for clarity only
|
|
||||||
- `cpv3/modules/jobs/router.py` where needed for clearer delegation only
|
|
||||||
- tests around task submission, webhook handling, cancellation, and caption task behavior
|
|
||||||
|
|
||||||
### Nearby modules to touch carefully if needed
|
|
||||||
|
|
||||||
- `cpv3/modules/captions/service.py`
|
|
||||||
- `cpv3/modules/media/service.py`
|
|
||||||
- `cpv3/modules/transcription/repository.py`
|
|
||||||
- `cpv3/modules/jobs/service.py`
|
|
||||||
|
|
||||||
These are supporting touches only. The refactor should remain centered in `tasks`.
|
|
||||||
|
|
||||||
## Target end state
|
|
||||||
|
|
||||||
After this phase:
|
|
||||||
|
|
||||||
- `TaskService` still owns task orchestration,
|
|
||||||
- but each major step is explicit and small,
|
|
||||||
- stored job payloads are validated through typed internal schemas,
|
|
||||||
- webhook application is broken into readable stages,
|
|
||||||
- repeated submission logic is reduced through simple private helpers,
|
|
||||||
- actor flow is easier to scan,
|
|
||||||
- tests cover the critical seams that future feature work will depend on.
|
|
||||||
|
|
||||||
`tasks/service.py` may still be large after this phase, but it should stop being a "many responsibilities blurred together" file.
|
|
||||||
|
|
||||||
## Main decisions
|
|
||||||
|
|
||||||
### 1. Keep orchestration in `tasks` for now
|
|
||||||
|
|
||||||
Do **not** move job lifecycle ownership into `jobs/service.py` in this phase.
|
|
||||||
|
|
||||||
Reason:
|
|
||||||
|
|
||||||
- it is a valid long-term direction,
|
|
||||||
- but it changes semantic ownership of cancellation and webhook application,
|
|
||||||
- which raises regression risk before the current flow is properly typed and decomposed.
|
|
||||||
|
|
||||||
### 2. Add typed internal payload schemas
|
|
||||||
|
|
||||||
Add explicit internal schemas in `cpv3/modules/tasks/schemas.py` for per-job stored payloads.
|
|
||||||
|
|
||||||
These schemas are for internal readability and validation only.
|
|
||||||
|
|
||||||
They should:
|
|
||||||
|
|
||||||
- represent the current JSON shape stored in `job.input_data` / `job.output_data`
|
|
||||||
- remain compatible with existing persisted data
|
|
||||||
- avoid forcing a database migration in this phase
|
|
||||||
- be explicit per job type rather than generic
|
|
||||||
|
|
||||||
Examples of the kind of models expected:
|
|
||||||
|
|
||||||
- media probe input/output
|
|
||||||
- silence detect input/output
|
|
||||||
- silence apply input/output
|
|
||||||
- media convert input/output
|
|
||||||
- transcription generate input/output
|
|
||||||
- frame extract input/output
|
|
||||||
- captions generate input/output
|
|
||||||
|
|
||||||
Important: the database can still store JSON, but `TaskService` should stop passing raw dicts around when internal meaning matters.
|
|
||||||
|
|
||||||
### 3. Split `record_webhook_event()` into explicit stages
|
|
||||||
|
|
||||||
Refactor `record_webhook_event()` into small private methods with one purpose each.
|
|
||||||
|
|
||||||
Target shape:
|
|
||||||
|
|
||||||
- load and validate job state
|
|
||||||
- ignore terminal jobs when appropriate
|
|
||||||
- apply status update
|
|
||||||
- append job event row
|
|
||||||
- run job-type-specific done hooks
|
|
||||||
- send notification
|
|
||||||
- return updated job
|
|
||||||
|
|
||||||
This keeps behavior in one place while making the sequencing obvious.
|
|
||||||
|
|
||||||
### 4. Reduce duplication only where it is obvious
|
|
||||||
|
|
||||||
Allowed helper extraction:
|
|
||||||
|
|
||||||
- output folder resolution
|
|
||||||
- broker reference update
|
|
||||||
- source file lookup/create flow
|
|
||||||
- artifact persistence helpers
|
|
||||||
- notification dispatch helper
|
|
||||||
- common actor start/fail envelope if the resulting code is still explicit
|
|
||||||
|
|
||||||
Do **not** introduce a generic task framework.
|
|
||||||
|
|
||||||
### 5. Keep domain persistence mostly where it is today
|
|
||||||
|
|
||||||
Do not push transcription/media/captions result persistence back into their modules yet.
|
|
||||||
|
|
||||||
Reason:
|
|
||||||
|
|
||||||
- domain ownership may improve long-term,
|
|
||||||
- but doing it before task contracts are typed risks scattering orchestration across several large files.
|
|
||||||
|
|
||||||
This phase should first make the existing orchestration understandable.
|
|
||||||
|
|
||||||
## Execution phases
|
|
||||||
|
|
||||||
### Phase 0 — Lock behavior with tests
|
|
||||||
|
|
||||||
Before changing the flow, expand tests around the current seams.
|
|
||||||
|
|
||||||
Priority coverage:
|
|
||||||
|
|
||||||
- `tests/unit/test_task_service.py`
|
|
||||||
- duplicate active job reuse
|
|
||||||
- terminal job webhook ignore behavior
|
|
||||||
- webhook event update sequencing
|
|
||||||
- artifact persistence trigger points
|
|
||||||
- cancellation path behavior
|
|
||||||
- `tests/unit/test_caption_tasks.py`
|
|
||||||
- caption render fallback behavior
|
|
||||||
- callback confirmation behavior
|
|
||||||
- cancellation-related safety where relevant
|
|
||||||
- integration coverage where current behavior is externally visible
|
|
||||||
- `tests/integration/test_jobs_endpoints.py`
|
|
||||||
- `tests/integration/test_captions_endpoints.py` if affected
|
|
||||||
|
|
||||||
The goal is not broad test expansion. The goal is to pin the behavior of the exact code being refactored.
|
|
||||||
|
|
||||||
### Phase 1 — Introduce typed internal task payloads
|
|
||||||
|
|
||||||
Add internal schemas in `cpv3/modules/tasks/schemas.py` for job payloads.
|
|
||||||
|
|
||||||
Implementation rules:
|
|
||||||
|
|
||||||
- keep schema names explicit per job type
|
|
||||||
- support current field names
|
|
||||||
- make optional fields tolerant enough for existing rows where necessary
|
|
||||||
- use these schemas at service boundaries where `input_data` and `output_data` are read or produced
|
|
||||||
|
|
||||||
Expected outcome:
|
|
||||||
|
|
||||||
- internal payload meaning becomes visible from types instead of being inferred from raw dict access
|
|
||||||
- future changes become easier to review safely
|
|
||||||
|
|
||||||
### Phase 2 — Decompose webhook application flow
|
|
||||||
|
|
||||||
Refactor `TaskService.record_webhook_event()` into a sequence of small private methods.
|
|
||||||
|
|
||||||
Recommended decomposition:
|
|
||||||
|
|
||||||
- `_load_job_for_webhook(...)`
|
|
||||||
- `_should_ignore_webhook(...)`
|
|
||||||
- `_apply_job_status_update(...)`
|
|
||||||
- `_create_job_event(...)`
|
|
||||||
- `_run_done_side_effects(...)`
|
|
||||||
- `_send_job_notification(...)`
|
|
||||||
|
|
||||||
Method names may differ, but the responsibilities should remain this explicit.
|
|
||||||
|
|
||||||
Important:
|
|
||||||
|
|
||||||
- keep sequencing behavior unchanged
|
|
||||||
- preserve the current order where artifacts are saved before notifications when that order matters
|
|
||||||
|
|
||||||
### Phase 3 — Normalize submission helpers
|
|
||||||
|
|
||||||
Refactor repetitive submit methods without hiding behavior.
|
|
||||||
|
|
||||||
The submit methods should remain explicit, but repeated steps can be centralized where the code becomes clearer:
|
|
||||||
|
|
||||||
- resolve user output folder
|
|
||||||
- prepare actor kwargs
|
|
||||||
- create job + webhook
|
|
||||||
- enqueue actor
|
|
||||||
- persist broker reference
|
|
||||||
- build submit response
|
|
||||||
|
|
||||||
The final submit methods should still read as business flows, not as thin wrappers over a generic registry.
|
|
||||||
|
|
||||||
### Phase 4 — Clean actor envelope duplication
|
|
||||||
|
|
||||||
If still useful after earlier phases, standardize only the repeated envelope around actors:
|
|
||||||
|
|
||||||
- cancellation check
|
|
||||||
- running event emission
|
|
||||||
- success/failure reporting
|
|
||||||
|
|
||||||
This should stay simple and local.
|
|
||||||
|
|
||||||
If the helper makes actor behavior harder to follow, do not extract it.
|
|
||||||
|
|
||||||
### Phase 5 — Reassess, do not auto-expand scope
|
|
||||||
|
|
||||||
After the in-place cleanup is done, reassess whether a second phase is justified.
|
|
||||||
|
|
||||||
Only then consider:
|
|
||||||
|
|
||||||
- moving lifecycle semantics into `jobs`
|
|
||||||
- pushing result persistence into owning modules
|
|
||||||
|
|
||||||
Those are explicitly **not** part of the current plan.
|
|
||||||
|
|
||||||
## File-by-file plan
|
|
||||||
|
|
||||||
### `cpv3/modules/tasks/schemas.py`
|
|
||||||
|
|
||||||
- Add explicit internal payload schemas for job input/output.
|
|
||||||
- Keep public API request/response schemas stable.
|
|
||||||
- Prefer additive internal typing over schema churn.
|
|
||||||
|
|
||||||
### `cpv3/modules/tasks/service.py`
|
|
||||||
|
|
||||||
- Keep this file as the orchestration center for this phase.
|
|
||||||
- Decompose large methods into readable private steps.
|
|
||||||
- Replace raw internal dict usage with typed parsing/serialization where the meaning matters.
|
|
||||||
- Reduce repeated code only through local, explicit helpers.
|
|
||||||
|
|
||||||
### `cpv3/modules/tasks/router.py`
|
|
||||||
|
|
||||||
- Keep routes unchanged.
|
|
||||||
- Only adjust delegation or error handling if required to support clearer internal service boundaries.
|
|
||||||
|
|
||||||
### `cpv3/modules/jobs/router.py`
|
|
||||||
|
|
||||||
- Keep the current cancel entrypoint behavior.
|
|
||||||
- If touched, only make delegation clearer.
|
|
||||||
- Do not move cancel semantics into `jobs/service.py` in this phase.
|
|
||||||
|
|
||||||
### `cpv3/modules/captions/service.py`
|
|
||||||
|
|
||||||
- Keep current ownership.
|
|
||||||
- Do not add more orchestration here in phase 1.
|
|
||||||
- Only make supporting adjustments if typed payload work needs a clearer boundary.
|
|
||||||
|
|
||||||
### `cpv3/modules/media/service.py`
|
|
||||||
|
|
||||||
- Keep media processing helpers as-is unless task cleanup reveals a very small, obvious extraction need.
|
|
||||||
- Avoid expanding this file into a second orchestration center.
|
|
||||||
|
|
||||||
## Risk controls
|
|
||||||
|
|
||||||
### Preserve persisted JSON compatibility
|
|
||||||
|
|
||||||
Existing jobs may already contain payloads in the database.
|
|
||||||
|
|
||||||
Therefore:
|
|
||||||
|
|
||||||
- typed internal schemas must support current persisted shapes
|
|
||||||
- avoid renaming stored keys unless there is a very strong reason
|
|
||||||
- prefer backward-compatible parsing over cleanup for cleanup’s sake
|
|
||||||
|
|
||||||
### Preserve side-effect ordering
|
|
||||||
|
|
||||||
Current flow saves some artifacts before notification dispatch.
|
|
||||||
|
|
||||||
That ordering matters because clients may refetch immediately after notification.
|
|
||||||
|
|
||||||
Do not change this ordering unless there is a proven reason and test coverage for the new behavior.
|
|
||||||
|
|
||||||
### Avoid ownership churn during cleanup
|
|
||||||
|
|
||||||
This phase is about readability and safer edits, not about redistributing the architecture.
|
|
||||||
|
|
||||||
If a change starts to feel like "this really belongs in another module," mark it for reassessment after phase 1 instead of expanding scope immediately.
|
|
||||||
|
|
||||||
## Verification strategy
|
|
||||||
|
|
||||||
For implementation of this plan, verification should include:
|
|
||||||
|
|
||||||
- targeted unit tests for `TaskService`
|
|
||||||
- targeted unit tests for caption task actor behavior
|
|
||||||
- relevant integration tests for jobs/tasks endpoints
|
|
||||||
- Ruff checks for touched files
|
|
||||||
|
|
||||||
The most important verification is behavioral:
|
|
||||||
|
|
||||||
- task submission still works
|
|
||||||
- duplicate job reuse still works
|
|
||||||
- webhook updates still drive correct job state
|
|
||||||
- artifact persistence still happens before notification where required
|
|
||||||
- cancellation still behaves as before
|
|
||||||
|
|
||||||
## Definition of done for this phase
|
|
||||||
|
|
||||||
Phase 1 is complete when all of the following are true:
|
|
||||||
|
|
||||||
- internal job payload handling is typed where it matters
|
|
||||||
- `record_webhook_event()` is decomposed into explicit, readable steps
|
|
||||||
- repetitive submit flow is reduced without introducing hidden abstractions
|
|
||||||
- tests protect the main task orchestration seams
|
|
||||||
- public APIs remain effectively unchanged
|
|
||||||
- the backend is easier to change safely without rediscovering task flow each time
|
|
||||||
|
|
||||||
## Explicit non-goals
|
|
||||||
|
|
||||||
This plan does **not** include:
|
|
||||||
|
|
||||||
- moving lifecycle ownership into `jobs/service.py`
|
|
||||||
- redesigning the task system
|
|
||||||
- introducing a generic abstraction layer for tasks
|
|
||||||
- moving artifact persistence into every owning domain module
|
|
||||||
- broad route redesign
|
|
||||||
- frontend contract changes
|
|
||||||
- module structure changes
|
|
||||||
|
|
||||||
## Follow-up after this phase
|
|
||||||
|
|
||||||
Once this plan is implemented and stable, reassess whether there is enough remaining pressure to justify a second phase.
|
|
||||||
|
|
||||||
If yes, the next candidate should be:
|
|
||||||
|
|
||||||
- **Option 2** selectively, and only where phase 1 proves that lifecycle ownership is still the main source of friction.
|
|
||||||
|
|
||||||
Until then, keep the refactor intentionally conservative.
|
|
||||||
@@ -354,18 +354,23 @@ async def apply_silence_cuts(
|
|||||||
proc = await asyncio.create_subprocess_exec(
|
proc = await asyncio.create_subprocess_exec(
|
||||||
*cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
|
*cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
|
||||||
)
|
)
|
||||||
|
stderr_stream = getattr(proc, "stderr", None)
|
||||||
|
stderr_task = asyncio.create_task(
|
||||||
|
stderr_stream.read() if stderr_stream is not None else asyncio.sleep(0, result=b"")
|
||||||
|
)
|
||||||
|
if on_progress is not None:
|
||||||
|
stdout_stream = getattr(proc, "stdout", None)
|
||||||
progress_task = asyncio.create_task(
|
progress_task = asyncio.create_task(
|
||||||
_forward_ffmpeg_progress(
|
_forward_ffmpeg_progress(
|
||||||
proc.stdout,
|
stdout_stream,
|
||||||
duration_seconds=output_duration_seconds,
|
duration_seconds=output_duration_seconds,
|
||||||
on_progress=on_progress,
|
on_progress=on_progress,
|
||||||
progress_stage="applying_cuts",
|
progress_stage="applying_cuts",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
stderr_task = asyncio.create_task(
|
|
||||||
proc.stderr.read() if proc.stderr is not None else asyncio.sleep(0, result=b"")
|
|
||||||
)
|
|
||||||
await asyncio.gather(progress_task, stderr_task)
|
await asyncio.gather(progress_task, stderr_task)
|
||||||
|
else:
|
||||||
|
await stderr_task
|
||||||
await proc.wait()
|
await proc.wait()
|
||||||
stderr = stderr_task.result()
|
stderr = stderr_task.result()
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
The user wants to refactor a backend project following DRY and KISS, keeping it developer-readable without hidden abstractions.
|
|
||||||
The user explicitly rejected a plan that did "in-place cleanup" of `cpv3/modules/tasks/service.py` and instead wants a different approach.
|
|
||||||
|
|
||||||
Currently, `tasks/service.py` is a 1600+ line monolith that:
|
|
||||||
1. Defines Dramatiq actors
|
|
||||||
2. Orchestrates job creation and duplication-checks
|
|
||||||
3. Has `submit_X` methods (e.g. `submit_media_probe`, `submit_transcription_generate`)
|
|
||||||
4. Has a giant `record_webhook_event` that updates the `Job` state
|
|
||||||
5. Contains domain-specific artifact saving (e.g. `_save_transcription_artifacts`, `_save_convert_artifacts`)
|
|
||||||
6. Handles cancellation logic.
|
|
||||||
|
|
||||||
Constraints:
|
|
||||||
1. Must use the exact module structure: `models.py`, `schemas.py`, `repository.py`, `service.py`, `router.py` (no subdirectories within modules).
|
|
||||||
2. Explicit, local helpers over hidden abstractions (no generic handler registries).
|
|
||||||
|
|
||||||
What is the best architectural approach to distribute these responsibilities across `jobs`, `tasks`, and domain modules (`media`, `transcription`, `captions`)?
|
|
||||||
Provide a concrete file-by-file blueprint on where each responsibility belongs and how the cross-module calls would look like, avoiding circular dependencies.
|
|
||||||
@@ -22,6 +22,9 @@ class _FakeProcess:
|
|||||||
async def communicate(self) -> tuple[bytes, bytes]:
|
async def communicate(self) -> tuple[bytes, bytes]:
|
||||||
return b"", b""
|
return b"", b""
|
||||||
|
|
||||||
|
async def wait(self) -> int:
|
||||||
|
return self.returncode
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_remove_silence_uses_single_input_trim_filter(tmp_path) -> None:
|
async def test_remove_silence_uses_single_input_trim_filter(tmp_path) -> None:
|
||||||
|
|||||||
Reference in New Issue
Block a user