# `PhoenixKitCatalogue.Import.Pro100TemplateLoader`
[🔗](https://github.com/BeamLabEU/phoenix_kit_catalogue/blob/v0.19.1/lib/phoenix_kit_catalogue/import/pro100_template_loader.ex#L1)

Applies a `Pro100TemplatePlan` to the catalogue.

Safe to run twice. Identity is resolved at every level, because the one
question nobody can answer — whether PRO100 regenerates its guids on each
export — decides whether a second run updates or duplicates:

    folder      by name
    catalogue   by data["pro100"]["template_guid"], else by (folder, name)
    category    by (catalogue, parent, name)
    item        by data["pro100"]["template_guid"], else by (category, name)
                and only when that item carries no guid of its own

The last condition is what stops a renamed line from overwriting an unrelated
item that happens to share its new name: if the candidate already has a guid,
it belongs to a different line, and the incoming row is reported instead.

Nothing is ever deleted. Items in a catalogue with no line in the file are
reported as `:absent`, which is the only signal that a position was dropped
upstream.

`dry_run: true` performs every lookup and decision and writes nothing.

Every write inside the transaction is muted (`broadcast: false`); once it
has committed the loader emits one `:folder` event if it created the
folder and one `:catalogue` roll-up per catalogue it touched — the same
discipline as `Import.Executor`, so open index/detail pages refresh once,
after the data is really there, instead of on every pre-commit row.

# `report`

```elixir
@type report() :: %{
  folder: :created | :reused,
  catalogues: [map()],
  rules: [map()],
  absent: [map()],
  reported: [map()],
  stats: map()
}
```

# `apply_plan`

```elixir
@spec apply_plan(
  map(),
  keyword()
) :: {:ok, report()} | {:error, term()}
```

---

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