Packages

Elixir Entities (Structs with MetaData and Noizu EntityReference Protocol support from noizu-labs-scaffolding/core built in.

Current section

Files

Jump to
Raw

AGENTS.md

# AGENTS.md — Working with `noizu_labs_entities`
Guide for AI coding agents contributing to, or building on top of, this library.
Read this first; pair it with `docs/PROJ-ARCH.md` and `docs/PROJ-LAYOUT.md` for deeper context.
## What This Library Is
An Elixir DSL that turns plain structs into metadata-rich **entities**: compile-time
declarations for fields, identifiers, persistence layers, JSON serialization formats,
and ACL rules. The DSL emits a `defstruct` plus a `__noizu_meta__/0` accessor, and
wires up `Noizu.EntityReference.Protocol` (ERP) and `Jason.Encoder`.
## Core Mental Model
- **Entity** — a struct + compile-time metadata (`use Noizu.Entity` + `def_entity do ... end`).
- **Repo** — a delegate module for CRUD (`use Noizu.Repo` + `def_repo()`). By convention
the repo is the entity module's parent namespace (`MyApp.Users.User``MyApp.Users`).
- **Persistence layer** — declared via `@persistence ecto_store(...)` / `mnesia_store(...)` /
`amnesia_store(...)` / `redis_store(...)` / `dummy_store(...)`. Multiple layers are allowed
and are iterated in order.
- **Store adapter** — each backend implements `EntityProtocol` (entity-level) and
`Entity.FieldProtocol` (field-level).
- **CRUD pipeline** — every operation is `__before_* → __do_* → __after_*`, all
`defoverridable`. Override in the repo module to add business logic.
- **JSON + ACL**`Jason.Encoder` delegates to `Noizu.Entity.Json.Protocol.prep/4`, which
applies `Noizu.Entity.ACL.Protocol.restrict/5` before building the output map.
## Minimal Entity + Repo
```elixir
defmodule MyApp.Users.User do
use Noizu.Entity
@vsn 1.0
@sref "user"
@persistence ecto_store(MyApp.Schema.User, MyApp.Repo)
def_entity do
id :uuid
field :name, nil, :string
field :email, nil, :string
field :time_stamp, nil, Noizu.Entity.TimeStamp
end
end
defmodule MyApp.Users do
use Noizu.Repo
def_repo()
end
```
## DSL Cheatsheet
| Construct | Meaning |
|-----------|---------|
| `id(type, opts)` | Identifier + type (`:integer`, `:uuid`, `:atom`, `:ref`, `:dual_ref`) |
| `field(name, default, type, opts)` | Field with optional ecto type / handler module |
| `transient do ... end` | Fields excluded from persistence |
| `pii(level) do ... end` | Mark fields as PII (`:low`, `:sensitive`, `:private`) |
| `@json ...` | Per-field JSON format config (supports named templates: `:default`, `:admin`, etc.) |
| `@restricted ...` / `@acl ...` | Field-level ACL rules (role, path, MFA) |
| `@persistence <store>(table, repo)` | Add a persistence layer |
| `@sref "slug"` | Short-reference prefix used by ERP for `ref:slug:<id>` strings |
| `@vsn x.y` | Entity version (written into struct) |
## Generator
```
mix nz.gen.entity my_entity store=ecto sref=my-entity field=biz:integer
```
Generates an entity module and matching ecto schema stubs. Output is a starting point —
expect to edit the generated files.
## When Adding a New Entity
1. Decide the `@sref` prefix and identifier type.
2. Pick persistence layers (start with one; add more only if needed).
3. Put test fixtures under `test/support/entities/` (see existing `foo.ex`, `bop.ex` for shape).
4. If introducing a new store, implement both `EntityProtocol` and `Entity.FieldProtocol` in
`lib/noizu_labs_entities/entity/store/<name>/` and mirror the ecto adapter layout.
## When Modifying the Core DSL
- DSL macros live in `lib/noizu_labs_entities/entity/macros/` and `.../repo/macros/`.
- Metadata accessors live in `lib/noizu_labs_entities/entity/meta/` — keep the `__noizu_meta__/0`
shape stable; changing it is a breaking change for every downstream entity.
- Identifier type handlers (`integer_identifier.ex`, `uuid_identifier.ex`, etc.) inject
`id/1`, `ref/1`, `sref/1`, `entity/2`, `stub/0,3`. New identifier types go here.
## Testing
```
mix test
mix credo
mix dialyzer
```
Fixtures in `test/support/entities/` exercise the DSL end-to-end — prefer extending those
over writing fresh mocks. Don't mock the DSL; compile real entities in `test/support/`.
## Conventions That Matter
- No runtime reflection — everything is resolved at compile time into `__noizu_meta__/0`.
- Don't bypass the CRUD pipeline. Business logic goes in repo `__before_*` / `__after_*` overrides.
- Restricted fields surface as the atom `:"*restricted*"` during JSON prep and are dropped by
`embed_field`. Don't treat them as data.
- Default JSON format is `:default`. Named templates (`:admin`, `:brief`, etc.) are selected
via the `{encoder, opts, user_settings}` tuple passed to Jason.
## Where To Read Next
- `docs/PROJ-ARCH.md` — full architecture, with diagrams
- `docs/PROJ-LAYOUT.md` — directory map
- `docs/arch/entity-dsl.md` — how `def_entity` compiles
- `docs/arch/persistence.md` — CRUD pipeline + store adapter contract
- `docs/arch/json-acl.md` — JSON templates and ACL integration
- `README.md` — user-facing overview (less agent-focused)