Compare commits
2 Commits
feat/65-nx
...
92c189b8c0
| Author | SHA1 | Date | |
|---|---|---|---|
| 92c189b8c0 | |||
| 1b49f541dc |
41
BACKLOG.md
41
BACKLOG.md
@@ -12,22 +12,41 @@ Each slice is **independently demoable** and meets the Definition of Done in `CL
|
||||
|
||||
## Iteration 0 — Foundations *(milestone: `Iteration 0 — Foundations`)*
|
||||
|
||||
### S-00 · Repository skeleton, Gitea Actions CI, contributor workflow
|
||||
> **S-00 was split** (CLAUDE.md §13) into the sub-slices below. The original
|
||||
> outcome — a fresh clone + `docker compose up` reaching a green BFF health
|
||||
> endpoint, with CI green and the contributor scaffolding in place — is the sum
|
||||
> of S-00-a…e. Milestones, labels, and the Iteration 1 population are already
|
||||
> done (see `tools/seed-gitea.sh`).
|
||||
|
||||
**Outcome:** A fresh `git clone` from the Respellion Gitea remote, followed by `docker compose up`, produces a green "hello world" health endpoint from a placeholder BFF. Gitea Actions runs lint, build, unit tests, and the compose-up smoke test, all green. Issue templates, PR template, milestones, labels, and the first project board exist in Gitea.
|
||||
### S-00-a · Placeholder BFF + health endpoint
|
||||
|
||||
**Acceptance:**
|
||||
**Outcome:** A minimal .NET BFF exposing `GET /health` returning green; runnable with `dotnet run`. TDD anchor for the slice.
|
||||
|
||||
- New developer follows `README.md` and reaches a green local environment in under 10 minutes.
|
||||
- Gitea Actions pipeline green on `main`.
|
||||
- `git-cliff` produces an empty `CHANGELOG.md`.
|
||||
- `docs/PRD.md`, `CLAUDE.md`, `BACKLOG.md`, `docs/architecture/adr-0001-loose-coupling.md`, `docs/gitea-workflow.md` all in repo.
|
||||
- `.gitea/workflows/ci.yaml`, `.gitea/ISSUE_TEMPLATE/{slice,bug,adr-proposal}.md`, `.gitea/PULL_REQUEST_TEMPLATE.md` all in repo.
|
||||
- Gitea milestone `Iteration 1 — Walking Skeleton` exists, populated with issues S-01 through S-09.
|
||||
**Touches:** `services/bff/`, tests. **Out of scope:** Docker, CI, OIDC.
|
||||
|
||||
**Touches:** repo layout, Gitea Actions workflows, Dockerfile for placeholder BFF, `docker-compose.yml` skeleton, MkDocs scaffold, Gitea issue/PR templates.
|
||||
### S-00-b · Dockerfile + compose skeleton + compose-up smoke
|
||||
|
||||
**Out of scope:** any business logic, frontend, OpenZaak.
|
||||
**Outcome:** BFF containerized; `infra/docker-compose.yml` brings it up; health green within 3 minutes from a fresh clone.
|
||||
|
||||
**Touches:** `services/bff/Dockerfile`, `infra/docker-compose.yml`, smoke script. **Out of scope:** other services, CI.
|
||||
|
||||
### S-00-c · Gitea Actions CI (lint, build, unit, compose-up smoke)
|
||||
|
||||
**Outcome:** `.gitea/workflows/ci.yaml` green on PRs and `main`: lint, build, unit, compose-up smoke. Actions pinned by absolute URL (§8.7/§15).
|
||||
|
||||
**Touches:** `.gitea/workflows/ci.yaml`, `docs/runbooks/ci.md`. **Out of scope:** mutation, e2e, container push.
|
||||
|
||||
### S-00-d · Contributor workflow: issue/PR templates, git-cliff, CHANGELOG
|
||||
|
||||
**Outcome:** Issue templates (`slice`/`bug`/`adr-proposal`), PR template, `git-cliff` → empty `CHANGELOG.md`, `docs/gitea-workflow.md`.
|
||||
|
||||
**Touches:** `.gitea/ISSUE_TEMPLATE/`, `.gitea/PULL_REQUEST_TEMPLATE.md`, `cliff.toml`, `CHANGELOG.md`, `docs/gitea-workflow.md`. **Out of scope:** app code.
|
||||
|
||||
### S-00-e · Docs scaffold: MkDocs + ADR-0001 + README quickstart
|
||||
|
||||
**Outcome:** MkDocs builds the `docs/` site; `docs/architecture/adr-0001-loose-coupling.md` exists; README has a sub-10-minute quickstart.
|
||||
|
||||
**Touches:** `mkdocs.yml`, `docs/` nav, `docs/architecture/adr-0001-loose-coupling.md`, `README.md`. **Out of scope:** Gitea Pages publish.
|
||||
|
||||
---
|
||||
|
||||
|
||||
202
tools/split-s00.sh
Normal file
202
tools/split-s00.sh
Normal file
@@ -0,0 +1,202 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# split-s00.sh — one-off: split issue S-00 (#1) into sub-slices S-00-a..e per
|
||||
# CLAUDE.md §13. Creates the five sub-slice issues, then closes #1 with a
|
||||
# comment listing the replacements.
|
||||
#
|
||||
# Idempotent: sub-slices already present (matched by title) are skipped; the
|
||||
# closing comment is posted once (guarded by a marker); #1 is closed only if open.
|
||||
#
|
||||
# Usage:
|
||||
# GITEA_TOKEN=<pat> bash tools/split-s00.sh
|
||||
#
|
||||
# Token scopes: write:issue.
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
: "${GITEA_TOKEN:?Set GITEA_TOKEN to a Gitea personal access token (scope: write:issue)}"
|
||||
|
||||
BASE="https://git.labs.respellion.tech/api/v1"
|
||||
OWNER="eho"
|
||||
REPO="register-referentie"
|
||||
REPO_API="$BASE/repos/$OWNER/$REPO"
|
||||
PARENT=1 # S-00 issue number
|
||||
MARKER="<!-- split-s00 -->"
|
||||
|
||||
AUTH=(-H "Authorization: token $GITEA_TOKEN")
|
||||
JSON=(-H "Content-Type: application/json" -H "Accept: application/json")
|
||||
say() { printf '%s\n' "$*"; }
|
||||
|
||||
code=$(curl -s -o /dev/null -w '%{http_code}' "${AUTH[@]}" "$REPO_API")
|
||||
[ "$code" = "200" ] || { say "ERROR: cannot access $OWNER/$REPO (HTTP $code)."; exit 1; }
|
||||
say "Authenticated against $REPO_API"
|
||||
|
||||
labels_json=$(curl -s "${AUTH[@]}" "$REPO_API/labels?limit=100")
|
||||
milestones_json=$(curl -s "${AUTH[@]}" "$REPO_API/milestones?state=all&limit=100")
|
||||
existing_issues=$(curl -s "${AUTH[@]}" "$REPO_API/issues?state=all&type=issues&limit=100")
|
||||
|
||||
MILESTONE="Iteration 0 — Foundations"
|
||||
|
||||
DOD=$(cat <<'EOF'
|
||||
|
||||
## Definition of Done
|
||||
|
||||
- [ ] A linked Gitea issue exists (this one).
|
||||
- [ ] Failing test written and committed first.
|
||||
- [ ] Implementation makes the test pass.
|
||||
- [ ] Refactor commit follows if structure improved.
|
||||
- [ ] Conventional Commit messages referencing this issue (`refs #NN`).
|
||||
- [ ] All Gitea Actions CI jobs green.
|
||||
- [ ] `docker compose up` from a fresh clone reaches green health checks within 3 minutes.
|
||||
- [ ] Docs touched if behaviour, contracts, or operations changed.
|
||||
- [ ] ADR added in `docs/architecture/` if a non-obvious decision was made.
|
||||
- [ ] This issue closed by the merging PR (`closes #NN`).
|
||||
EOF
|
||||
)
|
||||
|
||||
create_issue() {
|
||||
local title="$1" labels_csv="$2" body="$3"
|
||||
if echo "$existing_issues" | jq -e --arg t "$title" 'any(.[]; .title == $t)' >/dev/null; then
|
||||
say " skip $title"
|
||||
return
|
||||
fi
|
||||
local ms_id; ms_id=$(echo "$milestones_json" | jq -r --arg m "$MILESTONE" '.[] | select(.title == $m) | .id')
|
||||
local want label_ids
|
||||
want=$(printf '%s' "$labels_csv" | jq -R 'split(",")')
|
||||
label_ids=$(echo "$labels_json" | jq -c --argjson want "$want" '[ .[] | select(.name as $n | $want | index($n)) | .id ]')
|
||||
local payload
|
||||
payload=$(jq -n --arg t "$title" --arg b "${body}${DOD}" --argjson ms "$ms_id" --argjson ls "$label_ids" \
|
||||
'{title:$t, body:$b, milestone:$ms, labels:$ls}')
|
||||
curl -s "${AUTH[@]}" "${JSON[@]}" -X POST "$REPO_API/issues" -d "$payload" >/dev/null
|
||||
say " create $title"
|
||||
}
|
||||
|
||||
say ""
|
||||
say "== Sub-slice issues =="
|
||||
|
||||
create_issue "S-00-a · Placeholder BFF + health endpoint" \
|
||||
"type:slice,area:bff" "$(cat <<'EOF'
|
||||
**Outcome:** A minimal .NET BFF service exposing `GET /health` that returns a green (`Healthy`) status. Runnable with `dotnet run`.
|
||||
|
||||
**Acceptance:**
|
||||
|
||||
- A failing xUnit test asserts `GET /health` returns 200 with a `Healthy` payload (red commit first).
|
||||
- Implementation makes it pass; `dotnet run` then `curl /health` returns `Healthy`.
|
||||
- Project follows the §9 layering seed (minimal `Api` project; `Application`/`Domain` added as they earn their place).
|
||||
|
||||
**Touches:** `services/bff/`, tests.
|
||||
|
||||
**Out of scope:** Docker, CI, OIDC, any real endpoints.
|
||||
|
||||
_Split from #1 (S-00) per CLAUDE.md §13._
|
||||
EOF
|
||||
)"
|
||||
|
||||
create_issue "S-00-b · Dockerfile + compose skeleton + compose-up smoke" \
|
||||
"type:slice,area:bff,area:infra" "$(cat <<'EOF'
|
||||
**Outcome:** The BFF is containerized and `infra/docker-compose.yml` brings it up; health goes green within 3 minutes from a fresh clone.
|
||||
|
||||
**Acceptance:**
|
||||
|
||||
- `docker build` of the BFF image succeeds.
|
||||
- `docker compose up` brings the BFF to a healthy state; a compose-up smoke script curls `/health` and passes.
|
||||
- README documents the `docker compose up` path.
|
||||
|
||||
**Touches:** `services/bff/Dockerfile`, `infra/docker-compose.yml`, smoke script.
|
||||
|
||||
**Out of scope:** other services; CI wiring (S-00-c).
|
||||
|
||||
_Split from #1 (S-00) per CLAUDE.md §13._
|
||||
EOF
|
||||
)"
|
||||
|
||||
create_issue "S-00-c · Gitea Actions CI (lint, build, unit, compose-up smoke)" \
|
||||
"type:slice,area:infra" "$(cat <<'EOF'
|
||||
**Outcome:** `.gitea/workflows/ci.yaml` runs on PRs and `main` with lint, build, unit tests, and the compose-up smoke test — all green.
|
||||
|
||||
**Acceptance:**
|
||||
|
||||
- Pipeline green on the branch.
|
||||
- Jobs: lint, build, unit, compose-up smoke. `uses:` references are absolute URLs pinned to a tag (CLAUDE.md §8.7 / §15).
|
||||
- Self-hosted runner label documented in `docs/runbooks/ci.md`.
|
||||
|
||||
**Touches:** `.gitea/workflows/ci.yaml`, `docs/runbooks/ci.md`.
|
||||
|
||||
**Out of scope:** mutation, e2e, container build + push (later slices).
|
||||
|
||||
_Split from #1 (S-00) per CLAUDE.md §13._
|
||||
EOF
|
||||
)"
|
||||
|
||||
create_issue "S-00-d · Contributor workflow: issue/PR templates, git-cliff, CHANGELOG" \
|
||||
"type:slice,area:docs,area:infra" "$(cat <<'EOF'
|
||||
**Outcome:** Issue templates (`slice`/`bug`/`adr-proposal`), a PR template enforcing the DoD checklist, a `git-cliff` config producing an (empty) `CHANGELOG.md`, and `docs/gitea-workflow.md`.
|
||||
|
||||
**Acceptance:**
|
||||
|
||||
- `.gitea/ISSUE_TEMPLATE/{slice,bug,adr-proposal}.md` and `.gitea/PULL_REQUEST_TEMPLATE.md` present; opening a new issue offers the templates.
|
||||
- `cliff.toml` present; `git-cliff` generates `CHANGELOG.md`.
|
||||
- `docs/gitea-workflow.md` documents the issue → milestone → PR flow.
|
||||
|
||||
**Touches:** `.gitea/ISSUE_TEMPLATE/`, `.gitea/PULL_REQUEST_TEMPLATE.md`, `cliff.toml`, `CHANGELOG.md`, `docs/gitea-workflow.md`.
|
||||
|
||||
**Out of scope:** app code.
|
||||
|
||||
_Split from #1 (S-00) per CLAUDE.md §13._
|
||||
EOF
|
||||
)"
|
||||
|
||||
create_issue "S-00-e · Docs scaffold: MkDocs + ADR-0001 + README quickstart" \
|
||||
"type:slice,area:docs" "$(cat <<'EOF'
|
||||
**Outcome:** MkDocs Material builds the `docs/` site; `docs/architecture/adr-0001-loose-coupling.md` exists as the ADR template; README gains a sub-10-minute quickstart.
|
||||
|
||||
**Acceptance:**
|
||||
|
||||
- `mkdocs build` succeeds (`mkdocs.yml` + nav).
|
||||
- `adr-0001-loose-coupling.md` present, Nygard template.
|
||||
- A new developer following `README.md` reaches a green local environment in under 10 minutes.
|
||||
|
||||
**Touches:** `mkdocs.yml`, `docs/` nav, `docs/architecture/adr-0001-loose-coupling.md`, `README.md`.
|
||||
|
||||
**Out of scope:** Gitea Pages publish workflow (later).
|
||||
|
||||
_Split from #1 (S-00) per CLAUDE.md §13._
|
||||
EOF
|
||||
)"
|
||||
|
||||
# --- Close #1 with a comment listing the replacements -----------------------
|
||||
say ""
|
||||
say "== Close parent #1 =="
|
||||
|
||||
# Resolve the numbers of the sub-slices we now have.
|
||||
all_issues=$(curl -s "${AUTH[@]}" "$REPO_API/issues?state=all&type=issues&limit=100")
|
||||
refs=$(echo "$all_issues" | jq -r '
|
||||
[ .[] | select(.title | startswith("S-00-")) ]
|
||||
| sort_by(.title)
|
||||
| map("- #\(.number) — \(.title)")
|
||||
| join("\n")')
|
||||
|
||||
comments=$(curl -s "${AUTH[@]}" "$REPO_API/issues/$PARENT/comments?limit=100")
|
||||
if echo "$comments" | jq -e --arg m "$MARKER" 'any(.[]; .body | contains($m))' >/dev/null; then
|
||||
say " skip split comment (already posted)"
|
||||
else
|
||||
body="$MARKER
|
||||
Split into sub-slices per CLAUDE.md §13. Replacement issues:
|
||||
|
||||
$refs"
|
||||
curl -s "${AUTH[@]}" "${JSON[@]}" -X POST "$REPO_API/issues/$PARENT/comments" \
|
||||
-d "$(jq -n --arg b "$body" '{body:$b}')" >/dev/null
|
||||
say " create split comment on #$PARENT"
|
||||
fi
|
||||
|
||||
state=$(echo "$all_issues" | jq -r --argjson n "$PARENT" '.[] | select(.number == $n) | .state')
|
||||
if [ "$state" = "closed" ]; then
|
||||
say " skip #$PARENT already closed"
|
||||
else
|
||||
curl -s "${AUTH[@]}" "${JSON[@]}" -X PATCH "$REPO_API/issues/$PARENT" \
|
||||
-d "$(jq -n '{state:"closed"}')" >/dev/null
|
||||
say " closed #$PARENT"
|
||||
fi
|
||||
|
||||
say ""
|
||||
say "Done."
|
||||
Reference in New Issue
Block a user