# `MailglassAdmin.Controllers.Assets`
[🔗](https://github.com/szTheory/mailglass/blob/v1.0.0/lib/mailglass_admin/controllers/assets.ex#L1)

Compile-time asset server for the mailglass_admin preview dashboard.

Embeds `priv/static/app.css`, the concatenated Phoenix + Phoenix
LiveView JS bundles, the logo SVG, and the font woff2 subsets into
module attributes at compile time via `@external_resource` +
`File.read!/1`. Request-time cost is a single `Plug.Conn.send_resp/3`
from the module-attribute bytes — no filesystem I/O, no Plug.Static
in the chain.

## Caching

Every response sets:

    cache-control: public, max-age=31536000, immutable

MD5 hashes of the bundles are exposed via `css_hash/0` and `js_hash/0`
so layouts can emit cache-busting URLs like `css-<hash>.css`. New
builds produce new hashes → new URLs → bypass the immutable cache.

## Phoenix + LiveView JS not charged to our tarball

`phoenix.js` and `phoenix_live_view.js` are read from their host
packages' `priv/static/` directories via `Application.app_dir/2`.
Those bytes are NOT in mailglass_admin's Hex tarball — adopters
already pay for them via their own `:phoenix` + `:phoenix_live_view`
deps. The CONTEXT D-23 2 MB tarball gate only measures files we ship.

## Font allowlist

`call(conn, :font)` hits the six-member `@allowed_fonts` guard before
constructing a filesystem path. A path traversal attempt like
`GET /fonts/..%2F..%2Fetc%2Fpasswd` fails the guard, falls through to
`_ -> :error`, and returns 404 with an empty body. The 2-weights-per-
family lock from 05-UI-SPEC lines 71-79 means the allowlist is small
and stable; adding a seventh weight requires updating BOTH the
`@allowed_fonts` list AND the brand test fixture.

Boundary classification: submodule auto-classifies into the
`MailglassAdmin` root boundary declared in `lib/mailglass_admin.ex`;
`classify_to:` is reserved for mix tasks and protocol implementations
and is not used here.

# `call`

# `css_hash`

```elixir
@spec css_hash() :: String.t()
```

MD5 hash (lowercase hex) of the embedded `priv/static/app.css` bytes.

Used by `MailglassAdmin.Layouts.css_url/0` to build cache-busting URLs
like `css-<hash>.css`. The macro's `get "/css-:md5", ...` route
captures the hash in `conn.path_params["md5"]` but the handler does
not currently validate it — browsers never emit stale URLs because
the immutable cache drops when the rendered document URL changes.

# `init`

# `js_hash`

```elixir
@spec js_hash() :: String.t()
```

MD5 hash (lowercase hex) of the concatenated Phoenix + LiveView JS.

Same cache-busting role as `css_hash/0`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
