
# [App Name] · Phoenix LiveView

A LiveView app. Server-rendered HTML over WebSocket. Realtime updates without a JS framework.

## Source of truth
Production runs as a Phoenix release on Fly.io (BEAM clusters across Fly regions). Postgres in the same primary region with read replicas elsewhere. The Phoenix release tarball is canonical.

## Tech stack
Elixir 1.18 + Phoenix 1.8 + LiveView 1.0 + Phoenix.PubSub for cross-process messaging. Ecto + Postgres. Tailwind v4 (built via esbuild + tailwind ports). Oban for background jobs. ExUnit for tests. Deployed via Fly's Elixir launcher.

## Deploy
`fly deploy` from local. Releases are built via `mix release` inside the Fly builder. Postgres on Fly.

## File map
- `lib/myapp/` business domain (Ecto schemas, contexts)
- `lib/myapp_web/` web layer (LiveView modules, controllers, components)
- `lib/myapp_web/live/` LiveView modules, one per major surface
- `lib/myapp_web/components/` reusable function components
- `lib/myapp/repo.ex` Ecto repo
- `lib/myapp/application.ex` supervision tree (PubSub, Repo, Endpoint, Oban)
- `priv/repo/migrations/` Ecto migrations
- `assets/` Tailwind + esbuild entrypoints
- `mix.exs` deps + release config
- `fly.toml`

## .env keys
- `DATABASE_URL`
- `SECRET_KEY_BASE` (generate with `mix phx.gen.secret`)
- `PHX_HOST` your prod hostname
- `POOL_SIZE` Ecto pool, default 10

## Hard rules
- Business logic in contexts, NOT in LiveView modules. LiveView is the UI layer.
- `assign` everything you read in the template into `socket.assigns`. NEVER read from sockets implicitly.
- For lists with thousands of items, use streams (`stream/4`). Don't put 10k items into assigns.
- Phoenix.PubSub for any cross-LiveView communication. Don't hand-roll Channels.
- Migrations are reversible (`up` AND `down`). Tested with `mix ecto.rollback`.
- Use Oban for anything async. Don't `Task.start` in handlers; restarts will leak.

## Recent significant changes
- 2026-05-13: Scaffolded. Locked: LiveView 1.0 (stable now), Oban over Quantum (better persistence), Fly over Render (BEAM clustering across regions matters).

## Next session: start here
1. `mix phx.new myapp --live` to scaffold (or apply this CLAUDE.md over an existing scaffold).
2. Create the first context with `mix phx.gen.live`. Run it, click around.
3. Set up Tailwind v4 via the `tailwind` mix task.
4. Add Oban. Define one worker. Confirm it processes.
5. `fly launch` + `fly deploy`. Confirm `/live` heartbeat survives a deploy.
