- feature access/refresh tokens auth
3.7 KiB
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
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
NexHomedatabase - Set the
SECRET_KEYenvironment variable (used byauth.pyfor 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)](thedb_dependencyalias). - 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 + footertemplates/components/— navbar, footer, property_card macro, phone_inputtemplates/auth/— login, registertemplates/properties/— list, detail, create, edittemplates/dashboard/— user dashboard (my listings + favorites)
Known Issues
database.pyexports the engine asengin(typo).- No
requirements.txtorpyproject.toml. - Database credentials hardcoded in
database.py.