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

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