prop/CLAUDE.md
2026-03-28 11:28:47 -05:00

116 lines
4.8 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
Microwaveprop is a Phoenix 1.8 web application (Elixir ~> 1.15) with LiveView, PostgreSQL via Ecto, and Tailwind CSS v4 + daisyUI for styling. HTTP server is Bandit.
**All UI must be built with Phoenix LiveView.** Write idiomatic Elixir throughout. Phoenix uses esbuild for JS bundling — never run npm or use Node.js tooling.
## Commands
```bash
# Initial setup (deps, DB, assets)
mix setup
# Run dev server (live reloads automatically, no restart needed)
mix phx.server
iex -S mix phx.server # with IEx shell
# Run all tests
mix test
# Run a single test file
mix test test/microwaveprop_web/controllers/page_controller_test.exs
# Run previously failed tests
mix test --failed
# Format code (runs Styler plugin automatically)
mix format
# Static analysis
mix credo
# Pre-commit check (compile with warnings-as-errors, unlock unused deps, format, test)
# Runs in test env
mix precommit
# Database
mix ecto.create
mix ecto.migrate
mix ecto.gen.migration migration_name_using_underscores
mix ecto.reset # drop + setup
# Assets
mix assets.build
mix assets.deploy # minified + digest
```
## Architecture
Standard Phoenix 1.8 structure:
- `lib/microwaveprop/` - Business logic (contexts, schemas, repo)
- `repo.ex` - Ecto PostgreSQL repository
- `application.ex` - OTP supervision tree
- `lib/microwaveprop_web/` - Web layer
- `router.ex` - Routes and pipelines. The `:browser` scope is aliased to `MicrowavepropWeb`
- `components/core_components.ex` - UI component library (flash, button, input, table, list, icon)
- `components/layouts.ex` - Layout components; `Layouts` is aliased in `microwaveprop_web.ex`
- `controllers/` - Traditional controllers
- `config/` - Environment configs (`dev.exs`, `test.exs`, `prod.exs`, `runtime.exs`)
- `assets/` - JS (esbuild, not npm) and CSS (Tailwind v4). Only `app.js` and `app.css` bundles are supported
- `test/support/` - `ConnCase` and `DataCase` test helpers
## Key Conventions (from AGENTS.md)
### Phoenix / LiveView
- LiveView templates must start with `<Layouts.app flash={@flash} ...>` wrapping all content
- Use `<.icon name="hero-x-mark" class="w-5 h-5"/>` for icons, never Heroicons modules
- Use `<.input>` from core_components for form inputs
- Use `to_form/2` for forms, never pass changesets directly to templates
- Use LiveView streams for collections, never `phx-update="append"`/`"prepend"`
- Avoid LiveComponents unless strongly justified
- LiveView names use `Live` suffix: `MicrowavepropWeb.ThingLive`
- Use `<.link navigate={...}>` / `<.link patch={...}>`, never `live_redirect`/`live_patch`
- Router scope aliases prefix automatically; don't add redundant aliases
### HEEx Templates
- Use `{...}` for attribute interpolation, `<%= %>` only for block constructs (if/for/cond) in tag bodies
- Class lists must use `[...]` syntax for conditional classes
- Use `<%!-- comment --%>` for HTML comments
- Use `phx-no-curly-interpolation` on tags containing literal curly braces
- Never use `<% Enum.each %>`, always use `<%= for item <- @collection do %>`
### JS / CSS
- Assets are bundled via esbuild and Tailwind mix tasks — never use npm, npx, or Node.js directly
- Tailwind v4: no `tailwind.config.js`, uses `@import "tailwindcss" source(none)` syntax in `app.css`
- Never use `@apply` in CSS
- No inline `<script>` tags; use colocated JS hooks (`:type={Phoenix.LiveView.ColocatedHook}`) with `.` prefix names
- Vendor deps must be imported into `app.js`/`app.css`, no external script `src` or link `href`
### Elixir
- Write idiomatic Elixir: use pattern matching, pipe operator, and the standard library
- Styler auto-formats on `mix format` (alias sorting, pipe chains, moduledoc enforcement, etc.)
- No index access on lists (`mylist[i]`); use `Enum.at/2`
- Bind results of `if`/`case`/`cond` blocks to variables (immutable rebinding)
- Never nest multiple modules in one file
- Use `struct.field` not `struct[:field]` (structs don't implement Access)
- Predicate functions: `thing?` not `is_thing` (reserve `is_` for guards)
- Use `Req` for HTTP requests, never httpoison/tesla/httpc
### Ecto
- Preload associations in queries when accessed in templates
- `field :name, :string` for both string and text columns
- Use `Ecto.Changeset.get_field/2` to access changeset fields
- Programmatic fields (e.g. `user_id`) must not be in `cast` calls
- Generate migrations with `mix ecto.gen.migration`
### Testing
- Use `start_supervised!/1` for process cleanup
- Use `Process.monitor/1` + `assert_receive {:DOWN, ...}` instead of `Process.sleep`
- Use `LazyHTML` selectors for DOM assertions, never raw HTML matching
- Test against element IDs defined in templates
- Debug with `LazyHTML.filter/2` + `IO.inspect` instead of raw HTML dumps