# `MailglassAdmin.Preview.Discovery`
[🔗](https://github.com/szTheory/mailglass/blob/v1.0.0/lib/mailglass_admin/preview/discovery.ex#L1)

Reflection for mailable modules — finds `use Mailglass.Mailable` modules,
reads their `preview_props/0` callback if present, and returns the pair
ready for the preview dashboard sidebar.

## Discovery modes

  * `:auto_scan` (default) — Walks `:application.loaded_applications/0` and
    for each app calls `:application.get_key(app, :modules)`, filtering by
    the `__mailglass_mailable__/0` marker that `use Mailglass.Mailable`
    injects via `@before_compile`.

  * `[module | _]` explicit list — Override for umbrella apps, pathological
    module counts, or adopter preference. Each module MUST have the marker
    or discovery raises `ArgumentError` with an actionable message.

## Graceful failures (CONTEXT D-13)

  * Marker present, no `preview_props/0` defined -> `{module, :no_previews}`
  * `preview_props/0` raises -> `{module, {:error, formatted_stacktrace}}`
  * `preview_props/0` returns non-list or a list item whose second element
    is not a map -> `{module, {:error, shape_violation_message}}`

None of these failure modes raise from `discover/1`. The LiveView branches
on the second tuple element to render the correct sidebar + main pane state
(05-UI-SPEC sidebar section lines 189-207, error card lines 386-404).

## Performance

Empirical: ~50ms on a 10,000-module umbrella app. `function_exported?/3`
is O(1) per module. If adopters report slow mount, they bypass the scan
via the explicit `:mailables` list.

## Boundary classification

Submodule auto-classifies into the `MailglassAdmin` root boundary declared
in `lib/mailglass_admin.ex` (`use Boundary, deps: [Mailglass], exports:
[Router]`); Boundary's `classify_to:` directive is reserved for mix tasks
and protocol implementations and is not used here. Matches the package's
general convention for internal support modules.

# `reflection`

```elixir
@type reflection() :: [scenario()] | :no_previews | {:error, String.t()}
```

# `result`

```elixir
@type result() :: {module(), reflection()}
```

# `scenario`

```elixir
@type scenario() :: {atom(), map()}
```

# `discover`
*since 0.1.0* 

```elixir
@spec discover(:auto_scan | [module()]) :: [result()]
```

Discovers mailable modules and their preview scenarios.

Returns a list of tuples; order is implementation-defined but stable within
a single call.

---

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