# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview NexHome — a modern American-style second-hand house sales website built with FastAPI + Jinja2 templates. Features user authentication, property listings with search/filter, property CRUD with image upload, favorites, contact info with international phone formatting, and a user dashboard. ## Running the App ```bash source .venv/bin/activate # Recreate DB tables (first time or after model changes) python -c "from database import engine; from models import Base; Base.metadata.drop_all(bind=engine); Base.metadata.create_all(bind=engine)" # Start the dev server uvicorn main:app --reload ``` **Prerequisites:** - Python 3.14 - MySQL server running locally with a `NexHome` database - Set the `SECRET_KEY` environment variable (used by `auth.py` for JWT signing) ## Architecture **`main.py`** — FastAPI entry point. Creates the app, includes auth and properties routers, creates DB tables on startup, serves the homepage. **`auth.py`** — Authentication router (`/auth` prefix). Access-refresh token system: access token (15 min) + refresh token (7 days, stored in DB). `get_current_user()` checks access token cookie/bearer first, auto-refreshes via refresh token if expired. Web login sets both cookies; logout revokes refresh token in DB. **`config.py`** — Shared config: `SECRET_KEY`, `ALGORITHM`, `ACCESS_TOKEN_EXPIRE_MINUTES` (15), `REFRESH_TOKEN_EXPIRE_DAYS` (7), `templates`, `bcrypt_context`, `oauth2_bearer`. Jinja2 cache disabled for Python 3.14 compatibility. **`database.py`** — SQLAlchemy setup with MySQL engine, `SessionLocal`, `Base`. **`models.py`** — ORM models: `User` (with email/full_name/phone), `Property` (with contact_email/contact_phone), `PropertyImage`, `Favorite`, `RefreshToken` (for token rotation/revocation). **`properties.py`** — Property CRUD, search/filter, favorites, dashboard. Static paths (`/properties/new`) must be defined before parameterized paths (`/properties/{prop_id}`). ## Data Flow Request → `RefreshTokenMiddleware` (sets new access cookie if refreshed) → Router → dependency injection (`get_current_user`, `get_db`) → SQLAlchemy → Jinja2 template → HTML response. **Auth flow:** Login → issue access (15 min) + refresh (7 days) tokens → both set as HttpOnly cookies. Page load → `get_current_user()` decodes access token; if expired, uses refresh token cookie to get new access token via `try_refresh()`. Logout → revoke refresh token in DB, clear both cookies. **TemplateResponse API:** `templates.TemplateResponse(request, "template.html", {"user": user, ...})` — request is first arg (Starlette 1.x). ## Key Conventions - DB sessions: `Annotated[Session, Depends(get_db)]` (the `db_dependency` alias). - Redirect after POST: `RedirectResponse(url="...", status_code=303)`. - Image uploads: saved to `static/properties/` with UUID filenames, max 5MB. - USD currency: prices stored as integer dollars, displayed as `${:,}`. - Phone input: `templates/components/phone_input.html` — JS-powered country code selector with flags, dynamic placeholders, auto-formatting. - Route ordering: static paths before parameterized paths in `properties.py`. ## Template Structure - `templates/base.html` — Tailwind CSS CDN layout with navbar + footer - `templates/components/` — navbar, footer, property_card macro, phone_input - `templates/auth/` — login, register - `templates/properties/` — list, detail, create, edit - `templates/dashboard/` — user dashboard (my listings + favorites) ## Known Issues - `database.py` exports the engine as `engin` (typo). - No `requirements.txt` or `pyproject.toml`. - Database credentials hardcoded in `database.py`.