enum, the
allowed values are the real ones the census accepts.
The resource graph
| Relationship | Cardinality | Foreign key | Meaning |
|---|---|---|---|
| Family → Child | 1 — ∗ | child.family_id | A household holds one profile per kid. |
| Family → FamilyMember | 1 — ∗ | member.family_id | The guardians/parents on the account. |
| Child → ChildPolicy | 1 — ∗ | policy.child_id | A kid can have several policies (e.g. School Day, Weekend); one is active. |
| ChildPolicy → PolicyRule | 1 — ∗ | rule.policy_id | A policy is a set of rules drawn from the 123 OCSS categories. |
| ChildPolicy → EnforcementJob | 1 — ∗ | job.policy_id, job.child_id | Each push of a policy to platforms is a job. |
| EnforcementJob → EnforcementResult | 1 — ∗ | result.enforcement_job_id | One result row per connected platform the job fanned out to. |
| PolicyRule → Verdict | 1 — 1 (derived) | verdict.rule_ref | Each active rule compiles to one per-category decision in the signed profile. |
| Verdict → EnforcementReceipt | 1 — 1 (on confirm) | receipt.rule_ref | Confirming an applied verdict writes one signed receipt. |
Two planes, one graph. The green objects (Family → PolicyRule) and the blue objects
(EnforcementJob, EnforcementResult) live in the control/product plane —
normal REST resources you read and write with a
phosra_ key. The violet Verdict and
EnforcementReceipt live on the data plane: they are compiled
into a signed profile and evaluated locally, in-process by the gatekeeper — there is no
hosted POST /check. The rule_ref field is the thread that stitches a product-plane
PolicyRule to its data-plane Verdict and back to a receipt.Objects
Family — the household root
Family — the household root
The top of the graph. Everything else hangs off a family, directly or transitively.
Reference: Create a family ·
List families ·
concept → Families
| Field | Type | Notes |
|---|---|---|
id | uuid | Primary key. |
name | string | Display name of the household. |
created_at | date-time | RFC 3339. |
Family
FamilyMember — a guardian on the account
FamilyMember — a guardian on the account
The people who can manage a family. Distinct from
Reference: Add a member ·
List members
Child.| Field | Type | Notes |
|---|---|---|
id | uuid | Primary key. |
family_id | uuid | Foreign key → Family. |
user_id | uuid | The underlying user. |
role | enum | owner · parent · guardian. |
joined_at | date-time | RFC 3339. |
FamilyMember
Child — a kid's profile
Child — a kid's profile
A profile within a family, keyed by birth date. Phosra derives the age group (and thus the
age-appropriate rule defaults) from
Reference: Add a child ·
Get a child ·
Age ratings ·
concept → Children & Age Groups
birth_date.| Field | Type | Notes |
|---|---|---|
id | uuid | Primary key. |
family_id | uuid | Foreign key → Family. |
name | string | Display name. |
birth_date | date | YYYY-MM-DD. Drives age-group defaults and the ≥13 write-notice branch. |
avatar_url | string | Optional profile image. |
created_at | date-time | RFC 3339. |
Child
ChildPolicy — a named set of rules
ChildPolicy — a named set of rules
The container a child’s rules live in. A child may own several; policies carry a lifecycle
Reference: Create a policy ·
Generate rules from age ·
Activate ·
Pause ·
concept → Policies & Rules
status and a priority for ordering.| Field | Type | Notes |
|---|---|---|
id | uuid | Primary key. |
child_id | uuid | Foreign key → Child. |
name | string | Display name (e.g. School Day). |
status | enum | draft · active · paused. Only active policies enforce. |
priority | integer | Ordering weight when multiple policies apply; higher wins. |
version | integer | Bumped on every change. |
created_at | date-time | RFC 3339. |
ChildPolicy
PolicyRule — one category decision
PolicyRule — one category decision
A single rule inside a policy: which OCSS category, whether it’s on, and its category-specific
config. There are 123 categories — see the Rule Categories reference.
Reference: List policy rules ·
Bulk upsert rules ·
Update a rule
| Field | Type | Notes |
|---|---|---|
id | uuid | Primary key. |
policy_id | uuid | Foreign key → ChildPolicy. |
category | enum | One of the 123 OCSS rule categories. |
enabled | boolean | Whether this rule is active. |
config | object | Category-specific configuration. |
created_at | date-time | RFC 3339. |
PolicyRule
EnforcementJob — one push to platforms
EnforcementJob — one push to platforms
Created when you enforce a policy. It fans out to every connected platform in parallel.
Reference: Trigger enforcement ·
List jobs ·
Job results ·
concept → Enforcement
| Field | Type | Notes |
|---|---|---|
id | uuid | Primary key. |
child_id | uuid | Foreign key → Child. |
policy_id | uuid | Foreign key → ChildPolicy. |
trigger_type | enum | manual · auto · webhook. |
status | enum | pending · running · completed · failed · partial. |
started_at | date-time | null | Set when the job starts running. |
completed_at | date-time | null | Set when it finishes. |
created_at | date-time | RFC 3339. |
EnforcementJob
EnforcementResult — per-platform outcome
EnforcementResult — per-platform outcome
One row per connected platform in a job. This is what you poll to verify enforcement —
there is no push webhook on job completion.
Reference: Get job results ·
Retry a job
| Field | Type | Notes |
|---|---|---|
id | uuid | Primary key. |
enforcement_job_id | uuid | Foreign key → EnforcementJob. |
compliance_link_id | uuid | Foreign key → the compliance link this result is attributed to. |
platform_id | string | The target platform (e.g. nextdns). |
status | enum | pending · running · completed · failed · partial. |
rules_applied | integer | Rules successfully applied. |
rules_skipped | integer | Rules the platform can’t express (see Platforms). |
rules_failed | integer | Rules that errored. |
error_message | string | null | Detail on failure; null on success. |
details | object | Free-form provider response payload captured for debugging. |
started_at | date-time | null | RFC 3339 timestamp of when the result started running. |
completed_at | date-time | null | RFC 3339 timestamp of when it finished. |
EnforcementResult
Verdict — the gatekeeper's local decision
Verdict — the gatekeeper's local decision
On the data plane, each active rule compiles into a
Reference: Fetch profile ·
Platform integration · glossary → Verdict
CategoryEntry inside the signed
§8.3.6 enforcement profile. The @phosra/gatekeeper SDK reads it with gk.isAllowed({ category })
— entirely locally, zero network — and returns a Verdict.| Field | Type | Notes |
|---|---|---|
category | slug | OCSS rule category. |
decision | enum | allow · warn · block. |
fail_mode | enum | open · closed. closed = must block if the profile is missing/expired. |
rule_ref | string | Per-child opaque handle; echo it back to confirm(). null when fail-closed. |
rule_slug | string | Registry slug, for logging. |
Verdict (CategoryEntry)
One field, two spellings. The wire/profile names this
fail_mode with values
open/closed; the gatekeeper SDK surfaces the same signal as failMode with allow/block.
fail_mode:"closed" ⇔ failMode:"block". See Platform integration.EnforcementReceipt — the signed apply attestation
EnforcementReceipt — the signed apply attestation
After enforcing (or refusing) a verdict, the platform calls
Reference: Submit confirmation ·
glossary → Receipt
verdict.confirm(...), which
signs and POSTs a §8.3.8 enforcement_result receipt. It is identity-free by construction
— no child ref, device id, or user id. The inner body is exactly five fields.| Field | Type | Notes |
|---|---|---|
envelope_ref | string | Idempotency key of the carried envelope. |
rule_ref | string | The same rule_ref from the Verdict — ties the receipt to the rule. |
enforcement_state | enum | applied · degraded · refused. |
applied_at | date-time | RFC 3339. |
method_class | string | Mechanism of enforcement (e.g. dns_block, platform_gate). Non-empty when applied. |
EnforcementResultBody (signed inner body)
Lifecycle & state
Three objects in the graph are state machines. Knowing the transitions saves you a class of “why isn’t this enforcing?” bugs.ChildPolicy — draft → active → paused
draft
Created but not enforcing. Build up rules here.
POST /policies starts a policy in
draft unless you activate it.active
The only status that enforces.
POST /policies/{id}/activate. When a child has
multiple active policies, priority (higher wins) breaks the tie.EnforcementJob — pending → running → completed | failed | partial
partial
Some platforms applied, some didn’t — inspect
rules_skipped / rules_failed per result.
Common when a platform can’t express a category (manual_attested; see Platforms).failed
The job as a whole failed. Retry it.
Verdict standing — allow · warn · block (fail-closed)
A verdict is not a stored row that transitions; it is recomputed locally on every
isAllowed() call from the current signed profile. Its standing is one of allow, warn,
or block. If the cached profile is missing or expired, a fail_mode: closed category
resolves to block with rule_ref: null — enforcement never silently passes.
Prove the graph is live
The product-plane objects are served today. No key gives you a401 (not a 404), which is
the correct answer — the surface exists:
The product-plane resources above require a
phosra_ key (mint one in the
Developer Console); see Authentication and
the Quickstart to create your first family → child → policy → rule → enforcement
job end to end. There is no public unauthenticated sandbox for the product plane.Where to go next
Quickstart →
Create the whole graph in one
POST /setup/quick call, then enforce it.Architecture →
Why the product plane and the enforcement data plane are kept separate.
Policies & Rules →
How the 123 OCSS categories become a policy.
Enforcement →
Jobs, per-platform results, and the poll-don’t-webhook contract.