Spec
Goals (v1)
- Authors can link between boards without hand-building environment-specific absolute URLs—works for
dft serveand Cloud after resolution. - Query parameters on those links align with existing dashboard variables (see Cloud
dashboard_renderquery parsing). - Authoring uses standard Markdown link URLs only—no custom markdown dialect. Optional
.md/.yaml/.ymlsuffixes on paths may be stripped as author sugar (tool behavior, not CommonMark).
Non-goals (v1)
canonical_for/ entity-registry YAML — deferred to M5 and only if needed; see ADR-002 and task. Prefer path conventions (e.g.…/list,…/detail) instead.- Per-dashboard
slug/url_pathfrontmatter overrides — not v1; file location is source of truth (move the file to change URL). - Full Lightdash-style opaque filter blobs in the URL (may revisit; see research synthesis).
- Chart click wiring end-to-end—coordinate with
ai_notes/features/CLICK_INTERACTIONS.md; v1 makes href targets unambiguous so clicks can reuse the same resolver later. - Wikilinks
[[board]]in v1 unless trivial on top of the same resolver.
Dependencies
Author-facing URL model (v1)
Dashboard URL root (author view): paths are root-relative from the logical dashboard namespace—authors do not type a storage prefix like faces/.
Examples:
[Open tickets](/zendesk/tickets/list?status=open)
[Ticket detail](/zendesk/tickets/detail?id={{ ticket_id }})
Implementation mapping: the resolver maps author path → canonical project slug used by Cloud and dft serve today (typically under faces/ on disk, e.g. faces/zendesk/tickets/list). Exact normalization rules must match dashboard discovery / existing slug behavior—see open questions.
Relative paths: ../ and ./ resolve against the current board’s slug directory (after the same author-root ↔ storage-slug mapping), then rewrite for Cloud vs serve—see ADR-001.
Convention for “views” (no metadata): teams can standardize recognizable paths such as:
…/list— filtered / overview table…/detail— single-entity board (variables in query, e.g.?id=)
This is documentation + habit, not enforced schema in v1.
Why render-time rewriting?
| Concern | Compile time | Render time |
|---|---|---|
| Knows Cloud org/project | No | Yes (dashboard_render) |
| Same YAML in CLI and Cloud | Yes | Yes |
Browsers resolve relative href against the HTML page URL (Suite: /{org}/{project}/d/{slug}/), not the repo slug tree—so we rewrite board links when rendering. Same pattern as static site generators that “fix” .md links: tool behavior, not CommonMark.
Resolution targets (after rewrite)
| Runtime | Shape (conceptual) |
|---|---|
dft serve |
/{storage_slug_path}?{query} per dataface/core/serve/server.py |
| Cloud | /{org}/{project}/d/{dashboard_slug}/?{query} + merge branch (allowlist TBD) from current request when absent on link |
Pass link_context through render(..., **options) into the content pipeline (dataface/core/render/faces.py, etc.); centralize in e.g. dataface/core/render/board_links.py with tests.
Phase plan (v1)
| Phase | Scope |
|---|---|
| 1a | Root-relative /… + board-relative ../ / ./ in face.content; suffix strip; serve + Cloud |
| 1b | Context merge (branch, allowlist) |
| 2 | Optional escape hatch only if ambiguity appears (e.g. explicit scheme)—not default |
M5 (separate task): optional canonical_for / entity index only if product proves need beyond conventions—task.
Testing & docs
- TDD: Resolver tests (mapping author root → storage slug,
../, suffix strip, query merge, Cloud vs serve). - Docs (required for v1 ship): New or updated
docs/docs/page stating author rules (this section), branch behavior, and examples; link from variables docs. Update drill-down example whenaction: linkshares resolver. - Quickstart:
_templates/link-matrix.template.mdwith/connector/...style examples.
Open questions
- Allowlist for merged query params (
branchonly vs more). - Board links in nested includes / chart footnotes—same pipeline if shared.
- Author path → storage slug when both
faces/anddashboards/trees exist (precedence, explicit disambiguation).