-
Notifications
You must be signed in to change notification settings - Fork 1
how to contribute development workflow
The branch, code, test, PR, merge cycle for the 360Ghar backend. This page is mechanics. For what reviewers expect, see index.md. For conventions, see patterns-and-conventions.md.
The project uses uv for dependency management. Dependencies are declared in pyproject.toml and locked in uv.lock. Always prefix commands with uv run so the managed venv is used. Running python run.py directly uses the system Python, which lacks project dependencies like pgvector and will fail with ModuleNotFoundError.
uv sync --extra dev # Install runtime + dev deps (pytest, ruff, mypy)
uv run python run.py # Start the API on 0.0.0.0:3600For hot reload, uv run fastapi dev app/main.py --host 0.0.0.0 --port 3600 works. Locally you usually want Postgres+PostGIS and Redis up:
docker-compose up -d db redisCopy .env.example to .env and fill in DATABASE_URL, SUPABASE_URL, SUPABASE_*_KEY, REDIS_URL, and the AI provider keys you plan to exercise.
Branch from main. Keep the name short and intent-revealing, for example feat/flatmates-super-like or fix/booking-cursor. The team is two people, so branch hygiene is mostly about not stomping on each other.
Follow the patterns enforced by ruff (see patterns-and-conventions.md and tooling.md for the full list). The non-negotiables:
-
from __future__ import annotationsas the first import in every.pyfile. -
X | NonenotOptional[X],list[X]notList[X],dict[K, V]notDict[K, V]. - Async-first database access via
AsyncSessioninjected through FastAPI dependencies. - Service-class pattern:
class XService: def __init__(self, db: AsyncSession). - Exception chaining in
exceptblocks (from eorfrom None). - No ephemeral
async with httpx.AsyncClient()per request. Use the shared clients inapp/core/http.pywith per-requesttimeout=overrides. - No new
AsyncIOSchedulerinstances. Useget_scheduler()fromapp/infrastructure/scheduler.py.
Place code by layer: endpoints in app/api/api_v1/endpoints/, business logic in app/services/, persistence in app/models/, transport in app/schemas/, MCP logic in app/mcp/. The contribution contract has the full placement rules.
uv run pytest tests/ -v # All tests
uv run pytest tests/unit/services/ -v # A subtree
uv run pytest tests/test_user_service.py -v # One file
uv run pytest tests/ -k "user" -v # By keyword
uv run pytest tests/ --cov=app --cov-report=htmlCoverage must stay at or above 90%; CI enforces --cov-fail-under=90. Pick the narrowest layer that proves the behavior: tests/unit/ for isolated logic, tests/api/ for REST behavior, tests/integration/ for database semantics, tests/e2e/ for cross-layer flows, tests/mcp/ for MCP tools, tests/pm/ for property management, tests/middleware/ for request pipeline. See testing.md for the full breakdown.
External network calls must be mocked with respx, AsyncMock, or local fakes. Default test runs never hit live third parties.
The seed system lives in seed_data/. It generates deterministic JSON (with random.seed(42)), loads it into the database, and uploads media to Cloudinary. Seed records set is_seed_data = true on users, agents, and properties.
uv run python seed_data/01_load_all.py # Load all data
uv run python seed_data/01_load_all.py --only hardcoded,seed # Skip generated activity
uv run python seed_data/01_load_all.py --quick # Quick mode
uv run python seed_data/01_load_all.py --dry-run # Validate without writingClear with seed_data/02_clear_data.py:
uv run python seed_data/02_clear_data.py --confirmThese rules are load-bearing and enforced by review:
-
Never delete real user data. Any
DELETE,TRUNCATE, orDROPon a table that may hold real user data must be reviewed with the user before execution. -
02_clear_data.pyis dev-only. It filters byWHERE is_seed_data = trueonusers,agents, andproperties, and deletes child records via subquery joins to seed parents. Never run it against production. -
Child tables are protected via FK joins. Tables without an
is_seed_datacolumn (PropertyImage, Visit, Booking, BlogPost, etc.) are only touched when their FK parent is a confirmed seed record. Never issue bareDELETE FROMon tables that could contain real data. -
New seeded models must either add an
is_seed_databoolean column withserver_default=text("false")or cascade from an existing seeded parent.
Before pushing, run the same lint and type jobs CI runs:
uv run ruff check app/ --output-format=github
uv run mypy app/ --ignore-missing-importsRuff rules are listed in tooling.md and patterns-and-conventions.md. Common violations to watch for: missing from __future__ import annotations, Optional/List/Dict from typing, bare except without from e/from None, == True/== False on columns, single-letter l variable names, and zip without strict=.
- Push your branch and open a PR against
main. - Confirm all three CI jobs pass:
docs-contracts,test,lint. - Update
docs/repo-contract.jsonif you added or moved an endpoint, service, or MCP module. Thedocs-contractsjob will fail if the inventory drifts. - Request review. For auth, schedulers, migrations, or data-deletion paths, review is mandatory.
- Squash or rebase merge into
main. There is nodeveloplong-running branch in active use, although CI still triggers on it.
After merge, Railway auto-deploys from main via the railway.toml healthcheck on /health.
- testing.md for the test suite, fixtures, and coverage rules.
- debugging.md for logs, request IDs, and common errors.
- tooling.md for uv, ruff, mypy, Docker, and Supabase CLI migrations.
- patterns-and-conventions.md for the full coding conventions.
- Features overview
- Ghar Core (marketplace)
- 360 Stays (bookings)
- 360 Flatmates
- Property Management
- 360 Virtual Tours
- 360 Data Hub
- MCP servers and widgets
- AI agent
- Blog and SEO
- Notifications
- Vastu analyzer