Skip to content

Commit 8b47bc5

Browse files
committed
#51 part 4 — Provider domain orientation page
* documentation/domains/provider.md — short lift-the-lid page that names the Provider primitives used by Access (Specification, Instance, Characteristic, Pool, Assignment, Relationship, Feature, Place, Party, state machine), explains the TMF JSON encoder, and points at diffo's own livebooks for the deep dive * mix.exs — registered as an extra
1 parent 90d4374 commit 8b47bc5

2 files changed

Lines changed: 77 additions & 0 deletions

File tree

documentation/domains/provider.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<!--
2+
SPDX-FileCopyrightText: 2025 diffo_example contributors <https://github.com/diffo-dev/diffo_example/graphs.contributors>
3+
4+
SPDX-License-Identifier: MIT
5+
-->
6+
7+
# The Provider Domain
8+
9+
The Provider domain is **diffo's own domain** — the base resources and DSL on top of which Access, NBN, and any other domain you build are written. You've used every Provider primitive in the [Access scenario](access.md) without naming them; this page names what you've been using.
10+
11+
Provider isn't yours to extend. You don't `define` actions on it or relate to its resources directly. You build *with* it.
12+
13+
## What Provider gives you
14+
15+
Every `Instance` resource in your domain (`Shelf`, `Card`, `DslAccess`, `NbnEthernet` …) is a `BaseInstance`-derived Ash resource. `BaseInstance` is a Provider fragment that brings in a complete TMF Service/Resource surface — id, href, lifecycle state, places, parties, characteristics, features, relationships, the JSON encoder, the graph layer. Mix it in and a small DSL on top is enough to model your domain.
16+
17+
The primitives, in the order you met them in the Access scenario:
18+
19+
### Specification
20+
21+
Every `Instance` declares a `Specification` — the *type* of thing it is (`shelf`, `dslAccess`, `nbnEthernet`). Specifications carry a stable id, a name, a category, a description, and the TMF kind (`:serviceSpecification` or `:resourceSpecification`). They show up in every TMF JSON payload as `serviceSpecification` / `resourceSpecification`. You declared one with `specification do … end` inside your `provider do` block.
22+
23+
### Instance
24+
25+
A concrete thing of a specification — a particular `shelf` named "QDONC-0001" with a unique id. You created instances with `:build` actions (e.g. `Access.build_shelf/1`). Each instance is a node in the graph.
26+
27+
### Characteristic
28+
29+
Typed value slots on an instance — the actual data the consumer cares about. You declared them with `characteristics do characteristic :foo, FooCharacteristic end`. Each is its own little Ash resource (a `BaseCharacteristic`-derived module with attributes and a `:value` calculation), and the Provider encoder lifts it inline as `{name: foo, value: {…}}` in the instance's `serviceCharacteristic` / `resourceCharacteristic` array.
30+
31+
There's a sister kind — **metrics characteristics** — for local, non-inheritable aggregates (e.g. `CvcMetrics.avcs_count`). Same shape; the `:value` calc just reads the graph instead of stored attributes.
32+
33+
### Pool
34+
35+
A range of allocatable values declared on an instance — `:slots`, `:ports`, `:cvlans`, `:pairs`. You declared one with `pools do pool :slots, :slot end`: the first atom names the pool (the AssignableCharacteristic), the second names the *thing* being allocated. Pools surface in JSON as their own characteristic record showing first/last/free/algorithm.
36+
37+
### Assignment
38+
39+
A consumer takes a value from another instance's pool — Card takes a `:slot` from Shelf, Path takes a `:port` from Card, Path takes a `:pair` from Cable. Each assignment is an `AssignmentRelationship` edge with the value and an alias. The **alias is the consumer's name for the upstream related resource it's part of** — Card sets `alias: :shelf` because it's part of a Shelf. That alias is the key for inheritance walks.
40+
41+
### Relationship
42+
43+
Arbitrary edges between instances — `:contains`, `:owns`, `:isPartOf`. You created them with `:relate` actions taking `Relationship` structs. Provider stores these as either `Provider.Relationship` (mutable characteristics) or `DefinedSimpleRelationship` (one frozen characteristic at creation, used by the Assigner). They surface as `resourceRelationship` / `serviceRelationship` entries in JSON.
44+
45+
### Feature
46+
47+
Optional capabilities on an instance (`:dynamic_line_management` on `DslAccess`). Declared with `features do feature :name, is_enabled?: bool end`, optionally carrying their own characteristics.
48+
49+
### Place and Party
50+
51+
Where and who. Declared with `places do … end` and `parties do … end` blocks on an instance, populated by passing `%Place{id, role}` and `%Party{id, role}` structs to build/qualify actions. Surface as TMF `place` and `relatedParty` references.
52+
53+
### State machine
54+
55+
Services and resources both carry lifecycle state. You declared transitions with `state_machine do transitions do … end end`; each action that should transition uses `change transition_state(:new_state)` or `change set_attribute(:resource_state, …)`. The current state surfaces in JSON as `state` (service) or `lifecycleState` (resource).
56+
57+
## What the encoder does
58+
59+
You never wrote serialiser code. Once your instance has its specification, characteristics, features, places, parties, relationships and lifecycle state, the Provider encoder maps the whole graph into TMF-compliant JSON every time you call `Jason.encode!(instance)`. The order, naming, and nesting conventions all come from the Provider's `jason do` configurations. Customise per resource if you need to; otherwise just declare the model and the JSON shape follows.
60+
61+
## Bringing context up — the inheritance calcs
62+
63+
Provider doesn't (yet) ship the inheritance calculations you used in Access — `Card.shelf`, `Path.card`, `Path.shelf`. Those live in this example codebase as [InheritedCharacteristicViaAssignment](../../lib/diffo_example/calculations/inherited_characteristic_via_assignment.ex) and [InheritedCharacteristicViaRelationship](../../lib/diffo_example/calculations/inherited_characteristic_via_relationship.ex). They're small (one Ash calc each) and worth yarning upstream as Provider primitives — sister calcs to the existing `InheritedPlace` and `InheritedParty` that Provider already ships.
64+
65+
## Going deeper into Provider
66+
67+
This page is an orientation. For a deeper look at Provider itself:
68+
69+
- The [Diffo livebook](https://livebook.dev/run?url=https%3A%2F%2Fgithub.com%2Fdiffo-dev%2Fdiffo%2Fblob%2Fdev%2Fdiffo.livemd) — walks the Provider concepts directly (Specification, Instance, Feature, Characteristic, Party, Place, Relationship).
70+
- The [Provider Instance Extension livebook](https://livebook.dev/run?url=https%3A%2F%2Fgithub.com%2Fdiffo-dev%2Fdiffo%2Fblob%2Fdev%2Fdocumentation%2Fhow_to%2Fuse_diffo_provider_instance_extension.livemd) — walks the DSL you used to declare the Access resources.
71+
72+
## What next?
73+
74+
You've seen the primitives in action ([Access](access.md)) and you've seen what they are (here). The next move is to bring your own domain — even a sketch is enough — and model it the way Access does. Start with one specification, declare its characteristics, decide whether anything pools, sketch a build action, and watch the JSON come out the other side.
75+
76+
When you're ready for a richer example, the [NBN domain](nbn.md) revisits the same primitives at scale: multi-tenancy, a longer delivery chain, and the cross-resource inheritance that Access only hinted at.

mix.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ defmodule DiffoExample.MixProject do
6363
"README.md": [title: "Guide"],
6464
"documentation/domains/access.md": [title: "The Access Domain"],
6565
"documentation/domains/diffo_example_access.livemd": [title: "Access Livebook"],
66+
"documentation/domains/provider.md": [title: "The Provider Domain"],
6667
"documentation/domains/nbn.md": [title: "The NBN Domain"],
6768
"documentation/domains/diffo_example_nbn.livemd": [title: "NBN Livebook"],
6869
"documentation/how_to/setup_mcp.md": [title: "Setup the MCP server"],

0 commit comments

Comments
 (0)