Files
Black-Cyan 3f386e5e38 ✏️
- feature access/refresh tokens auth
2026-06-11 15:59:29 +08:00

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 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.