@openora/create 0.1.0 → 0.4.1-canary.101

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +74 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/generated/core-version.d.ts +1 -1
  4. package/dist/generated/core-version.d.ts.map +1 -1
  5. package/dist/generated/core-version.js +1 -1
  6. package/dist/generated/core-version.js.map +1 -1
  7. package/package.json +3 -3
  8. package/template/README.md.tpl +1 -1
  9. package/template/__dot__env.example +3 -1
  10. package/template/__dot__gitignore +1 -1
  11. package/template/__dot__rulesync/commands/adr.md +32 -0
  12. package/template/__dot__rulesync/commands/check.md +3 -3
  13. package/template/__dot__rulesync/commands/doctor.md +16 -0
  14. package/template/__dot__rulesync/commands/scaffold-module.md +2 -2
  15. package/template/__dot__rulesync/commands/scaffold-plugin.md +1 -1
  16. package/template/__dot__rulesync/commands/scaffold-route.md +1 -1
  17. package/template/__dot__rulesync/hooks/guard-generated.mjs +3 -3
  18. package/template/__dot__rulesync/rules/conventions.md +90 -0
  19. package/template/__dot__rulesync/rules/e2e-conventions.md +48 -0
  20. package/template/__dot__rulesync/rules/oss-boundaries.md +31 -0
  21. package/template/__dot__rulesync/rules/overview.md +9 -2
  22. package/template/__dot__rulesync/skills/add-feature/SKILL.md +3 -3
  23. package/template/__dot__rulesync/skills/create-plugin/SKILL.md +6 -6
  24. package/template/__dot__rulesync/skills/create-pr/SKILL.md +1 -1
  25. package/template/__dot__rulesync/skills/create-ui-module/SKILL.md +58 -0
  26. package/template/__dot__rulesync/skills/handoff/SKILL.md +94 -0
  27. package/template/__dot__rulesync/skills/review/SKILL.md +111 -0
  28. package/template/__dot__rulesync/subagents/builder.md +3 -3
  29. package/template/__dot__rulesync/subagents/debugger.md +1 -2
  30. package/template/__dot__rulesync/subagents/qa.md +1 -1
  31. package/template/__dot__rulesync/subagents/quality-reviewer.md +67 -0
  32. package/template/__dot__rulesync/subagents/security-reviewer.md +54 -0
  33. package/template/apps/api/package.json.tpl +1 -2
  34. package/template/apps/api/src/main.ts.tpl +1 -3
  35. package/template/apps/api/src/seed.ts.tpl +5 -1
  36. package/template/docker-compose.yml +11 -0
  37. package/template/docs/standards/comments.md +16 -0
  38. package/template/{__dot__rulesync/rules/db-conventions.md → docs/standards/database.md} +15 -21
  39. package/template/docs/standards/enforcement.md +12 -0
  40. package/template/docs/standards/errors.md +26 -0
  41. package/template/docs/standards/frontend.md +60 -0
  42. package/template/docs/standards/functions.md +38 -0
  43. package/template/docs/standards/git-delivery.md +16 -0
  44. package/template/docs/standards/module-structure.md +37 -0
  45. package/template/docs/standards/testing.md +48 -0
  46. package/template/docs/standards/types.md +31 -0
  47. package/template/package.json.tpl +4 -4
  48. package/template/rulesync.jsonc +1 -1
  49. package/template/turbo/generators/config.ts +1 -1
  50. package/template/turbo.json +14 -2
  51. package/template/__dot__rulesync/skills/code-review/SKILL.md +0 -111
  52. package/template/apps/api/src/migrate.ts.tpl +0 -46
@@ -0,0 +1,90 @@
1
+ ---
2
+ root: false
3
+ targets:
4
+ - '*'
5
+ globs:
6
+ - '**/*'
7
+ description: Engineering code conventions (TS, DB, frontend, testing, git) - the always-on core, with a routing table to full detail in docs/standards/.
8
+ ---
9
+
10
+ # Engineering conventions
11
+
12
+ The always-on core of the code standard: what you must obey while typing. Detail, examples, and
13
+ rationale live in `docs/standards/` - read the one file that matches the change instead of
14
+ carrying all of it. The enforced import graph lives in `oss-boundaries`; Playwright rules in
15
+ `e2e-conventions`.
16
+
17
+ | Change you are making | Read first |
18
+ | ------------------------------------- | ------------------------------------ |
19
+ | schema, type, enum-like value set | `docs/standards/types.md` |
20
+ | function, service method, constructor | `docs/standards/functions.md` |
21
+ | new package, overlay, module layout | `docs/standards/module-structure.md` |
22
+ | a comment or JSDoc | `docs/standards/comments.md` |
23
+ | error class, catch, money path | `docs/standards/errors.md` |
24
+ | a test | `docs/standards/testing.md` |
25
+ | commit, PR | `docs/standards/git-delivery.md` |
26
+ | a failing gate, a new lint rule | `docs/standards/enforcement.md` |
27
+ | React/UI component, page, styling | `docs/standards/frontend.md` |
28
+ | SQL, Drizzle, migration, seed | `docs/standards/database.md` |
29
+
30
+ `docs/standards/frontend.md` doesn't apply to a headless/api-only repo - delete it (and its row
31
+ above) if this repo has no UI apps.
32
+
33
+ ## Philosophy
34
+
35
+ - Functional and declarative: pure functions, immutable data, composition. No stateful classes, no
36
+ imperative accumulation loops.
37
+ - Explicit over magic: no decorators, no auto-discovery, no reflection. Every wiring point is a
38
+ greppable typed call (`ctx.provide(TOKEN, factory)`).
39
+ - Self-documenting: clear names beat comments (`percentChange`, not `d` + a comment).
40
+ - YAGNI then DRY: don't build for imagined futures; abstract on the third occurrence, not the
41
+ first.
42
+ - Boring and consistent: match the surrounding code's idiom, naming, and density.
43
+
44
+ ## Never (lint-enforced unless noted)
45
+
46
+ - `any` outside tests, `!` non-null assertions, `as` casts to silence the compiler (`as const` is
47
+ fine).
48
+ - `interface`, TS `enum`, decorators, inheritance for reuse, default exports (exceptions:
49
+ `*.config.*`, `plugin.ts`, Next.js App Router files).
50
+ - Hand-written duplicates of an inferrable type, re-inferring an imported schema, re-typing
51
+ derived schema fields, ad-hoc/duplicated Zod schemas outside a module's `contract/`.
52
+ - Re-exporting types "to be nice" - import from where defined.
53
+ - Inline `fetch`/`axios` in module code - third-party access is a port + adapter bound at the
54
+ composition root.
55
+ - Deep (`../../`+) relative imports that leave your module/zone, imports of another module's
56
+ internals, import cycles, deep `dist/`/`src/` paths into another package.
57
+ - SQL anti-patterns (bare `timestamp()`, CamelCase identifiers, hand-edited migrations) - detail
58
+ in `docs/standards/database.md`.
59
+
60
+ ## Always
61
+
62
+ - **Naming:** files `kebab-case.ts`, one concept per file, filename names the concept
63
+ (`wallet.service.ts`, never `helpers.ts`); types `PascalCase`; values/functions `camelCase`;
64
+ true global constants `SCREAMING_SNAKE_CASE`; Zod schemas `<Name>Schema` with inferred type
65
+ `<Name>`; booleans read as predicates (`isActive`, `canEdit`); money is a decimal string plus a
66
+ `currency` field alongside it, never `amountCents`.
67
+ - **One source of truth per shape** - infer, never hand-write: `z.infer<typeof XSchema>`,
68
+ `typeof x.$inferSelect`. Full detail: `docs/standards/types.md`.
69
+ - **Literal config arrays/objects (option lists, key sets) use `as const`**, not an explicit union
70
+ type annotation - let TypeScript infer the literal types.
71
+ - **Schema-first at every boundary** (HTTP, config, env, events); validate once at the edge, trust
72
+ the type after.
73
+ - **Entity ids typed through their owning type** (`playerId: Player['id']`), never a bare
74
+ `string`.
75
+ - **Guard clauses first, main path last; more than 3 params -> one named object.** Detail:
76
+ `docs/standards/functions.md`.
77
+ - **Construct objects by spread + override**, never a hand-copied field list.
78
+ - **Side effects at the edges**; money paths are transactional AND idempotent (a DB guard inside
79
+ the transaction, not just an idempotency key). Detail: `docs/standards/errors.md`.
80
+ - **Typed, named error classes** from the shared factories, mapped to transport in the router's
81
+ `mapErrors`.
82
+ - **Pin exact dependency versions** (no `^`/`~`); add a dependency deliberately - std lib or a few
83
+ lines often beat a tree.
84
+ - **Test at the outermost tier that reaches the behaviour:** a UI journey -> browser E2E; an API
85
+ route, an overlay, a vendor adapter, anything with SQL -> API E2E against real Postgres with the
86
+ vendor stubbed at its HTTP boundary; a pure function -> a co-located unit test in `__tests__/`.
87
+ Never fake a query builder and never let a spy assertion be the point of a test; always cover
88
+ authz negatives. Detail: `docs/standards/testing.md`.
89
+ - **Green before review:** `pnpm verify` passes. Conventional commits, lowercase subject, one PR
90
+ per concern. Never push without explicit confirmation. Detail: `docs/standards/git-delivery.md`.
@@ -0,0 +1,48 @@
1
+ ---
2
+ root: false
3
+ targets:
4
+ - '*'
5
+ globs:
6
+ - 'apps/e2e/**'
7
+ description: Playwright E2E conventions - specs run against the real stack; mocking is a narrow, justified exception.
8
+ ---
9
+
10
+ # E2E conventions (`apps/e2e`)
11
+
12
+ Two kinds of spec live here:
13
+
14
+ - **Browser specs** (`tests/<app>/**`) - a player or admin journey through the UI.
15
+ - **API specs** (`tests/api/**`) - the `api` Playwright project: no browser, no `page`. Drives the real API over HTTP against real Postgres, with each external vendor replaced by a stub HTTP server the API is pointed at by env. This is the tier that proves an overlay end to end: request -> route -> service -> rows -> webhook -> resulting state. `USE_MOCKS` does not apply here at all.
16
+
17
+ ## Real stack by default
18
+
19
+ Every spec runs against the real seeded stack - API, Postgres, and the apps under test - and that
20
+ run is what blocks merge. A test that never executes the backend cannot tell you the backend works.
21
+
22
+ `USE_MOCKS=true` intercepts responses in the browser and exists only for a state you cannot produce
23
+ for real: a third-party widget or redirect you are not allowed to run in CI. It is an exception you
24
+ justify per spec, never the mode a suite is written for. Anything reachable by seeding data or by
25
+ scripting a vendor stub is NOT such a state - script the stub instead, and prefer the API tier when
26
+ the behaviour under test is the backend's.
27
+
28
+ Existing mocked specs are converted as they are touched; delete the fixture with the last spec that
29
+ used it.
30
+
31
+ ## Rules
32
+
33
+ - Import `test`/`expect` from `fixtures.ts`, NEVER from `@playwright/test` - fixtures add `cleanup()` and shared setup.
34
+ - Set up state through the product: seed data or drive the API, so the spec exercises the same path a player would. `mockApi(page, routes)` (from `lib/mocks.ts`) is the escape hatch above - reach for it only after the real setup is genuinely impossible, and never branch test logic on the mode.
35
+ - A mock that stays is typed: fixture shapes in `mocks/<domain>.ts` mirror the response contract - type platform-endpoint fixtures with the `z.infer` contract type from `@openora/*` so a contract change fails typecheck. No loose hand-written JSON.
36
+ - Selectors use `data-testid` - kebab-case, domain-prefixed (`chat-message`, `chat-input`). Never assert on CSS classes or component-library structure; shared UI components spread props so `data-testid` passes through.
37
+ - Page objects in `pages/<name>.page.ts` are functional factories - no classes, no `this`; locators + actions returned as a plain object.
38
+ - Test names are behavioural: "shows masked standings", not "table renders".
39
+ - `cleanup(fn)` reverses any data a test creates (runs in reverse order) - the suite shares one database, so a spec that leaks rows breaks the next one.
40
+ - Layout: `tests/<app>/<domain>/<scenario>.spec.ts` (one Playwright project per app, sharing fixtures/mocks/pages; run one with `--project=<app>`), `mocks/<domain>.ts`, `pages/<name>.page.ts`.
41
+
42
+ ## API specs (`tests/api/**`)
43
+
44
+ - Use `request` (Playwright's APIRequestContext), never `page`. Assert status, body, and the state a follow-up request reports - not internals.
45
+ - A vendor stub is a plain `node:http` server under `apps/e2e/`, modelled on `mock-identity-server.mjs`: it answers only the vendor endpoints the flow reaches and records the calls a spec asserts on. Point the API at it with the vendor's base-URL env var; every vendor adapter must accept one.
46
+ - Drive the vendor's inbound side the way the vendor does - post the real webhook shape to the real route with a signature the stub's key material produces. Never call the adapter directly.
47
+ - Own your data: create the player the spec needs and reverse it with `cleanup(fn)`. The suite shares one database.
48
+ - Layout: `tests/api/<domain>/<scenario>.spec.ts`.
@@ -0,0 +1,31 @@
1
+ ---
2
+ root: false
3
+ targets:
4
+ - '*'
5
+ globs:
6
+ - '**/*'
7
+ description: OSS core is read-only; enforced import/module boundaries.
8
+ ---
9
+
10
+ # OSS core + import boundaries
11
+
12
+ ## Never modify OSS core
13
+
14
+ `@openora/*` is a third-party dependency - read it for reference, never write to it.
15
+
16
+ - Do NOT edit `node_modules/**` or a linked OSS checkout. Those paths are write-denied in `.claude/settings.json`; don't route around it with `sed`, redirection, or scripts. A patched dependency is lost on reinstall and diverges from the published package.
17
+ - Extend from the OUTSIDE only: overlay plugins, adapter rebindings, UI plugins, config.
18
+ - If something can only be fixed in core, STOP and report it upstream (problem, expected behavior, likely location).
19
+
20
+ ## Import boundaries (enforced)
21
+
22
+ Enforced by `pnpm check:lint` (oxlint, per-edit), `pnpm check:boundaries` (dependency-cruiser, whole graph), the pre-commit hook, CI, and the agent PostToolUse hook. Fix the import, never work around a violation.
23
+
24
+ - No deep OSS imports: `@openora/*/src/*` or `/dist/*` - import only the published entrypoint or subpath export.
25
+ - No deep imports into your own shared packages - only the barrel/index entrypoint.
26
+ - No app-to-app imports (`apps/api` <-> `apps/web` <-> `apps/backoffice`) - extract shared code to `packages/*`.
27
+ - No cross-module imports inside an app - go through the module barrel, a query invalidation, or a domain event.
28
+ - No overlay-to-overlay imports - couple via a command port, a domain event, or a shared contract.
29
+ - No import cycles.
30
+
31
+ `pnpm check:boundaries:graph` renders the graph (needs Graphviz).
@@ -14,10 +14,16 @@ this repo. Every per-tool instruction file (`AGENTS.md` - shared, also Codex's b
14
14
  subagent and command mirrors are generated by
15
15
  [rulesync](https://github.com/dyoshikawa/rulesync) from the single source in `.rulesync/`
16
16
  (`rules/`, `subagents/`, `commands/`, `mcp.json`). Edit the source under `.rulesync/`, then
17
- run `pnpm sync:agents`. Do not hand-edit the generated files.
17
+ run `pnpm gen:agents`. Do not hand-edit the generated files.
18
18
 
19
19
  This repo is a downstream igaming operator built on the OSS platform (`@openora/*`).
20
20
 
21
+ Sibling rules (load on demand; don't reopen settled questions):
22
+
23
+ - `conventions` - the always-on code standard (naming, types, functions, package structure, errors, testing, git, frontend, DB), with a table routing each kind of change to its deep-dive file in `docs/standards/`.
24
+ - `oss-boundaries` - OSS core is read-only; enforced import/module boundaries.
25
+ - `e2e-conventions` - dual-mode Playwright specs, fixtures, mocks, page objects.
26
+
21
27
  ## HARD RULE: never modify OSS core
22
28
 
23
29
  `@openora/*` is a third-party dependency - treat it like any published npm package. You may READ it for reference, never write to it.
@@ -72,6 +78,8 @@ Delegate work to these scoped agents - the `start` / `enhance-intent` playbooks
72
78
  - `builder` - senior fullstack engineer. Implements overlays, swaps adapters, mounts UI pages.
73
79
  - `qa` - writes/runs Playwright E2E tests; triages whether a bug is in OSS core (upstream) or your overlay (local fix).
74
80
  - `debugger` - root-causes failures, build-time (Next/Turbopack, tsc, module resolution) and runtime (Chrome DevTools: console/network/DOM). Spawn it whenever something errors or behaves wrong; it finds the cause and routes the fix.
81
+ - `quality-reviewer` - reviews a diff: boundaries, conventions, frontend rules, perf, duplication. Findings only.
82
+ - `security-reviewer` - reviews a diff: authz, secrets/PII, money paths, input validation. Findings only.
75
83
 
76
84
  This repo consumes OSS core as linked packages - never edit `@openora/*` source. If a bug is in core, report it upstream; extend from the outside via plugins.
77
85
 
@@ -86,7 +94,6 @@ This server reads the platform CATALOG (not OSS source) - it tells you what exis
86
94
  - `list-adapters` - vendor swap seams (interface + token + status)
87
95
  - `list-routes [module]` - oRPC route namespaces
88
96
  - `list-events` - cross-module domain events you can subscribe to
89
- - `list-slots` - named UI slots you can fill from a UI plugin
90
97
  - `describe-module <name>` - one module's group, tables, routes
91
98
  - `schema-get <name>` - locate a Zod contract schema's file
92
99
  - `get-config-schema` - the igaming-config fields a consumer can set
@@ -4,7 +4,7 @@ name: add-feature
4
4
  description: >
5
5
  Deliver a feature end-to-end in this consumer repo. Aggregates context (Jira + Confluence + Slack +
6
6
  Google Drive + Notion + local docs + past sessions + codebase), produces an approved plan, then drives
7
- delivery by calling sibling skills - create-plugin (build), code-review (review), create-pr (MR) -
7
+ delivery by calling sibling skills - create-plugin (build), review, create-pr (MR) -
8
8
  and create-task for ticket hygiene. Transitions Jira (no comments) and drafts a one-line Slack
9
9
  notice. Use on "add feature", "plan <KEY>-XXX", "deliver <KEY>-XXX", or /add-feature [<KEY>-XXX].
10
10
  Read-only until the plan is approved; never pushes, transitions Jira, or sends Slack without OK.
@@ -33,7 +33,7 @@ re-implement their work. The platform-core twin is the `/add-feature` skill in t
33
33
  - **Read-only until the Step 3 plan is approved.** No edits, commits, pushes, Jira writes, or Slack
34
34
  sends before sign-off.
35
35
  - Reuse sibling skills, don't reinvent: **create-task** (ticket format), **create-plugin** (build an
36
- overlay), **code-review** (review), **create-pr** (MR). Delegate code to subagents.
36
+ overlay), **review** (review), **create-pr** (MR). Delegate code to subagents.
37
37
 
38
38
  ## Steps
39
39
 
@@ -82,7 +82,7 @@ When implementation starts, transition Jira to In Progress (Step 7 - confirm fir
82
82
 
83
83
  ### 5. Review + tests
84
84
 
85
- - Run **code-review** on the change set; loop `[BLOCK]`/`[WARN]` fixes back through `builder`.
85
+ - Run **review** on the change set; loop `[BLOCK]`/`[WARN]` fixes back through `builder`.
86
86
  - Run `/check` (typecheck + lint). Don't proceed on red.
87
87
  - Derive an e2e checklist from the AC (happy path, edge cases, authz negatives, error states), then
88
88
  `qa`: write/run the E2E specs, drive `chrome-devtools` on failure.
@@ -13,7 +13,7 @@ description: >
13
13
 
14
14
  The platform is extended from the **outside only** (overlay plugin / adapter rebind / UI page /
15
15
  config) - never by editing `@openora/*`. This skill picks the correct seam and scaffolds it.
16
- Domain questions go to `expert` first; review the result with `code-review`.
16
+ Domain questions go to `expert` first; review the result with `review`.
17
17
 
18
18
  ## 1. Classify the seam (ask if unclear)
19
19
 
@@ -30,9 +30,9 @@ Hand off via the `add-feature` skill's `handoff.md`. Do not patch the linked OSS
30
30
  ## 2. Ground first
31
31
 
32
32
  - Read `.claude/rules/overview.md` (what you may and may not touch) and
33
- `.claude/rules/db-conventions.md` (if the extension owns tables).
33
+ `docs/standards/database.md` (if the extension owns tables).
34
34
  - Inspect what already exists with the `oss` MCP: `catalog-overview`, `list-adapters` (token +
35
- default binding to swap), `list-routes` (collision check), `list-slots`, `list-events`.
35
+ default binding to swap), `list-routes` (collision check), `list-events`.
36
36
  - For a domain rule you can't safely assume (a limit, a KYC threshold, a jurisdiction behavior),
37
37
  spawn `expert` before scaffolding.
38
38
 
@@ -54,8 +54,8 @@ plugins: [myCustomPspAdapter, walletModule];
54
54
 
55
55
  - **Boundaries**: import only package entrypoints (`@openora/core`, not `.../src` or `.../dist`).
56
56
  No imports between extensions; cross-extension data goes through the oRPC client or a schema subpath.
57
- - **Tables**: live in the overlay's own `src/schema/index.ts`; follow `db-conventions` (snake_case,
58
- `timestamp({ withTimezone: true })`). Run `pnpm db:migrate` after.
57
+ - **Tables**: live in the overlay's own `src/schema/index.ts`; follow `docs/standards/database.md`
58
+ (snake_case, `timestamp({ withTimezone: true })`). Run `pnpm db:migrate` after.
59
59
  - **Audit every mutation**: each state-changing action emits a domain event the `audit` add-on
60
60
  subscribes to, or resolves `AUDIT_WRITER` and calls `record(...)`. A mutation with no audit is not done.
61
61
  - **Validate at the edge**: Zod schemas for every route input/output; no inline `fetch`/SQL in handlers.
@@ -64,7 +64,7 @@ plugins: [myCustomPspAdapter, walletModule];
64
64
 
65
65
  - `/check` (typecheck + lint) green.
66
66
  - Plugin boots (API health check / `pnpm dev`).
67
- - Hand to `code-review` before opening an MR.
67
+ - Hand to `review` before opening an MR.
68
68
 
69
69
  ## Rules
70
70
 
@@ -31,7 +31,7 @@ If the current branch isn't in the table, target `dev`.
31
31
  3. **Commit.** Conventional-commit message (`feat:`, `fix:`, `docs:`, `refactor:`,
32
32
  `chore:`); for ticket work prefix the ticket key (e.g. `feat(<KEY>-123): ...`).
33
33
  4. **Verify before pushing** (cheap insurance): run the repo's check (e.g.
34
- `pnpm typecheck && pnpm lint`). Don't push a red tree.
34
+ `pnpm check:types && pnpm check:lint`). Don't push a red tree.
35
35
  5. **Push** the current branch - but STOP and get an explicit per-action "yes push"
36
36
  from the user FIRST. Report the commit SHA, then ask. Invoking this skill is NOT
37
37
  push authorization. Pushing to a shared/env branch (`dev`, `stage`, `prod`)
@@ -0,0 +1,58 @@
1
+ ---
2
+ name: create-ui-module
3
+ targets: ['*']
4
+ description: >
5
+ Create a frontend feature module in apps/backoffice or apps/web following ADR-0001's
6
+ modular architecture: standard folder shape, co-located locales, DI hooks, pure
7
+ components, barrel entry, route wiring. Use on "create module", "new feature module",
8
+ "add a backoffice/web module", "/create-ui-module <app> <name>".
9
+ ---
10
+
11
+ # create-ui-module (consumer)
12
+
13
+ Scaffold a feature module under `src/modules/<name>/` per ADR-0001 (`docs/adr/0001-modular-architecture.md`). The shape is lint-enforced (`tools/oxlint-module-structure.mjs`: folder structure, `use-` hook naming, kebab-case files, client-component naming). Copy an existing module as the reference - `apps/backoffice/src/modules/roles/` is canonical.
14
+
15
+ ## 1. Resolve input
16
+
17
+ `<app> <name>` from `$ARGUMENTS` (`backoffice` | `web`, kebab-case name). Ask if missing. Confirm the module doesn't exist and the concern isn't already owned by another module.
18
+
19
+ ## 2. Create the shape
20
+
21
+ ```
22
+ src/modules/<name>/
23
+ pages/<name>-page.tsx page entrypoint(s)
24
+ components/ presentational only - props in, JSX out
25
+ hooks/use-<x>.ts ALL logic/queries/mutations; deps passed as parameters
26
+ utils/ local helpers (only if needed)
27
+ locales/en.json translation keys
28
+ locales/index.ts registration (below)
29
+ index.ts public barrel - the ONLY entry other code may import
30
+ ```
31
+
32
+ `locales/index.ts` pattern (exact):
33
+
34
+ ```ts
35
+ import { registerTranslations } from '@<scope>/ui';
36
+ import en from './en.json';
37
+
38
+ export const locales = { en };
39
+ export const ns = registerTranslations('<name>', locales);
40
+ ```
41
+
42
+ Components use `useTranslation(ns)`; no hardcoded copy. Non-`en` files mirror `en.json` keys exactly.
43
+
44
+ ## 3. Wire the route
45
+
46
+ - backoffice: `src/routes/_authed/<name>.tsx` -> `createFileRoute` with `component` imported from `@/modules/<name>` (see `src/routes/_authed/roles.tsx`).
47
+ - web: the App Router page under `app/(shell)/<name>/` imports from `@/modules/<name>`; client components get `'use client'` line 1 + `.client.tsx` suffix.
48
+
49
+ ## 4. Non-negotiables
50
+
51
+ - No cross-module imports - cross-module effects go through query cache invalidation, never a direct import.
52
+ - Outside code imports ONLY the barrel via `@/modules/<name>`; inside the module use relative paths.
53
+ - Hooks take their clients (oRPC/API) as parameters (see `roles/hooks/use-iam-client-deps.ts`) so they're testable without global mocks.
54
+ - Follow `docs/standards/frontend.md` (daisyUI, theme tokens, hoisted `styles` const, React Compiler - no manual memo).
55
+
56
+ ## 5. Verify
57
+
58
+ `/check` green (the structure lint runs inside `pnpm check:lint`); route renders (`pnpm dev`). Hand to `review` before an MR.
@@ -0,0 +1,94 @@
1
+ ---
2
+ name: handoff
3
+ description: >
4
+ Package the current task into a self-contained prompt another agent (a
5
+ teammate, or a fresh Claude session in another repo) can execute without this
6
+ conversation. Gathers context from the chat so far plus live repo/environment
7
+ state, then emits a copy-pasteable handoff. Use on "hand this off", "prompt for
8
+ another agent", "write a handoff", when routing an OSS-core change into the
9
+ platform repo, or /handoff [what to hand off | target agent/repo]. Produces a
10
+ copy-pasteable prompt and may use any tool to gather context; the one hard line
11
+ is never force-push.
12
+ allowed-tools:
13
+ - Read
14
+ - Grep
15
+ - Glob
16
+ - Write
17
+ - Edit
18
+ - Bash
19
+ disallowed-tools:
20
+ - Bash(git push --force:*)
21
+ - Bash(git push -f:*)
22
+ - Bash(git push --force-with-lease:*)
23
+ - Bash(git push --force-with-lease)
24
+ - Bash(git push -f)
25
+ ---
26
+
27
+ # handoff - write a self-contained prompt for another agent
28
+
29
+ Turn "what we're doing" into a prompt a _stranger_ agent can act on with zero access to this
30
+ chat. The receiver has none of our context, so the prompt must carry all of it.
31
+
32
+ Common use here: an OSS-core change this consumer can't make itself. The receiver is a teammate
33
+ (agent teams on) or a new Claude session rooted in the platform checkout (agent teams off) - see
34
+ the "Fixing something in OSS core" rule. Either way it needs a standalone brief.
35
+
36
+ Optional argument = what to hand off / who to (e.g. `the OSS core publish fix`, `to a teammate in
37
+ the platform repo`, a repo path, an issue/MR#). No argument -> hand off the current in-flight task.
38
+
39
+ ## Rules
40
+
41
+ - **One hard line: never force-push** (`git push --force` / `-f` / `--force-with-lease`), in any
42
+ repo, ever - it rewrites shared history. Every other tool is fair game. The skill's main output
43
+ is still the prompt; take further action (commit, push, spawn, launch) only on explicit confirmation.
44
+ - **Self-contained.** The receiver can't see this conversation. Inline every fact they need:
45
+ exact paths, branch/remote names, IDs (MR/PR/ticket), commands, versions, error strings.
46
+ No "as discussed", no "the file we changed", no unresolved pronouns.
47
+ - **Facts over memory.** Verify the moving parts against live state (git, files, CLIs) before
48
+ writing them - don't trust half-remembered branch names or versions.
49
+ - **No secrets.** Never inline tokens, passwords, or `.env` values. Reference the env var name.
50
+ - **Scope, don't dump.** Include what's load-bearing for the task; link/name the rest.
51
+
52
+ ## Step 1 - Resolve scope
53
+
54
+ From the argument + the conversation, state in one line: the goal, the target repo/dir, and (if
55
+ known) the agent type or persona best suited. If genuinely ambiguous, ask one clarifying question;
56
+ otherwise proceed with the obvious reading and note the assumption.
57
+
58
+ ## Step 2 - Gather live context
59
+
60
+ Pull only what the task touches (skip irrelevant ones):
61
+
62
+ - Repo/env: `pwd`; `git -C <dir> remote -v`; `git -C <dir> branch --show-current`;
63
+ `git -C <dir> status --short`; recent `git log --oneline -5`. Note default/target branch.
64
+ - Work state: relevant file paths (verify they exist), functions/symbols, versions/pins,
65
+ exact error messages or failing job names, IDs (MR/PR/ticket/pipeline).
66
+ - Conventions the receiver must follow: point at the repo's rules (`CLAUDE.md`,
67
+ `.rulesync/`, `AGENTS.md`) rather than restating them; call out any that bit us.
68
+ - What's already done vs. what remains (so they don't redo or undo work).
69
+
70
+ ## Step 3 - Emit the handoff
71
+
72
+ Output one fenced markdown block (so it copy-pastes cleanly), using these headings - drop any
73
+ that don't apply, never pad:
74
+
75
+ - **Task** - one imperative sentence: the outcome wanted.
76
+ - **Environment** - repo(s), absolute path(s), remote(s), current + target branch, sibling deps.
77
+ - **Background** - the why + current state + root cause/findings already established. This is
78
+ where prior investigation goes so it isn't repeated.
79
+ - **Do this** - ordered, concrete steps. Name files/symbols/commands. Mark decisions that need
80
+ a human ("report the plan first, don't push").
81
+ - **Verify** - the exact commands/gates that must pass, and the expected green result.
82
+ - **Constraints** - boundaries (read-only zones, "never push without explicit yes", conventional
83
+ commits, branch-off-target, don't touch X). Inherit the repo's rules; restate only the sharp edges.
84
+
85
+ After the block, in <=2 lines: state the key assumption you made, and offer to (a) tweak the
86
+ prompt, (b) save it to a file, or (c) launch it now (spawn a teammate with a suitable agent type,
87
+ or hand it to the operator to paste into a session rooted in the target repo). Only save or launch
88
+ on explicit confirmation.
89
+
90
+ ## Quality bar
91
+
92
+ A good handoff passes this test: **hand it to someone who has never seen this repo or chat, and
93
+ they can start in under a minute and finish without asking you anything.** If a step assumes
94
+ context the block doesn't contain, fix the block.
@@ -0,0 +1,111 @@
1
+ ---
2
+ name: review
3
+ targets: ['*']
4
+ description: Multi-agent code review of the working branch against this repo's conventions, OSS-core boundaries, frontend rules, security, and operator-domain fit. Fans out a configurable number of parallel reviewers, each grounded in the rule docs, then synthesizes one verdict. Use on "review this", "code review", "/review", optionally "--agents N", "--base <ref>", "--fix", "--post" (publish findings to the MR as inline comments + a summary verdict), "--yes" (post without confirming), a GitLab MR number, or paths.
5
+ ---
6
+
7
+ # review
8
+
9
+ You are the orchestrator: scope the diff, fan out N reviewers across dimensions, dedup findings, report ONE verdict. Report-only unless `--fix`.
10
+
11
+ Checklist - tick as you go:
12
+
13
+ ```
14
+ - [ ] 1. Parse args (--agents / --base / MR# / paths / --fix / --post / --yes)
15
+ - [ ] 2. Scope the diff; if empty, ask
16
+ - [ ] 3. Collect task context (ticket AC + MR discussion)
17
+ - [ ] 4. Pick applicable dimensions; small diff -> review inline, else spawn reviewers in ONE message
18
+ - [ ] 5. Dedup + apply the evidence gate
19
+ - [ ] 6. Report one verdict (+ apply fixes only if --fix)
20
+ - [ ] 7. Post to the MR as inline comments + summary (only if --post)
21
+ ```
22
+
23
+ ## 1. Parse `$ARGUMENTS`
24
+
25
+ - `--agents N` - parallel reviewers (1-5); default one per applicable dimension.
26
+ - `--base <ref>` - diff base; default `dev`.
27
+ - `<number>` - a GitLab MR: `glab mr diff <n>` for the patch, `glab mr view <n>` for intent.
28
+ - paths - restrict review to those files/dirs.
29
+ - `--fix` - apply BLOCK/WARN fixes after the review; default report-only.
30
+ - `--post` - publish findings to the GitLab MR as inline diff-line comments + a one-line summary verdict (§8). Requires an MR number. Draft-and-confirm by default.
31
+ - `--yes` - with `--post`, skip the confirmation and publish straight away.
32
+
33
+ ## 2. Scope the diff
34
+
35
+ `git diff <base>...HEAD --name-only`; if empty, fall back to `git status -s`; if still empty, ask. Group changed files by app/package so reviewers and any file-split share the same map. Note the total changed-line count - it picks the mode in §4.
36
+
37
+ ## 2b. Collect task context
38
+
39
+ Distill everything here into ONE context block of at most ~30 lines; it is the only task context reviewers receive.
40
+
41
+ - **Ticket.** Extract the BF key from the branch name / MR title. Fetch it (Atlassian MCP or REST) and distill: goal in one line + acceptance criteria as bullets. No key or no access: skip silently.
42
+ - **MR discussion.** If reviewing an MR: `glab mr view <n>` + unresolved discussion threads. Distill to stated intent + open reviewer asks, so the review doesn't repeat or contradict them. No MR: use branch commit subjects as intent.
43
+ - The AC bullets feed the verdict (§7) - a finding "AC not met" needs a specific bullet.
44
+
45
+ ## 3. Ground every reviewer (mandatory)
46
+
47
+ Each reviewer MUST read the changed code AND the rule docs owning its dimension before judging - never infer behavior from a diff hunk; if a finding depends on a called function, open it. Cite the docs in findings:
48
+
49
+ - `.claude/rules/conventions.md` - the always-on code standard, with a table routing to the deep-dive file in `docs/standards/`.
50
+ - `docs/standards/frontend.md` - React/UI rules (React Compiler, daisyUI, module isolation) when the diff touches a UI app or the shared UI package.
51
+ - `.claude/rules/oss-boundaries.md` - OSS core read-only; enforced import boundaries.
52
+ - `docs/standards/database.md` - SQL/Drizzle rules for overlay tables.
53
+ - `.claude/rules/workflow.md` + `.claude/rules/overview.md` - how this repo operates.
54
+
55
+ ## 4. Dimensions
56
+
57
+ Dimensions and the roster agent that owns each - never `general-purpose`:
58
+
59
+ 1. **Boundaries, conventions, frontend, perf, duplication** - `quality-reviewer` (its prompt carries the full lens checklists; always applicable).
60
+ 2. **Security & secrets** - `security-reviewer`; only if overlay routes, adapters, auth/session, env/config, or money-adjacent code changed.
61
+ 3. **Operator/domain fit** - `expert`; only if business logic changed AND AC exists to judge against.
62
+
63
+ **Small-diff fast path (<= 150 changed lines): no subagents.** Read the changed files in the main thread and apply the applicable agents' checklists yourself (they live in `.claude/agents/<name>.md` - skim, don't spawn). This is the common case and costs a fraction of a fan-out.
64
+
65
+ ## 5. Allocate to `--agents N` (large diffs only)
66
+
67
+ - N unset: one reviewer per applicable dimension.
68
+ - N > dimensions: extras are additional `quality-reviewer` instances split by file group (state the split; never silently drop files).
69
+ - N < dimensions: drop `expert` first, then merge security into quality (say so in the report).
70
+
71
+ Spawn all reviewers in a SINGLE message (parallel). Pass each: the changed-file list for its dimension (pre-grouped - reviewers never re-scope), the base ref, the §2b context block, and hard caps: read only changed files + immediate callees; max 10 findings; compact `[SEV] file:line - finding - evidence - fix` lines, no prose; do NOT run `/check`/tests.
72
+
73
+ ## 6. Evidence gate (cut false positives)
74
+
75
+ Every reviewer applies this before returning; re-apply it yourself when synthesizing:
76
+
77
+ - Every `[BLOCK]`/`[WARN]` cites a concrete `file:line` AND the rule doc violated - otherwise downgrade to `[INFO]` or drop.
78
+ - High-confidence findings only; unsure = downgrade or omit. Few actionable findings beat flooding.
79
+ - No invented runtime failures - state the trigger path or don't raise it.
80
+ - Don't duplicate what tooling enforces (oxlint, the `/check` gate); for a suspected lint/boundary issue say "confirm with `pnpm check:lint`" - flag only what the gates miss.
81
+
82
+ ## 7. Synthesize
83
+
84
+ Dedup by `file:line`, group by dimension, order BLOCK -> WARN -> INFO. Each line: `[SEV] file:line - finding - evidence - rule cited - fix`. Lead with a one-line summary (counts per severity + verdict); end with **APPROVED** / **CHANGES REQUESTED** + the single most critical finding.
85
+
86
+ Severities: `[BLOCK]` must fix before merge (core edit, boundary break, authz/secret/PII risk, broken extension wiring); `[WARN]` should fix (convention violation, missing test, weak validation); `[INFO]` FYI / hardening.
87
+
88
+ If `--fix`: apply BLOCK + WARN fixes in the working tree (smallest diff satisfying the cited rule), run `/check`, report green/red. Leave INFO untouched. Never commit or push.
89
+
90
+ ## 8. Post to the MR (`--post`)
91
+
92
+ Only when `--post` is set and the target is an MR number. Turns findings into terse review comments: one line each, brief why, backtick every identifier.
93
+
94
+ Post BLOCK + WARN as inline threads; include INFO only if it maps to a concrete `file:line`. One comment per finding, one line each.
95
+
96
+ 1. **Draft.** Rewrite each finding as a terse comment keyed to its `file:line`. Compose the summary as ONE sentence stating whether the changes block prod/push, e.g. `Not a blocker for push - a few cleanups worth doing.` or `Blocker: BLOCK finding in `x.ts` must be fixed before we push.`
97
+ 2. **Confirm.** Show all drafted comments + the summary and stop for approval - UNLESS `--yes`, then skip straight to posting.
98
+ 3. **Post inline comments** as positional discussions on the diff. Mechanics + gotchas are in the Notion memory `glab MR inline diff-line comments (positional discussions)` (query the Memories DB) - the short of it:
99
+ - Diff SHAs from `glab api "projects/consumer%2Fconsumer/merge_requests/<n>" | jq .diff_refs`.
100
+ - Anchor on the NEW-file line of an added (`+`) line (`git show <src-branch>:<file> | grep -n`).
101
+ - POST JSON (build with Python `json.dumps` to dodge quoting) to `.../merge_requests/<n>/discussions` with a `position` object; `glab api -H "Content-Type: application/json" ... --input -`. Do NOT use `-f "position[...]"` - nested params silently drop the position.
102
+ - Verify each response's `.notes[0].position.new_line`; if null it fell back to a general note - delete (`glab api -X DELETE .../notes/<id>`) and retry.
103
+ 4. **Post the summary** as one general MR note (`glab mr note <n> -m "<one sentence>"`).
104
+ 5. Report back the count posted + the summary verdict. Never resolve threads; never push.
105
+
106
+ ## Constraints
107
+
108
+ - Reviewers report; only the orchestrator edits, and only under `--fix` (working tree only - no commit, no push).
109
+ - NEVER edit `@openora/*` core or `node_modules`.
110
+ - Every finding cites a rule doc - no ungrounded opinions.
111
+ - Cap at 5 parallel reviewers.
@@ -46,17 +46,17 @@ my-igaming/
46
46
  2. Create `apps/api/src/extensions/<vendor>/plugin.ts`:
47
47
 
48
48
  ```ts
49
- import { definePlugin } from '@openora/plugin-host';
49
+ import type { CoreTokenCatalog, Plugin } from '@openora/core/server';
50
50
  import { KYC_ADAPTER } from '@openora/adapters';
51
51
  import { MyKycAdapter } from './src/my-kyc-adapter.js';
52
52
 
53
- export default definePlugin({
53
+ export default {
54
54
  id: 'my-kyc',
55
55
  dependsOn: ['identity'], // always load after the default-binding module
56
56
  register(ctx) {
57
57
  ctx.provide(KYC_ADAPTER, () => new MyKycAdapter());
58
58
  },
59
- });
59
+ } as const satisfies Plugin<CoreTokenCatalog>;
60
60
  ```
61
61
 
62
62
  3. Register it in `extensions.config.ts` AFTER the module that owns the default binding.
@@ -26,7 +26,7 @@ Reproduce deterministically with a build, not the dev server (dev caches aggress
26
26
 
27
27
  ```bash
28
28
  pnpm -C apps/web exec next build # or apps/backoffice
29
- pnpm typecheck
29
+ pnpm check:types
30
30
  ```
31
31
 
32
32
  Common consumer-side causes (this stack links `@openora/*` from a sibling checkout):
@@ -35,7 +35,6 @@ Common consumer-side causes (this stack links `@openora/*` from a sibling checko
35
35
  | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
36
36
  | `Module not found: Can't resolve '@openora/...'` but `node -e "require.resolve(...)"` works | A bundler won't compile across the link: boundary (packages live outside the project root) | point the bundler's project root at the common ancestor of your frontend repo and the OSS checkout, and allow imports from outside the root (eg Next.js `turbopack.root` + `experimental.externalDir: true`). |
37
37
  | `extends "@openora/tsconfig/..." doesn't resolve` | An `extends` chain through a symlinked tsconfig | the `@openora/tsconfig` configs must be self-contained (no `extends`) |
38
- | Resolves but won't import | `@openora/*` not built | run `pnpm build:oss` |
39
38
  | Stale error after a fix | Turbopack cache | `rm -rf apps/*/.next` and rebuild |
40
39
 
41
40
  To confirm a resolution issue is the bundler (not a missing dep):
@@ -23,7 +23,7 @@ The OSS platform is headless (API + modules only) - the player app and backoffic
23
23
  | Player app | http://localhost:3000 | operator |
24
24
  | Backoffice | http://localhost:3002 | operator |
25
25
 
26
- Seed credentials (after `pnpm seed`): `admin@oss.dev` / `password123`
26
+ Seed credentials (after `pnpm db:seed`): `admin@oss.dev` / `password123`
27
27
 
28
28
  Confirm actual ports and which UIs exist with the operator - they may have only an API, or a single combined app.
29
29