generated from coulomb/repo-seed
- Schema: hubs, widgets, widget_versions, interaction_events (append-only trigger), annotations, users — single migration file - Web layer: Types, Routes, FrontController with auth + AutoRefresh layout - Controllers: Hubs (CRUD), Widgets (CRUD + versioning), InteractionEvents (JSON capture, canonical event_type validation), Annotations (threaded, append-only) - Sessions controller for IHP auth - Views: Hubs (index/show/new/edit), Widgets (index/show/new/edit), Annotations (index/new), Sessions (login) - widgetEnvelope helper with full data-* governance attributes - Integration tests: Hub CRUD, Widget versioning, event capture, append-only guard, annotation threading, validation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
57 lines
1.9 KiB
Markdown
57 lines
1.9 KiB
Markdown
# Widget Envelope Convention
|
|
|
|
Every rendered widget in inter-hub wraps its HSX in the `widgetEnvelope` helper
|
|
from `Application.Helper.View`. This injects a stable set of `data-*` attributes
|
|
that enable client-side event capture without coupling to implementation details.
|
|
|
|
## Usage
|
|
|
|
```haskell
|
|
import Application.Helper.View (widgetEnvelope)
|
|
|
|
-- In any view:
|
|
widgetEnvelope widget [hsx|
|
|
<button class="...">Click me</button>
|
|
|]
|
|
```
|
|
|
|
## Emitted HTML
|
|
|
|
```html
|
|
<div
|
|
class="ihf-widget"
|
|
data-widget-id="<uuid>"
|
|
data-widget-type="chart"
|
|
data-hub-id="<uuid>"
|
|
data-capability-ref="pipeline.run"
|
|
data-view-context="ops/dashboard"
|
|
data-policy-scope="internal"
|
|
data-widget-version="3"
|
|
>
|
|
<!-- inner content -->
|
|
<div class="ihf-widget-controls">
|
|
<a href="/widgets/<uuid>/annotations" class="ihf-annotate-btn">Annotate</a>
|
|
</div>
|
|
</div>
|
|
```
|
|
|
|
## Attributes
|
|
|
|
| Attribute | Source | Purpose |
|
|
|-----------|--------|---------|
|
|
| `data-widget-id` | `widget.id` | Stable identity for event capture |
|
|
| `data-widget-type` | `widget.widgetType` | Semantic role of the widget |
|
|
| `data-hub-id` | `widget.hubId` | Which hub owns this widget |
|
|
| `data-capability-ref` | `widget.capabilityRef` | Link to hub capability |
|
|
| `data-view-context` | `widget.viewContext` | Logical location in the UI |
|
|
| `data-policy-scope` | `widget.policyScope` | Governance policy boundary |
|
|
| `data-widget-version` | `widget.version` | Version at render time |
|
|
|
|
## Rules
|
|
|
|
1. **Every interactive hub element** that participates in governance must be wrapped.
|
|
2. The `data-widget-id` is the capture key — the event capture endpoint uses it as `widget_id`.
|
|
3. Do not add or remove `data-*` attributes without updating both this convention doc and
|
|
the event capture client script.
|
|
4. The "Annotate" control is always rendered. It links to the full annotation thread for the widget.
|