Flows
F 04 Catalog Setup
Status: ๐ข ready to test Owner: Adilet Last updated: 2026-05-08 Last verified on production: โ
Goal
An admin sets up the catalog tree (Organization โ Product โ Product Version) that test cycles attach to. This flow is the prerequisite for every cycle creation.
Actors
- Primary โ Admin
Preconditions
- Admin is signed in.
- (Optional) Production already has the seeded
Hackordaorganisation,Hackorda Webproduct, andv0.1.0version โ for an additional setup, you start from this baseline.
Trigger
Admin clicks "New" on /app/admin/organizations (or /products /
/products/:id versions panel).
Happy path โ Step 1: create organization
| # | Actor | UI surface | Action | API call | DB writes | Side effects | Suggested event |
|---|---|---|---|---|---|---|---|
| 1 | Admin | /app/admin/organizations | Click "New organization" | โ | โ | โ | โ |
| 2 | Admin | sheet form | Fill name, slug, type (internal/client/sponsor/partner), website | POST /api/admin/organizations | INSERT INTO organizations | โ | org.created |
| 3 | Frontend | list re-renders | toast: "Organization created" | โ | โ | โ | โ |
Happy path โ Step 2: create product
| # | Actor | UI surface | Action | API call | DB writes | Side effects | Suggested event |
|---|---|---|---|---|---|---|---|
| 1 | Admin | /app/admin/products | Click "New product" | โ | โ | โ | โ |
| 2 | Admin | sheet form | Pick organization, fill name, slug, URL, discipline (web_app/website/mobile/backend/api/ml/data/infra/mixed), payout-requires-verification flag | POST /api/admin/products | INSERT INTO products | โ | product.created |
| 3 | Frontend | list re-renders | toast: "Product created" | โ | โ | โ | โ |
Happy path โ Step 3: create product version
| # | Actor | UI surface | Action | API call | DB writes | Side effects | Suggested event |
|---|---|---|---|---|---|---|---|
| 1 | Admin | /app/admin/products/:id | Open versions panel, click "New version" | โ | โ | โ | โ |
| 2 | Admin | inline form | Fill version (e.g. v0.2.0), name, released_at, notes | POST /api/admin/products/:id/versions | INSERT INTO product_versions | โ | product_version.created |
| 3 | Frontend | versions list updates | toast: "Version created" | โ | โ | โ | โ |
Acceptance criteria
- AC-1 โ Given the admin fills a unique slug, when they submit the org form, then a row is inserted and the slug is enforced unique.
- AC-2 โ Given the admin tries to create a product without selecting an organisation, when they submit, then the form blocks with a validation error.
- AC-3 โ Given a product is configured with
payoutRequiresVerification = true, when later cycles inherit, then the verification gate is active by default for issues filed under those cycles (see F-10). - AC-4 โ Given the admin enters a version string identical to an
existing version on the same product, when they submit, then the API
returns 400 (unique on
(product_id, version)). - AC-5 โ Given the org / product / version are created, when the
admin opens
/app/admin/test-cycles/new, then the new entries appear in the dropdowns.
Test data / fixtures
Baseline seed not required โ this flow creates the catalog tree.
Use a unique slug like e2e-test-org to avoid colliding with seeded data.
Negative paths
| # | Scenario | Expected behavior |
|---|---|---|
| N-1 | Duplicate org slug | API 400 "slug already in use" |
| N-2 | Missing required fields | UI form validation blocks submit |
| N-3 | Non-admin caller | API 403 |
| N-4 | Delete an org with products attached | API 400 OR cascade โ verify policy on prod (currently RESTRICT) |
| N-5 | Bad URL format on products.url | UI validation OR API 400 |
Manual QA checklist
- Create a new Organization with slug
qa-test-org - Confirm it appears in the list
- Open the org detail page โ basic info renders correctly
- Create a Product under it: name
QA Test Product, slugqa-test-product, URLhttps://example.com, disciplineweb_app, verification gate ON - Confirm the product card shows the URL link and discipline
- Create version
v0.1.0for the product - Confirm version appears in versions panel
- On
/app/admin/test-cycles/new, confirm the new product + version are pickable - (Cleanup) Delete the version โ product โ organization (verify cascade or restrict behavior matches policy)
Automated test outline
test.describe("F-04 catalog setup", () => {
test("creates org โ product โ version end-to-end", async ({ page, request }) => { โฆ });
test("rejects duplicate org slug", async ({ request }) => { โฆ });
test("blocks non-admin", async ({ request }) => { โฆ });
});Code references
- Pages:
src/app/app/admin/organizations/page.tsx,src/app/app/admin/products/page.tsx - API:
src/app/api/admin/organizations/route.ts(GET, POST)src/app/api/admin/organizations/[id]/route.ts(GET, PATCH, DELETE)src/app/api/admin/products/route.tssrc/app/api/admin/products/[id]/route.tssrc/app/api/admin/products/[id]/versions/route.ts
- Hooks:
src/hooks/test-cycles/organizations.ts,src/hooks/test-cycles/products.ts - Schema:
organizations,products,product_versions
Events emitted (proposed)
org.createdโ{ org_id, slug, type, created_by }org.updatedโ{ org_id, fields_changed }org.deletedโ{ org_id }product.createdโ{ product_id, org_id, slug, discipline, gate_default }product.updated,product.deletedโ analogousproduct_version.createdโ{ version_id, product_id, version_string }
Open questions / known gaps
- No multi-tenant isolation: every admin sees every org. (Single-tenant
by design for v1; flagged in
feature-matrix.mdยง3.1.) - No org logo / branding upload yet.
- Product
integration_provider_slug+integration_configcolumns exist but the only wired provider is Linear (F-15).