This commit is contained in:
2026-06-05 10:28:28 -04:00
parent 0f95a1ca47
commit c2bd3a9492

View File

@@ -1,18 +1,20 @@
# Addon Skeleton Specification # Addon Skeleton Specification
**Project:** kane-diagnostics **Project:** kane-diagnostics
**Version:** 1.0 **Version:** 2.0
**Prerequisite reading:** README.md, DSC-development-map.md, HANDOFF.md, CODING-GUIDELINES.md **Prerequisite reading:** README.md, DSC-development-map.md, HANDOFF.md, CODING-GUIDELINES.md, INSTITUTIONAL-RELATIONSHIPS.md, FOR-PARTICIPANTS-AND-PROFESSIONALS.md
--- ---
## Purpose ## The Standard
This document specifies the three addon skeletons to be created as the baseline for the kane-diagnostics project. It is a handoff document — the incoming Assistant reads this, reads the repos, and then works with the operator to build each skeleton before any functional code is written. This document defines the skeleton standard for all Kane Diagnostics Hubzilla addons — present and future. The three addons described below are the first implementations of the standard, not the definition of it. Any addon added to this project follows the same skeleton: same file layout, same Widget structure, same PDL pattern, same config template fields, same spool contract discipline, same coding constraints.
A skeleton is not a working addon. It is the correct structure, the correct conventions, the correct file layout, and the correct configuration — with placeholder content where the logic will go. A skeleton that compiles and loads without errors is a skeleton that is ready to develop. The standard changes only by deliberate revision of this document. A revised document increments the version number and is committed to the repo. The previous version is never deleted — it remains as the historical record of what was built under it.
**Nothing in this document should be built without the operator's input and confirmation at each step.** If you are reading this document and the repo contains addon code, read the code before reading this document any further. The code is the ground truth. This document describes what the code should look like. When they conflict, ask the operator before proceeding.
Nothing in this document should be built without the operator's input and confirmation at each step.
--- ---
@@ -36,7 +38,7 @@ A skeleton is not a working addon. It is the correct structure, the correct conv
**What it does not do:** **What it does not do:**
- It does not present scenarios - It does not present scenarios
- It does not present case law - It does not present case law
- It does not manage attorney listings - It does not manage the institutional directory
--- ---
@@ -59,7 +61,7 @@ A skeleton is not a working addon. It is the correct structure, the correct conv
**What it does not do:** **What it does not do:**
- It does not present scenarios - It does not present scenarios
- It does not manage the Vital Signs record - It does not manage the Vital Signs record
- It does not manage attorney listings - It does not manage the institutional directory
--- ---
@@ -80,9 +82,9 @@ A skeleton is not a working addon. It is the correct structure, the correct conv
**What it does not do:** **What it does not do:**
- It does not present Vital Signs - It does not present Vital Signs
- It does not present case law - It does not present case law
- It does not manage attorney listings - It does not manage the institutional directory
**Relationship to pilot:** **Relationship to pilot:**
The pilot `ds01` addon in `caselaw-document-access` is the functional prototype for this addon. The new `scn01` is a clean rebuild on the complete foundation — not a port of the pilot code. The pilot is reference, not source. The pilot `ds01` addon in `caselaw-document-access` is the functional prototype for this addon. The new `scn01` is a clean rebuild on the complete foundation — not a port of the pilot code. The pilot is reference, not source.
--- ---
@@ -93,20 +95,21 @@ Each addon skeleton follows this structure. Files marked `[placeholder]` contain
``` ```
hubzilla/addon/{addon}/ hubzilla/addon/{addon}/
{addon}.php — main addon file: hooks, load/unload, content routing {addon}.php — main addon file: hooks, load/unload, content routing
{addon}.apd — app descriptor {addon}.apd — app descriptor
mod_{addon}.pdl — PDL layout: aside, content, right_aside mod_{addon}.pdl — PDL layout: aside, content, right_aside
config.json.template — all config fields documented, no secrets config.json.template — all config fields documented, no secrets
listings.json.template — institutional directory schema, Core slots pre-populated
Widget/ Widget/
{Addon}.php — sidebar widget: navigation, resources, status {Addon}.php — sidebar widget: the institutional directory
view/ view/
css/ css/
{addon}.css — all presentation styles, no inline styles anywhere {addon}.css — all presentation styles, no inline styles anywhere
js/ js/
{addon}.js — all behavior, no inline scripts anywhere {addon}.js — all behavior, no inline scripts anywhere
contracts/ contracts/
spool-v1.json — the spool envelope contract this addon produces spool-v1.json — the spool envelope contract this addon produces
README.md — one paragraph: what this addon does and does not do README.md — one paragraph: what this addon does and does not do
``` ```
--- ---
@@ -125,10 +128,11 @@ Must contain, in order:
6. **Access wall**`{addon}_access_wall()` — plain language, SASE link 6. **Access wall**`{addon}_access_wall()` — plain language, SASE link
7. **Content router**`{addon}_content()` — loads CSS/JS, checks access, routes by path and method 7. **Content router**`{addon}_content()` — loads CSS/JS, checks access, routes by path and method
8. **Config loader**`{addon}_load_config()` 8. **Config loader**`{addon}_load_config()`
9. **CSRF token and verify** — standard pattern 9. **Listings loader**`{addon}_load_listings()` — reads `listings.json`, returns structured array; fails visibly if file is missing or malformed
10. **Placeholder content functions** — one per route, each returning a `// TODO` string with a plain description of what goes here 10. **CSRF token and verify** — standard pattern
11. **Placeholder content functions** — one per route, each returning a `// TODO` string with a plain description of what goes here
No functional logic in the skeleton. No database calls. No file I/O. No orchestrator calls. Those come after the skeleton is confirmed. No functional logic in the skeleton. No database calls. No file I/O beyond config and listings loaders. No orchestrator calls. Those come after the skeleton is confirmed.
### {addon}.apd ### {addon}.apd
@@ -161,28 +165,124 @@ $content
[/region] [/region]
``` ```
The right_aside is permanent and identical across all addons. It is never modified.
### config.json.template ### config.json.template
Every field the addon reads from `config.json` must appear here with a descriptive comment and a placeholder value. No field should ever be read from `config.json` that does not first appear in `config.json.template`. Every field the addon reads from `config.json` must appear here with a descriptive comment and a placeholder value. No field should ever be read from `config.json` that does not first appear in `config.json.template`.
```json ```json
{ {
"_note": "Copy to config.json. Do not commit config.json — it contains secrets.", "_note": "Copy to config.json. Do not commit config.json — it contains secrets and installation-specific values.",
"receiver_url": "REPLACE — orchestrator receiver endpoint", "receiver_url": "REPLACE — orchestrator receiver endpoint",
"node_token": "REPLACE — shared secret for node-to-orchestrator auth", "node_token": "REPLACE — shared secret for node-to-orchestrator auth",
"corpus_builder_group_id": 0 "corpus_builder_group_id": 0,
"listings_file": "REPLACE — absolute path to listings.json on the host"
}
```
### listings.json.template
The institutional directory schema. This file documents the structure. The live `listings.json` on the host is operator-managed and never committed to the repo.
The Core tier always contains exactly three slots. They are permanent. They render whether populated or not. An unpopulated slot displays its role description and invitation text. No entity name or mark appears until the operator records written approval and populates the entry.
```json
{
"_note": "Copy to listings.json on the host. Do not commit listings.json — it contains entity names and approval records that are operator-managed.",
"_version": "1.0",
"core": [
{
"slot": "taxonomy-authority",
"role": "Taxonomy Authority",
"description": "The institutional source of the case law categories this diagnostic record is organized by.",
"status": "pending",
"name": null,
"mark_url": null,
"url": null,
"approved_date": null
},
{
"slot": "methodology-certifier",
"role": "Methodology Certifier",
"description": "The law firm whose professional association with this project certifies the diagnostic record meets a standard the legal community can use.",
"status": "pending",
"name": null,
"mark_url": null,
"url": null,
"approved_date": null
},
{
"slot": "peer-operator",
"role": "Peer Operator",
"description": "The cooperating Civic Infrastructure host who can independently verify, support, and if necessary continue this diagnostic record.",
"status": "pending",
"name": null,
"mark_url": null,
"url": null,
"approved_date": null
}
],
"tier1": [],
"tier2": [],
"other": []
}
```
Entry schema for Tier-I, Tier-II, and Other:
```json
{
"id": "REPLACE — unique identifier, e.g. t1-001",
"role": "REPLACE — e.g. Mediator, Attorney, Civic Organization",
"name": "REPLACE — display name",
"description": "REPLACE — one sentence describing this entity's practice",
"url": "REPLACE — public URL",
"qualifying_case": "REPLACE — Tier-II attorneys only: case citation from public record",
"listed_date": "REPLACE — ISO date of listing",
"approved_date": "REPLACE — ISO date of written approval"
} }
``` ```
### Widget/{Addon}.php ### Widget/{Addon}.php
The Widget renders the institutional directory in the left aside. This is its only job.
Must contain: Must contain:
- Correct namespace: `namespace Zotlabs\Widget;` - Correct namespace: `namespace Zotlabs\Widget;`
- Class name matching filename exactly: `class {Addon}` - Class name matching filename exactly: `class {Addon}`
- `widget($arr)` method returning sidebar HTML - `widget($arr)` method returning sidebar HTML
- `current_step()` or `current_route()` for navigation state - `render_directory()` — loads listings via `{addon}_load_listings()`, renders the four-tab structure
- Sidebar navigation showing current location - `render_core_tab()` — always renders all three Core slots; pending slots show role description and invitation text
- Resources panel using `data-{addon}-resource` attributes — no navigation links - `render_tier_tab($entries, $placeholder)` — renders entries if any exist; renders placeholder text if none
- `h($value)` — local HTML escape method
The Widget does not render navigation. It does not render a steps indicator. It does not render resource panels. Those patterns belong to the pilot and do not transfer.
#### Tab structure
Four horizontal Bootstrap nav-tabs across the top of the aside:
| Tab | Label | Content |
|-----|-------|---------|
| Core | Core | Three permanent slots — Taxonomy Authority, Methodology Certifier, Peer Operator |
| Tier-I | Tier-I | Mediators, subject matter experts, advisors, authors |
| Tier-II | Tier-II | Attorneys — qualification standard per INSTITUTIONAL-RELATIONSHIPS.md |
| Other | Other | Civic organizations, consumer protection entities, oversight agencies |
The default active tab is Core. The operator may specify a different default per addon in `config.json` via a `directory_default_tab` field — this field is listed in `config.json.template` with value `"core"`.
A pending Core slot renders:
```html
<div class="{addon}-directory-slot {addon}-slot-pending">
<div class="{addon}-slot-role">{role}</div>
<div class="{addon}-slot-description">{description}</div>
<div class="{addon}-slot-status">Invitation pending</div>
</div>
```
A populated Core slot renders the entity name, mark (if provided), and URL. It never renders until `status` is `"active"` in `listings.json`.
### contracts/spool-v1.json ### contracts/spool-v1.json
@@ -197,19 +297,19 @@ This file is the contract. When the payload structure changes, the version incre
Skeleton contains: Skeleton contains:
- File header comment with addon name and version - File header comment with addon name and version
- Section comments for each visual area: layout, header, content, sidebar, resources, manage - Section comments for each visual area: layout, header, content, aside, directory, directory-core, directory-tiers, manage
- No rules yet — just the section comments as placeholders - No rules yet — just the section comments as placeholders
### {addon}.js ### {addon}.js
Skeleton contains: Skeleton contains:
- IIFE wrapper - IIFE wrapper
- `initResourcePanels()` function — complete, this is the same in every addon - `initDirectory()` function — placeholder, `// TODO: Bootstrap tab init if needed beyond data-bs-toggle`
- One placeholder function per interactive area with a `// TODO` comment - One placeholder function per interactive area with a `// TODO` comment
- `init()` calling all functions - `init()` calling all functions
- DOMContentLoaded guard - DOMContentLoaded guard
The `initResourcePanels()` function is shared behavior. It is the same in every addon. Copy it exactly from the pilot — it is proven. The pilot's `initResourcePanels()` function does not transfer. The new addons have no resource panels.
--- ---
@@ -221,7 +321,7 @@ The operator will direct which addon to build first. The expected sequence based
2. `dsc01` — DSC Categories — because it is the primary reference surface 2. `dsc01` — DSC Categories — because it is the primary reference surface
3. `scn01` — Scenarios — because it depends on both Vital Signs and DSC context being established 3. `scn01` — Scenarios — because it depends on both Vital Signs and DSC context being established
**Each skeleton must be confirmed working — loading without errors, displaying the access wall or placeholder content correctly — before the next skeleton begins.** **Each skeleton must be confirmed working — loading without errors, displaying the access wall or placeholder content correctly, rendering all four directory tabs including the three pending Core slots — before the next skeleton begins.**
--- ---
@@ -231,7 +331,7 @@ Before writing any skeleton file, discuss and confirm with the operator:
1. The exact route — the operator may have a different preference than what is proposed here 1. The exact route — the operator may have a different preference than what is proposed here
2. The access model — which privacy group gates participant access for this addon 2. The access model — which privacy group gates participant access for this addon
3. The sidebar content — what resources and navigation the Widget shows 3. The default directory tab — which of the four tabs is active on first load for this addon's typical visitor
4. The config fields — whether any addon-specific configuration is needed beyond the standard fields 4. The config fields — whether any addon-specific configuration is needed beyond the standard fields
5. The spool contract — what the payload block contains for this addon's submissions 5. The spool contract — what the payload block contains for this addon's submissions
@@ -241,10 +341,12 @@ Do not assume these decisions are made because they appear in this document. Thi
## What Not To Do ## What Not To Do
- Do not port the pilot `ds01` code. Read it as reference. Write the skeleton fresh. - Do not port the pilot `ds01` code. Read it as reference for Hubzilla conventions. Write the skeleton fresh.
- Do not add functional logic to the skeleton. Placeholders only. - Do not add functional logic to the skeleton. Placeholders only.
- Do not generate all three skeletons at once. One at a time, confirmed working before the next begins. - Do not generate all three skeletons at once. One at a time, confirmed working before the next begins.
- Do not create files that already exist in the repo. Read the repo first. - Do not create files that already exist in the repo. Read the repo first.
- Do not hardcode any value that belongs in `config.json`. - Do not hardcode any value that belongs in `config.json`.
- Do not write inline styles or inline scripts. - Do not write inline styles or inline scripts.
- Do not exceed 500 lines in any PHP file. The skeleton should be well under that — if it is approaching 300 lines before any logic is added, something is wrong. - Do not exceed 500 lines in any PHP file. The skeleton should be well under that — if it is approaching 300 lines before any logic is added, something is wrong.
- Do not build the Widget without all four directory tabs present and the three Core slots rendering. The directory is not a feature added after the skeleton is confirmed. It is part of what makes the skeleton complete.
- Do not populate Core slots with entity names. Pending state is the correct skeleton state. Names appear only after written approval is recorded by the operator.