generated from coulomb/repo-seed
STATE-WP-0062 T5: docs, first-party↔repo test, mark workplan finished
- Add /docs/services reference (two-dimension model, persistence, API) and a pointer note from /docs/tpsc; add it to the Reference nav. - Add a test asserting first_party.repo_slug resolves to a managed_repos FK (8 services tests green). - Mark STATE-WP-0062 tasks done / status finished. Known classes seeded in the live catalog via the API (Gitea, Postgres as self-hosted/third-party; State Hub as self-hosted/first-party at Level 2). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -113,6 +113,7 @@ export default {
|
||||
{ name: "Repos", path: "/docs/repos" },
|
||||
{ name: "SBOM", path: "/docs/sbom" },
|
||||
{ name: "SCOPE.md", path: "/docs/scope" },
|
||||
{ name: "Service Catalog", path: "/docs/services" },
|
||||
{ name: "Tasks", path: "/docs/tasks" },
|
||||
{ name: "TPSC", path: "/docs/tpsc" },
|
||||
{ name: "TPSC — GDPR Maturity", path: "/docs/gdpr-maturity" },
|
||||
|
||||
54
dashboard/src/docs/services.md
Normal file
54
dashboard/src/docs/services.md
Normal file
@@ -0,0 +1,54 @@
|
||||
---
|
||||
title: Service Catalog — Reference
|
||||
---
|
||||
|
||||
# Service Catalog (two dimensions)
|
||||
|
||||
Every service coulomb consumes or operates is classified along **two independent
|
||||
dimensions**, so four classes fall out of their product:
|
||||
|
||||
| | **third-party** (not dev-responsible) | **first-party** (dev-responsible) |
|
||||
|---|---|---|
|
||||
| **cloud-hosted** (consumed) | SaaS / APIs — the classic [TPSC](/docs/tpsc) | a coulomb service deployed to a cloud |
|
||||
| **self-hosted** (operated) | OSS coulomb runs (Gitea, Postgres…) | a coulomb service on coulomb infra |
|
||||
|
||||
- **Hosting** — `self_hosted` (coulomb operates the service) vs `cloud_hosted`
|
||||
(coulomb consumes someone else's running service).
|
||||
- **Development** — `first_party` (coulomb is development-responsible) vs
|
||||
`third_party` (coulomb is not).
|
||||
|
||||
## Persistence
|
||||
|
||||
A common **`service_catalog`** core table holds the shared fields
|
||||
(`slug`, `name`, `owner_or_provider`, `category`, `status`, `hosting_type`,
|
||||
`development_type`, `maturity_level`). Dimension-specific data lives in 1:1
|
||||
extension tables that **compose** — a self-hosted first-party service carries
|
||||
both the self-hosted *and* first-party extensions:
|
||||
|
||||
| Extension | Keyed on | Holds |
|
||||
|---|---|---|
|
||||
| `service_third_party` | `development_type = third_party` | upstream packages, support/service contacts, source, license, pricing |
|
||||
| `service_first_party` | `development_type = first_party` | internal dev repo (`managed_repos` FK), owning domain |
|
||||
| `service_cloud` | `hosting_type = cloud_hosted` | GDPR maturity, DPA, ToS/privacy, data-processing regions, retention |
|
||||
| `service_self_hosted` | `hosting_type = self_hosted` | three-helix instance/host, deployment & runbook refs, upstream OSS project |
|
||||
|
||||
`maturity_level` (1 · Core → 2 · Standard → 3 · Mature) tracks a service against
|
||||
the [Service DoM](/policy/service-dom).
|
||||
|
||||
## API
|
||||
|
||||
- `GET /services/catalog?hosting_type=&development_type=&maturity_level=&status=`
|
||||
— filtered list; each row includes its applicable extensions.
|
||||
- `GET /services/{slug}` — one service with extensions.
|
||||
- `POST /services/catalog` — upsert by slug; pass `first_party.repo_slug` to link
|
||||
the internal dev repo.
|
||||
|
||||
The dashboard **Services** section renders three views over this catalog:
|
||||
[Third Party](/tpsc), [First Party](/services/first-party), and
|
||||
[Self Hosted](/services/self-hosted).
|
||||
|
||||
## Migration & back-compat
|
||||
|
||||
Existing TPSC catalog rows migrated into `service_catalog` as
|
||||
`(cloud_hosted, third_party)`, reusing their ids so `tpsc_entries.catalog_id`
|
||||
keep resolving. The `/tpsc/*` endpoints and `tpsc.yaml` ingestion are unchanged.
|
||||
@@ -7,6 +7,11 @@ title: Third-Party Services Catalog (TPSC)
|
||||
The TPSC tracks external service dependencies (APIs, SaaS, CLIs) across all
|
||||
registered repos — complementing the SBOM for package dependencies.
|
||||
|
||||
> **Now part of the broader service catalog.** TPSC is the `cloud_hosted` +
|
||||
> `third_party` quadrant of the two-dimension [service catalog](/docs/services).
|
||||
> Catalog rows have migrated into `service_catalog`; the `/tpsc/*` endpoints and
|
||||
> per-repo `tpsc.yaml` dependency snapshots continue to work unchanged.
|
||||
|
||||
---
|
||||
|
||||
## Why TPSC?
|
||||
|
||||
@@ -91,3 +91,18 @@ async def test_first_party_unknown_repo_slug_404(client):
|
||||
async def test_get_unknown_service_404(client):
|
||||
r = await client.get("/services/nope")
|
||||
assert r.status_code == 404
|
||||
|
||||
|
||||
async def test_first_party_repo_slug_links_to_repo(client):
|
||||
await client.post("/domains/", json={"slug": "custodian", "name": "Custodian"})
|
||||
repo = (await client.post("/repos/", json={
|
||||
"domain_slug": "custodian", "slug": "state-hub", "name": "State Hub",
|
||||
})).json()
|
||||
|
||||
r = await client.post("/services/catalog", json=_svc(
|
||||
"state-hub-api", "self_hosted", "first_party",
|
||||
maturity_level=2,
|
||||
first_party={"repo_slug": "state-hub", "owning_domain": "custodian"},
|
||||
))
|
||||
assert r.status_code == 201, r.text
|
||||
assert r.json()["first_party"]["repo_id"] == repo["id"]
|
||||
|
||||
@@ -4,11 +4,12 @@ type: workplan
|
||||
title: "Two-dimension service catalog (hosting × development) + Services nav section"
|
||||
domain: custodian
|
||||
repo: state-hub
|
||||
status: proposed
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: custodian
|
||||
created: "2026-06-19"
|
||||
updated: "2026-06-19"
|
||||
state_hub_workstream_id: "b5c9d93f-9f5e-4d10-bb3b-90322c7419b7"
|
||||
---
|
||||
|
||||
# STATE-WP-0062 — Two-dimension service catalog + Services nav section
|
||||
@@ -92,55 +93,59 @@ tables (each 1:1, optional, keyed by `service_id`):
|
||||
|
||||
```task
|
||||
id: STATE-WP-0062-T01
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "f74612f6-b442-4b5f-ac4d-7bc6d1d4883f"
|
||||
```
|
||||
|
||||
- [ ] `api/models/service_catalog.py`: `ServiceCatalog` core + `ServiceThirdParty`,
|
||||
- [x] `api/models/service_catalog.py`: `ServiceCatalog` core + `ServiceThirdParty`,
|
||||
`ServiceFirstParty`, `ServiceCloud`, `ServiceSelfHosted` extensions.
|
||||
- [ ] Alembic migration; register in `api/models/__init__.py`.
|
||||
- [ ] Data migration: copy `tpsc_catalog` → `service_catalog` + `service_cloud`
|
||||
- [x] Alembic migration; register in `api/models/__init__.py`.
|
||||
- [x] Data migration: copy `tpsc_catalog` → `service_catalog` + `service_cloud`
|
||||
with `(cloud_hosted, third_party)`; backfill `service_id` on TPSC entries.
|
||||
|
||||
### T2 — API + MCP
|
||||
|
||||
```task
|
||||
id: STATE-WP-0062-T02
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "373cddfa-c85b-47a7-bb8e-c86e9341c237"
|
||||
```
|
||||
|
||||
- [ ] `GET /services/catalog` with `hosting_type` / `development_type` /
|
||||
- [x] `GET /services/catalog` with `hosting_type` / `development_type` /
|
||||
`maturity_level` filters; `GET /services/{slug}` returns core + applicable
|
||||
extensions.
|
||||
- [ ] Write path to register/update a service and its extensions (generalise
|
||||
- [x] Write path to register/update a service and its extensions (generalise
|
||||
`register_service`; keep a `third_party`-shaped compatibility wrapper).
|
||||
- [ ] Keep `/tpsc/*` working as a `development_type=third_party` view.
|
||||
- [x] Keep `/tpsc/*` working as a `development_type=third_party` view.
|
||||
|
||||
### T3 — Services nav section + four-quadrant pages
|
||||
|
||||
```task
|
||||
id: STATE-WP-0062-T03
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "b14bbbdd-347e-4f62-9ac3-ad42360fa766"
|
||||
```
|
||||
|
||||
- [ ] Replace the top-level "Services (TPSC)" entry with a **Services** section.
|
||||
- [ ] Pages: **Third Party** (current TPSC view), **First Party** (with internal
|
||||
- [x] Replace the top-level "Services (TPSC)" entry with a **Services** section.
|
||||
- [x] Pages: **Third Party** (current TPSC view), **First Party** (with internal
|
||||
repo link + **Service Maturity Level** column), **Self Hosted** (three-helix
|
||||
infra view). Each is a filtered view over `service_catalog`.
|
||||
- [ ] Surface the two dimensions explicitly (e.g. a quadrant filter) so the four
|
||||
- [x] Surface the two dimensions explicitly (e.g. a quadrant filter) so the four
|
||||
classes are navigable.
|
||||
|
||||
### T4 — Terminology: Tier → Level (Service DoM only)
|
||||
|
||||
```task
|
||||
id: STATE-WP-0062-T04
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "1c296d7a-c090-430f-8d0d-27b548d88d9e"
|
||||
```
|
||||
|
||||
- [ ] `policies/service-dom.md`: rename "Tier 1/2/3" → "Level 1/2/3"; column
|
||||
- [x] `policies/service-dom.md`: rename "Tier 1/2/3" → "Level 1/2/3"; column
|
||||
header "Service Maturity Level". **Do not** touch the DoI tier subsystem
|
||||
(`repos.md`, `check_doi.py`, `doi_cache` migration) — that is a separate,
|
||||
established concept.
|
||||
@@ -149,15 +154,16 @@ priority: medium
|
||||
|
||||
```task
|
||||
id: STATE-WP-0062-T05
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "2edd68ee-0d9a-431d-9891-73a0f6be6a41"
|
||||
```
|
||||
|
||||
- [ ] Tests: model + migration round-trip, dimension filters, TPSC back-compat
|
||||
- [x] Tests: model + migration round-trip, dimension filters, TPSC back-compat
|
||||
view, first-party↔repo link.
|
||||
- [ ] Docs: `/docs/services` reference; update `/docs/tpsc` to point at the
|
||||
- [x] Docs: `/docs/services` reference; update `/docs/tpsc` to point at the
|
||||
generalised model.
|
||||
- [ ] Seed the known classes: TPSC SaaS (cloud/third-party), self-hosted OSS from
|
||||
- [x] Seed the known classes: TPSC SaaS (cloud/third-party), self-hosted OSS from
|
||||
`tools.md` (Gitea, Postgres — self-hosted/third-party), and State Hub itself
|
||||
(self-hosted/first-party).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user