# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview SIBU (Sistema de Transporte) is a PWA for public transportation in Panama. It has two main parts: - **Backend**: FastAPI + SQLModel + PostgreSQL (in `backend/`), managed with `uv` - **Frontend**: Vue 3 + Vite + TypeScript + Tailwind CSS (in `frontend/`), managed with `bun` The frontend uses **Supabase** for auth and real-time data, while the backend provides the REST API. Both can be used together or independently. --- ## Commands ### Development ```bash make dev # Run both backend + frontend concurrently make dev-backend # Backend only → http://localhost:8000 make dev-frontend # Frontend only → http://localhost:5173 ``` ### Install ```bash make setup # Install all deps + instructions make install-backend # uv sync make install-frontend # bun install ``` ### Migrations ```bash make migrate-up # Apply all pending make migrate-down # Rollback last make migrate-create NAME=nombre # Create new migration make migrate-history # Show history ``` ### Lint & Format ```bash make lint-backend # ruff check --fix make format-backend # ruff format make lint-frontend # bun run build (type-check via vue-tsc) ``` ### Tests ```bash make test-backend # uv run pytest make test-frontend # bun run test ``` ### Database utilities ```bash make seed # Seed initial data make db-reset # Drop all tables + recreate (asks for confirmation) make import-coordinates ROUTE="Boquete>David" # Import coords from Supabase make import-coordinates ALL=true ``` --- ## Package Management Rules - **Backend**: NEVER edit `pyproject.toml` manually — use `uv add ` - **Frontend**: NEVER edit `package.json` manually — use `bun add ` --- ## Environment Variables ### Backend (`backend/.env.development`) ``` DATABASE_URL=postgresql+asyncpg://localhost:5432/sibu_dev ENVIRONMENT=development DEBUG=true ``` ### Frontend (`frontend/.env.development`) ``` VITE_API_URL=http://localhost:8000 VITE_GOOGLE_MAPS_API_KEY=... VITE_SUPABASE_URL=... VITE_SUPABASE_ANON_KEY=... ``` --- ## Architecture ### Frontend Architecture **Auth** is handled by Supabase (`src/supabase.ts`). The `useAuthStore` (Pinia) listens to `onAuthStateChange` and only reloads the user profile on `SIGNED_IN` / `INITIAL_SESSION` events — not on `TOKEN_REFRESHED` — to avoid network hangs on mobile wake. **User roles**: `PASSENGER` (default), `DRIVER`, `PROMOTER`, `ADMIN`. The router (`src/router/index.ts`) enforces role-based access via `meta.requiresAuth` and `meta.role`. Auth check has a 3-second timeout to avoid blocking the UI. **State**: Pinia stores in `src/stores/` — one per domain (`auth`, `route`, `busStop`, `map`, `shuttle`, `taxi`, `coupon`, `favorites`, `schedule`, `theme`). State is persisted via `pinia-plugin-persistedstate`. **Services** (`src/services/`) are thin API clients — one per resource. They call the FastAPI backend or Supabase directly. **Composables** (`src/composables/`) contain map logic: `useGoogleMaps`, `useMapState`, `useDirectionsRoute`, `useETA`, `useParadaCercana`, `useFlujoPrincipal`. **Routing structure**: - `/` — Landing - `/map` — Main Google Maps view - `/routes`, `/schedules`, `/bus-stop/:id` — Transit info - `/transporte/viajes-turisticos` — Tourist shuttles (nested layout) - `/transporte/taxis-locales` — Local taxis - `/discover`, `/coupons`, `/favorites`, `/profile` — App features - `/admin`, `/driver`, `/promoter` — Role-protected dashboards **PWA**: Configured with `vite-plugin-pwa`. Service worker uses `autoUpdate`. API routes (`/api`, `/rest/v1`) are excluded from navigation fallback to prevent blank screens. **i18n**: `vue-i18n` with `es` and `en` locales in `src/i18n/locales/`. ### Backend Architecture ``` backend/app/ ├── api/ # Route handlers (FastAPI routers) ├── core/ # config.py (pydantic-settings), database.py, seed.py ├── models/ # SQLModel table models ├── schemas/ # Pydantic request/response schemas └── services/ # Business logic layer ``` Config is loaded from `app/core/config.py` using `pydantic-settings`. Database sessions use async SQLAlchemy via `asyncpg`. All API routes use the `/api/` prefix. ### Vue Component Conventions - Always use `