# AccrueAdmin Integration Guide
`accrue_admin` mounts a package-scoped LiveView billing UI inside a host Phoenix app. The package owns its own router macro, private static bundle, and non-prod inspection tools.
Start with the package quickstart in [`README.md`](../README.md), then return here for the host wiring and release checks. Published `accrue_admin` releases depend on the matching `accrue` minor (see Hex for the current `~>` range), while monorepo development keeps the local sibling dependency shape by default.
## UI stack and polish direction
- **Build:** Tailwind CSS v3 compiles [`assets/css/app.css`](../assets/css/app.css) into `priv/static/accrue_admin.css` via `mix accrue_admin.assets.build`. [`assets/tailwind.config.js`](../assets/tailwind.config.js) scans `lib/**/*.{ex,heex}`; [`assets/tailwind_preset.js`](../assets/tailwind_preset.js) maps CSS variables to Tailwind theme colors so utilities stay on the same tokens as `ax-*` rules.
- **Authoring:** Prefer **`ax-*` classes** in `app.css` / `theme.css` for layout, surfaces, and reusable blocks. Add **Tailwind utilities in HEEx** when they reduce duplication (spacing, responsive tweaks) without fighting the preset.
- **Principles:** least surprise for billing operators; clear hierarchy (context → KPIs → primary work area); visible focus states; explicit empty, loading, and error states on lists; microcopy that matches host and Stripe language (subscription, invoice, webhook) unless the screen is intentionally abstracted.
- **Motion:** light CSS transitions on shells, drawers, and modals; honor `prefers-reduced-motion`; reach for LiveView `JS` only when CSS cannot carry the interaction.
- **Responsive:** keep the mounted shell usable on small viewports first; avoid wide horizontal scroll for primary tables unless unavoidable—prefer column discipline and secondary detail surfaces.
## Host Setup
Add the package to your router and mount it where operators expect billing controls:
```elixir
defmodule MyAppWeb.Router do
use MyAppWeb, :router
import AccrueAdmin.Router
scope "/" do
pipe_through [:browser]
accrue_admin "/billing",
session_keys: [:user_token],
on_mount: [{MyAppWeb.UserAuth, :mount_current_user}]
end
end
```
`accrue_admin "/billing"` creates:
- hashed package asset routes under `/billing/assets/*`
- the main billing LiveView routes under `/billing/*`
- compile-gated dev routes under `/billing/dev/*` only outside `MIX_ENV=prod`
## Branding
The package reads its brand chrome from `Accrue.Config.branding/0` through the package branding plug. Configure the host app's billing identity once and the admin shell inherits it:
```elixir
config :accrue,
branding: [
business_name: "Acme Corp",
from_email: "billing@acme.test",
support_email: "support@acme.test",
logo_url: "https://example.test/logo.svg",
accent_color: "#5E9E84"
]
```
## Auth Expectations
The mount macro wires the package auth hook into the LiveSession by default.
`Accrue.Auth` must be able to resolve the current operator from the forwarded
session data, and `session_keys: [:user_token]` is the supported host boundary
for the standard Phoenix auth flow.
The host app remains responsible for browser-session setup before the admin
routes mount. Keep `accrue_admin "/billing"` inside the authenticated browser
scope so `/billing` inherits the same auth boundary as the rest of the app.
## Private Asset Bundle
The package serves its own committed bundle from `priv/static/`. The JavaScript bundle must be **valid ES module output** (not a placeholder): it includes Phoenix + LiveView so admin `phx-click` interactions work in the browser. Rebuild it locally with:
```bash
cd accrue_admin
mix accrue_admin.assets.build
```
That task only touches:
- `priv/static/accrue_admin.css`
- `priv/static/accrue_admin.js`
No host Tailwind config edits or host JavaScript bootstrap changes are required.
## Release Verification
CI and local publish dry runs must force the Hex-safe sibling dependency shape:
```bash
cd accrue_admin
export ACCRUE_ADMIN_HEX_RELEASE=1
```
Use this release gate before shipping or validating publish automation:
```bash
mix format --check-formatted
mix compile --warnings-as-errors
mix test --warnings-as-errors
mix credo --strict
mix docs --warnings-as-errors
mix dialyzer --format github
mix hex.audit
mix hex.build
mix hex.publish --dry-run
```
## Browser UAT
Phase 7 operator verification is automated with Playwright specs under `e2e/`. The suite starts a local test Phoenix endpoint, seeds deterministic billing data, and runs the dashboard, webhook replay, bulk DLQ replay, and step-up refund flows in desktop and mobile Chromium profiles.
Run it locally with:
```bash
cd accrue_admin
npm ci
npx playwright install chromium
npm run e2e
```
CI runs the same suite in `.github/workflows/accrue_admin_browser.yml` with Postgres and uploads Playwright traces on failure.
To replay the GitHub Actions job locally with `act`:
```bash
act workflow_dispatch \
-W .github/workflows/accrue_admin_browser.yml \
-j browser-uat
```
## Dev-Only Surfaces
Outside prod builds, a floating dev toolbar links to:
- `/billing/dev/clock`
- `/billing/dev/email-preview`
- `/billing/dev/webhook-fixtures`
- `/billing/dev/components`
- `/billing/dev/fake-inspect`
Those pages are hidden entirely from prod builds and also refuse to expose tooling unless the configured processor is `Accrue.Processor.Fake`.
## Prod Compile Guarantee
`accrue_admin` enforces the dev surface in two layers:
- compile time: the dev LiveViews, toolbar component, and `/billing/dev/*` routes are only defined when `Mix.env() != :prod`
- runtime: even in `:dev` and `:test`, the pages render only when `Application.get_env(:accrue, :processor)` is `Accrue.Processor.Fake`
Use `MIX_ENV=prod mix compile` in `accrue_admin/` as the smoke check that the package ships without any dev-only admin tooling in production builds.