# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## CRITICAL: Read AGENTS.md First **Before starting any work in this repository**, you MUST read `AGENTS.md` in the project root. - `AGENTS.md` contains comprehensive Phoenix/LiveView/Elixir guidelines that are mandatory for this project - These guidelines take precedence over general development practices when there's a conflict - Always read `AGENTS.md` at the start of a new conversation or when resuming work - Follow the project-specific patterns, conventions, and constraints documented there ## Project Overview Towerops is a Phoenix 1.8 web application built with Elixir, using Ecto for database operations (PostgreSQL), LiveView for real-time interactions, and Tailwind CSS v4 for styling. ### Data Model Relationships ``` ┌─────────────┐ │ User │ │ (Accounts) │ └──────┬──────┘ │ owns/member of (many-to-many) │ ↓ ┌──────────────────────────────────────────────────────┐ │ Organization │ │ (Organizations) │ └────┬────────────┬─────────────┬──────────────────────┘ │ │ │ │ has many │ has many │ has many │ │ │ ↓ ↓ ↓ ┌─────────┐ ┌──────────┐ ┌────────────────┐ │ Site │ │Equipment │ │ AgentToken │ │ (Sites) │ │(Equipment│ │ (Agents) │ └────┬────┘ └────┬─────┘ └────────┬───────┘ │ │ │ │ has many │ has one │ assigned via │ │ │ ↓ ↓ ↓ ┌──────────┐ ┌──────────────┐ ┌──────────────────┐ │Equipment │ │ SNMPDevice │ │ AgentAssignment │◀──┐ │(Equipment│ │(Snmp.Devices)│ │ (Agents) │ │ └────┬─────┘ └──────────────┘ └──────────────────┘ │ │ │ │ │ has many └───────────────┘ ├────────────────┬─────────────────┘ │ │ assigns equipment ↓ ↓ to agent ┌──────────────┐ ┌─────────┐ │MonitoringCheck│ │ Alert │ │ (Monitoring) │ │ (Alerts)│ └──────────────┘ └─────────┘ Key Relationships: - User can own/belong to multiple Organizations - Organization has default_agent_token_id (optional) - Equipment belongs to both Site and Organization (denormalized) - Equipment can be assigned to one AgentToken via AgentAssignment - Equipment has one SNMPDevice with Sensors and Interfaces - Equipment has many MonitoringChecks (polling results) - Equipment has many Alerts (equipment_down, equipment_up) - AgentToken authenticates remote agents for local SNMP polling ``` **Note to AI assistants**: When you make changes to the data model (migrations, schema additions, new contexts), update this diagram to reflect the current state. ## Essential Commands ### Setup and Development - `mix setup` - Install dependencies, create/migrate database, setup and build assets - `mix phx.server` - Start the Phoenix server (accessible at http://localhost:4000) - `iex -S mix phx.server` - Start server with interactive Elixir shell ### Testing and Quality - `mix test` - Run all tests (automatically creates and migrates test database) - `mix test test/path/to/specific_test.exs` - Run a specific test file - `mix test --failed` - Re-run only previously failed tests - `mix test --cover` - Run tests with coverage report (view: `open cover/modules_*.html`) - `mix precommit` - **Run before committing**: compiles with warnings as errors, unlocks unused deps, formats code, and runs tests - `mix dialyzer` - Run static type analysis **Coverage Notes**: - Target: 90% minimum - Protobuf-generated modules (Towerops.Agent.*) show 0% but don't need tests - TimescaleDB aggregate tests should be tagged `@tag :skip` (test DB lacks continuous aggregates) ### Database - `mix ecto.create` - Create the database - `mix ecto.migrate` - Run pending migrations - `mix ecto.reset` - Drop, create, and migrate database - `mix ecto.gen.migration migration_name_using_underscores` - Generate a new migration file ### Assets - `mix assets.build` - Build CSS and JS assets (Tailwind + esbuild) - `mix assets.deploy` - Build minified assets for production ## Architecture ### Application Structure Standard Phoenix conventions with separation between business logic (`lib/towerops/`) and web interface (`lib/towerops_web/`). **Key Configuration**: - **Binary IDs**: Generators use binary (UUID) primary keys by default (`binary_id: true`) - **Timestamps**: Use `:utc_datetime` for all timestamps - **Web server**: Bandit adapter (not Cowboy) - **HTTP client**: `:req` library (Req module) - this is the only approved HTTP client - **Ecto repos**: `[Towerops.Repo]` ### Web Layer Patterns All LiveViews, LiveComponents, and HTML modules automatically get these imports/aliases via `html_helpers/0`: - `ToweropsWeb.CoreComponents` - Core UI components (`<.button>`, `<.input>`, `<.form>`, etc.) - `ToweropsWeb.Layouts` - Layout components - `Phoenix.LiveView.JS` - Client-side JS commands - Gettext for translations - Verified routes with `~p` sigil ### Rate Limiting Uses Hammer (ETS-backed) for rate limiting to prevent brute-force attacks. **Endpoints Protected:** - **Auth endpoints** (10 req/min per IP): `/users/log-in`, `/users/register`, `/users/reset-password`, TOTP verification, mobile auth QR flows - **API v1 endpoints** (1000 req/min per IP): `/api/v1/*` - relaxed for Terraform/automation - **Admin API endpoints**: Not rate limited (superuser only, different attack profile) **Implementation:** - Plug: `ToweropsWeb.Plugs.RateLimit` with `:auth` or `:api` type - Uses client's real IP from `X-Forwarded-For` or `X-Real-IP` headers (for proxy/load balancer) - Returns `429 Too Many Requests` with `Retry-After` header when limit exceeded **Configuration:** - Disabled in test environment via `config :towerops, :rate_limiting_enabled, false` - ETS backend configured in `config/config.exs` - Hammer process started in `application.ex` supervision tree ### Asset Pipeline - **Tailwind CSS v4**: Uses new `@import "tailwindcss"` syntax in `assets/css/app.css`, no `tailwind.config.js` needed - **esbuild**: Bundles JavaScript from `assets/js/app.js` - All vendor scripts/styles must be imported into app.js/app.css - cannot reference external src/href in layouts - No inline `