4.8 KiB
4.8 KiB
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
# 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 repositoryapplication.ex- OTP supervision tree
lib/microwaveprop_web/- Web layerrouter.ex- Routes and pipelines. The:browserscope is aliased toMicrowavepropWebcomponents/core_components.ex- UI component library (flash, button, input, table, list, icon)components/layouts.ex- Layout components;Layoutsis aliased inmicrowaveprop_web.excontrollers/- Traditional controllers
config/- Environment configs (dev.exs,test.exs,prod.exs,runtime.exs)assets/- JS (esbuild, not npm) and CSS (Tailwind v4). Onlyapp.jsandapp.cssbundles are supportedtest/support/-ConnCaseandDataCasetest 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/2for 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
Livesuffix:MicrowavepropWeb.ThingLive - Use
<.link navigate={...}>/<.link patch={...}>, neverlive_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-interpolationon 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 inapp.css - Never use
@applyin 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 scriptsrcor linkhref
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]); useEnum.at/2 - Bind results of
if/case/condblocks to variables (immutable rebinding) - Never nest multiple modules in one file
- Use
struct.fieldnotstruct[:field](structs don't implement Access) - Predicate functions:
thing?notis_thing(reserveis_for guards) - Use
Reqfor HTTP requests, never httpoison/tesla/httpc
Ecto
- Preload associations in queries when accessed in templates
field :name, :stringfor both string and text columns- Use
Ecto.Changeset.get_field/2to access changeset fields - Programmatic fields (e.g.
user_id) must not be incastcalls - Generate migrations with
mix ecto.gen.migration
Testing
- Use
start_supervised!/1for process cleanup - Use
Process.monitor/1+assert_receive {:DOWN, ...}instead ofProcess.sleep - Use
LazyHTMLselectors for DOM assertions, never raw HTML matching - Test against element IDs defined in templates
- Debug with
LazyHTML.filter/2+IO.inspectinstead of raw HTML dumps