Fix #348: org create/profile/manage #355

Merged
crueber merged 2 commits from fix/issue-348 into main 2026-09-11 23:51:03 +00:00
Owner

Implements Forgejo #348 over the existing org service (UI/reveal ticket — no new endpoints):

Backend

  • owners/detailed rows gain always-present is_org (07 §8) from the new Env.Orgs OrgLister seam (law 8; one ListOrgs per listing regardless of owner count, law 6; nil seam → all false; list error fails open to all-false — display metadata never fails the listing). identity.Service.ListOrgs satisfies it; wired in cmd/walhub composition.
  • Table-driven internal/api/owners_orgs_test.go: nil/empty/unknown/error seam cases, wire-shape pin (present bool, never null), all three lane twins.

Frontend (no new deps)

  • Create-org flow: OrgNew.jsx at /orgs/new (static route before /:owner; no server change — the /{owner}/{repo} shell serves it) with name/display/description → orgs.create → lands in /:org/settings; "New organization" entry button on /explore. Validation in headless web/src/lib/orgs.js (mirrors identity.ValidOrg).
  • Public org profile: /:owner renders org header (badge + display name + description) above the repo list when the owner is an org (orgs.get, null for users); "Manage organization" only on profile can_edit (server-authoritative org-owner/host-admin). Private repos stay hidden by the server (#345).
  • Discovery: /explore badges org sections from the same payload (is_org, zero extra GETs, #281 pattern).
  • Owner-only management: settings tabs render read-only with "org owner required" notices for non-owners; server 403s unchanged (cosmetic-on-top).

Verification

  • go build ./..., go vet ./... clean; gofmt clean.
  • go test ./internal/api/ -race ok; package coverage 95.3% (≥95% gate holds); go test ./internal/identity/ -race, ./cmd/walhub/ -short ok.
  • node --test web/test/unit/*.test.js: 692 pass incl. new orgs.test.js (7 tests: validation parity, create body, is_org strictness, role lookup); 3 smoke failures are pre-existing/environmental (need a live server — identical on clean main).
  • vite build + esbuild SDK bundle green.
  • Docs amended in-change (law 12): 07_api.md (§8 shape + Decisions), 12_web_ui.md (Decisions), features/01 (Decisions).

Notes

  • Browser proof open (shared-daemon loopback guard; no private daemon per workspace rules).
  • web/dist/.keep restored after each vite build (emptyOutDir side effect) — committed tree keeps it.
Implements Forgejo #348 over the existing org service (UI/reveal ticket — no new endpoints): **Backend** - `owners/detailed` rows gain always-present `is_org` (07 §8) from the new `Env.Orgs` `OrgLister` seam (law 8; one `ListOrgs` per listing regardless of owner count, law 6; nil seam → all false; list error fails open to all-false — display metadata never fails the listing). `identity.Service.ListOrgs` satisfies it; wired in `cmd/walhub` composition. - Table-driven `internal/api/owners_orgs_test.go`: nil/empty/unknown/error seam cases, wire-shape pin (present bool, never null), all three lane twins. **Frontend** (no new deps) - Create-org flow: `OrgNew.jsx` at `/orgs/new` (static route before `/:owner`; no server change — the `/{owner}/{repo}` shell serves it) with name/display/description → `orgs.create` → lands in `/:org/settings`; "New organization" entry button on `/explore`. Validation in headless `web/src/lib/orgs.js` (mirrors `identity.ValidOrg`). - Public org profile: `/:owner` renders org header (badge + display name + description) above the repo list when the owner is an org (`orgs.get`, null for users); "Manage organization" only on profile `can_edit` (server-authoritative org-owner/host-admin). Private repos stay hidden by the server (#345). - Discovery: `/explore` badges org sections from the same payload (`is_org`, zero extra GETs, #281 pattern). - Owner-only management: settings tabs render read-only with "org owner required" notices for non-owners; server 403s unchanged (cosmetic-on-top). **Verification** - `go build ./...`, `go vet ./...` clean; `gofmt` clean. - `go test ./internal/api/ -race` ok; package coverage 95.3% (≥95% gate holds); `go test ./internal/identity/ -race`, `./cmd/walhub/ -short` ok. - `node --test web/test/unit/*.test.js`: 692 pass incl. new `orgs.test.js` (7 tests: validation parity, create body, is_org strictness, role lookup); 3 smoke failures are pre-existing/environmental (need a live server — identical on clean main). - `vite build` + esbuild SDK bundle green. - Docs amended in-change (law 12): 07_api.md (§8 shape + Decisions), 12_web_ui.md (Decisions), features/01 (Decisions). **Notes** - Browser proof open (shared-daemon loopback guard; no private daemon per workspace rules). - `web/dist/.keep` restored after each vite build (emptyOutDir side effect) — committed tree keeps it.
Backend (07_api.md §8, features/01 §8): owners/detailed rows gain
always-present is_org from the new Env.Orgs OrgLister seam (one
ListOrgs per listing, fail-open; identity.Service satisfies it;
wired in cmd/walhub composition). No new endpoint, no discovery
change. Table-driven owners_orgs_test.go (nil/empty/error seam,
shape pin, lane twins).

Frontend (12_web_ui.md): /orgs/new create-org form (orgs.create,
lands in /:org/settings; entry button on /explore); /:org public
org header above the repo list (Manage link on profile can_edit);
explore org badges from the same payload; settings tabs read-only
for non-owners (server 403s unchanged). Headless orgs.test.js.

Decisions appended in 07_api.md, 12_web_ui.md, features/01.
Sign in to join this conversation.
No description provided.