RFC-0001: v0.1 implementation plan¶
Status: Accepted Author: Alex Nodeland Created: 2026-10-12 Discussion: derived from lattice RFC-0002, accepted on 2026-10-12 with its decisions P1 to P6 Siblings:
- lattice RFC-0002 is the design this plan builds. Its decisions are portalr's ADR-0001 to ADR-0006.
- lattice RFC-0001 is grantr, whose API the UIs ask and the admin UI manages access through. Most of portalr's later phases wait on its phases.
- stackr RFC-0003 fixes portalr's layout, its Bun workspace and its CI, which RFC-0002 amends twice.
Summary¶
portalr is the portal that lattice RFC-0002 designs: an app UI and an admin UI, as static single-page apps in React, sharing a typed client and a ui kit, and a router the application mounts that serves them and adds the few routes no library has. This RFC is portalr's plan for v0.1: RFC-0002's eight phases, after a foundation, with the parts each phase adds, where its work lands, and what it waits on. The design itself is RFC-0002's and is not repeated here.
Motivation¶
RFC-0002 is a lattice document, and its phases reach into four packages besides portalr: grantr's API, artifactr's and reflexr's log records, and stackr's collector, stack and template. portalr needs a plan in its own series that its pull requests reference and tick, that says which work is portalr's, and what each phase waits on in the others.
Design¶
Parts¶
| Part | Holds | Phase |
|---|---|---|
packages/portalr/web/ |
The Bun workspace's four packages, each a moon project with lint, typecheck and check, and test or build as it has code to test or build (ADR-0008) |
1 |
@portalr/ui |
The brand tokens and Base UI primitives (2); the chat and artifact components (5); the tables (6) | 1, 2, 5, 6 |
@portalr/client |
The generated types, the fetch client, and a WebSocket store per protocol, with its reducer | 1, 3 |
portalr.readers |
One reader per tool, Langfuse, Tempo, Loki, Prometheus and LiteLLM, each taking a Tenant, with the tests over every query |
4 |
portalr (the router) |
portalr_router: the UIs, config.json, the readers' routes, invites, and portalr's action catalog |
4 |
schemas/, bruno/ |
portalr's OpenAPI document with its drift test, and its Bruno collection | 4 |
app |
Sign-in, the tenant and workspace pickers, and the app's areas | 1, 5 |
admin |
The admin's areas | 1, 6 |
A module's name may change when it is built; the architecture's status table shows what exists.
Work that lands elsewhere¶
| Work | Lands in | Phase |
|---|---|---|
| portalr's and grantr's marks, working colours and tokens, as lattice ADR-0014 | lattice's brand | 2 |
| The tenant attribute on log records | artifactr, reflexr | 4 |
tenant.id in the collector, prom-label-proxy, and access_token redacted from access logs and spans |
stackr | 4 |
GET /grantr/v1/me and POST /grantr/v1/checks |
grantr, in its own plan | grantr's phase 3 |
The portal question, the smoke test, and the Acceptance job's portalr steps |
stackr's template, CI | 7 |
Prerequisites¶
As of 2026-10-12:
| Prerequisite | From | Needed by | State |
|---|---|---|---|
| artifactr's and reflexr's OpenAPI documents | stackr RFC-0003's phase 5 | phase 3 | Done (#68) |
| grantr's OpenAPI document | lattice RFC-0001's phase 3 | phase 3 | Done (#60) |
Grants and grantr:add_member |
lattice RFC-0001's phases 2 and 3 | phase 4 | Done (#54, #60) |
Memberships, /me and /checks, and the template's access |
lattice RFC-0001's phases 1 to 4 | phases 5 and 6 | Done (#54, #60, #69) |
| Restricted threads and artifacts | lattice RFC-0001's phase 5 | phase 5's restricted items | Done (#94, #97) |
Phases¶
| Phase | Deliverable | Lands in | Waits on | Exit criteria |
|---|---|---|---|---|
| 0. Foundation | The package, its release, its site section, ADRs for P1 to P6, this plan and its tracking issue | portalr, lattice | Nothing | portalr:check and the site's strict build pass |
| 1. The workspace | The Bun workspace, the toolchains, Biome, TypeScript, knip and moon's TypeScript tasks; empty client, ui, app and admin; the TypeScript 7 check of each tool; osv-scanner and Renovate over bun.lock |
portalr, lattice | Nothing | moon ci runs the web packages' check in CI, and an empty app builds |
| 2. The brand | lattice ADR-0014: portalr's and grantr's marks and working colours, and their tokens; ui's tokens and primitives |
portalr, lattice's brand | Nothing; drawn with the maintainer | ui's components pass their browser tests in light and dark, and the site shows both new marks |
| 3. client | Generated types, the fetch client, and the WebSocket stores, tested against docplan and oncall | portalr | The OpenAPI documents above | A test client resumes a stream across a dropped connection without losing or repeating an event |
| 4. The router | portalr_router: serving the UIs, the readers and their filters, invites; its OpenAPI document and drift test; its Bruno collection; the tenant on log records, tenant.id in the collector, prom-label-proxy |
portalr, artifactr, reflexr, stackr | grantr's phases 2 and 3 | The collection passes against an application on the stack, with each tool both up and down, and the readers' two-tenant test never sees the other tenant |
| 5. app | Sign-in, the tenant and workspace pickers, and the app's areas | portalr | grantr's phases 1 to 4, and its phase 5 for restricted items | Each area's bdd scenario passes |
| 6. admin | The admin's areas | portalr | grantr's phases 1 to 4 | Each area's bdd scenario passes, for a tenant admin and for an operator |
| 7. Template and acceptance | The portal question, the smoke test, the Acceptance job's portalr steps, and the size budgets |
stackr's template, CI | Phases 4 to 6, and grantr's phase 4 | A generated application with a portal passes its CI, and the Acceptance job is green |
| 8. Docs and ADRs | portalr's guides, architecture and README, and the ADRs for each decision | portalr | Phases 1 to 7 | portalr's section builds, with the architecture updated |
Each phase is a series of small pull requests to main, and a phase brings its guides, reference pages, architecture and ADRs with it.
Drawbacks¶
- It waits on grantr. Phases 4 to 7 can't finish until grantr's phases land, and grantr is planned in parallel.
- Part of the plan lands elsewhere. Phases 2, 4 and 7 change lattice's brand, artifactr, reflexr and stackr, so this checklist tracks work its own pull requests don't contain.
Alternatives¶
RFC-0002 weighs portalr's design, and the alternatives to each decision, in its Alternatives and Decisions. For the plan itself, tracking portalr's work in RFC-0002's checklist would keep one list, but a lattice-wide one, which would mix portalr's progress with the other packages'.
Unresolved questions¶
RFC-0002's own open questions stand: the working colours, spend by workspace, mobile, and analytics beyond usage and spend. One more moved:
- Localization: whether the UIs' strings go through a catalog from the start, or stay in English in the components until a second language is wanted. RFC-0002 gave it to phase 1, which built no screens. Settled in ADR-0014: English in the components, and a catalog with a second language.
Tracking¶
The tracking issue is #46.
- Phase 0: foundation
- Phase 1: the workspace (portalr ADR-0007, ADR-0008)
- Phase 2: the brand (lattice ADR-0014)
- Phase 3: client (ADR-0010)
- Phase 4: the router (ADR-0011, ADR-0012)
- Phase 5: app
- Phase 6: admin
- 6a: signing in, admin's tenant and every tenant, and Home (ADR-0023)
- 6b: Access
- 6c: Audit, Feedback, and Usage and spend
- 6c-i: Audit, on grantr's audit filters and its read from the end (ADR-0026, grantr ADR-0030, ADR-0032)
- 6c-ii: Feedback and evaluations, and the first charts (ADR-0027)
- 6c-iii: Usage and spend (ADR-0028)
- 6d: Traces and logs, and Runs
- 6e: the operators' Tenants and Tools
- Phase 7: template and acceptance
- 7a: the
portalquestion and the generated application's wiring (stackr ADR-0038) - 7b: the UIs' scenarios against a generated application, the Acceptance job's portalr steps, and the size budgets (ADR-0040)
- 7a: the
- Phase 8: docs and ADRs, the guides (Getting started, the app, the admin UI, the operators' runbook and what portalr keeps from view); the ADRs were written with each phase (ADR-0001 to ADR-0006 in phase 0)