Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
203 commits
Select commit Hold shift + click to select a range
57a3383
feat!: GraphQL query service over relational read models
patrickleet Jul 11, 2026
579d991
fix: live GraphQL subscriptions + real phase 4/5 e2e
patrickleet Jul 11, 2026
d221260
feat(cli): distributed-graphql skill + scaffold --query-api
patrickleet Jul 11, 2026
9d28dde
test(cli): restore tracing scaffold unit test attribute
patrickleet Jul 11, 2026
104ef42
fix(cli): emit DATABASE_URL for query_api gitops + skill dry-run script
patrickleet Jul 11, 2026
820ad16
feat(graphql): GraphiQL playground example and local defaults
patrickleet Jul 11, 2026
26e5c4c
docs: project query-layer specification package to docs/
patrickleet Jul 12, 2026
616144d
docs: add query-layer desired-vs-current state tracker
patrickleet Jul 12, 2026
b8a761d
fix(graphql): harden P0/P1 query-layer security, AuthZ, metrics, tests
patrickleet Jul 12, 2026
146db8e
docs: ignore GraphQL README doctest snippet
patrickleet Jul 12, 2026
81e5d8c
test(graphql): column allowlist e2e + where max_depth rejection
patrickleet Jul 12, 2026
4080da0
docs: sync query-layer state after P0/P1 harden closeout
patrickleet Jul 12, 2026
87ad116
docs: remove projected query-layer package from code tree
patrickleet Jul 12, 2026
99ba8d9
test(graphql): prove introspection flag, SQLite TIMEOUT, prod GraphiQL
patrickleet Jul 12, 2026
06f4976
fix(graphql): deterministic statement_timeout proof for harden-13
patrickleet Jul 12, 2026
0a751b1
fix: resolve GraphQL query service review comments
patrickleet Jul 12, 2026
566fbe1
test(graphql): red-team harden suite + by_pk claim/null fixes
patrickleet Jul 12, 2026
b17d834
fix(graphql): restore by_pk projection-first bind order for nested se…
patrickleet Jul 12, 2026
1bbc569
refactor(graphql): dedup join predicates, DialectOps, apply_binds
patrickleet Jul 12, 2026
dcf37af
feat(graphql): quality-2 do-now security and ops slice
patrickleet Jul 12, 2026
574da06
feat(graphql): strict_where default true (fail-closed filters)
patrickleet Jul 12, 2026
fccbbdf
feat(graphql): dialect-honest comparison operator surface
patrickleet Jul 12, 2026
0d340fc
feat(graphql): nested selection complexity weights
patrickleet Jul 12, 2026
e30623e
feat(graphql): ship identity modes + OIDC Bearer (F1–F10)
patrickleet Jul 12, 2026
f92ea5a
fix(graphql): public scaffold always OidcBearer (D6, never DevHeaders)
patrickleet Jul 12, 2026
64b1c4b
ci: run GraphQL identity + Zitadel OIDC e2e on PRs and main
patrickleet Jul 12, 2026
fe19e5e
fix(ci): make Zitadel OIDC e2e work via docker compose (local + GHA)
patrickleet Jul 12, 2026
9e5da82
fix(ci): wait for Zitadel management API before bootstrap (503 race)
patrickleet Jul 12, 2026
cb5db6b
feat(graphql): multi-provider OIDC e2e (Keycloak, Authentik, Okta)
patrickleet Jul 12, 2026
82ba1da
fix(ci): preserve Zitadel FirstInstance key across re-bootstrap
patrickleet Jul 12, 2026
2c9bcc1
fix(graphql): honest OIDC E1 isolation + E5 expiry; IdP role claims
patrickleet Jul 12, 2026
a0e3065
chore(graphql): drop Okta OIDC e2e adapter (SaaS-only)
patrickleet Jul 12, 2026
dd4ff55
feat(tests): workshop multi-crate domain fixture with monolith/multi …
patrickleet Jul 13, 2026
5d01ae9
feat(tests): replace workshop fixture with e2e-ui + GraphQL WS chat
patrickleet Jul 13, 2026
b5d440f
fix(graphql): raise depth/complexity when GraphiQL is enabled
patrickleet Jul 13, 2026
e6c2b03
fix(graphql): make GraphiQL subscriptions work over WebSocket
patrickleet Jul 13, 2026
890f64c
feat(e2e-ui): OIDC+Postgres Docker template with SSR and WS Bearer auth
patrickleet Jul 13, 2026
f534784
fix(e2e-ui): fail closed on OidcBearer command identity spoofing
patrickleet Jul 13, 2026
b1d8313
feat(e2e-ui): remake home as Distributed framework template landing
patrickleet Jul 13, 2026
ff2894c
feat(e2e-ui): neutral wireframe home with CQRS architecture samples
patrickleet Jul 13, 2026
405ef12
feat(e2e-ui): unidirectional story home, Zitadel login stack, SSR polish
patrickleet Jul 14, 2026
9686e46
feat(e2e-ui): expose todos_create command mutation (owner-scoped)
patrickleet Jul 14, 2026
ef2f0a8
feat(e2e-ui): GraphQL-only public API — no HTTP command routes
patrickleet Jul 14, 2026
b4a26b8
fix(e2e-ui): clean env quoting and clearer GraphQL 401s
patrickleet Jul 14, 2026
b805e9c
fix(e2e-ui): preserve AUTH_SECRET across make up
patrickleet Jul 14, 2026
01e7960
fix(e2e-ui): always mint fresh login-client PAT
patrickleet Jul 14, 2026
4fbdb25
feat(e2e-ui): browser GraphQL mutations with shared documents
patrickleet Jul 14, 2026
c148704
docs(e2e-ui): SvelteKit GraphQL DX spec + unified request client pilot
patrickleet Jul 14, 2026
205102b
docs(e2e-ui): component-colocated GraphQL “decorator” DX
patrickleet Jul 14, 2026
9116c4b
docs(e2e-ui): move design specs to GitKB
patrickleet Jul 14, 2026
ac660d3
feat(e2e-ui): defineResource co-located GraphQL ops for todos
patrickleet Jul 14, 2026
c707d44
feat(e2e-ui): co-locate chat GraphQL resource (query/sub/post)
patrickleet Jul 14, 2026
0bb5f67
feat(e2e-ui): Houdini-inspired .gql files + GraphQL codegen
patrickleet Jul 14, 2026
dbd0ac1
feat(e2e-ui): export role user SDL from GraphQL engine for UI codegen
patrickleet Jul 14, 2026
9bc9e99
refactor(e2e-ui): DRY GraphQL auth headers, env cleaning, page wiring
patrickleet Jul 14, 2026
d5c7095
feat(e2e-ui): admin all-owners todos example (role-scoped RLS)
patrickleet Jul 14, 2026
8be0d69
feat(e2e-ui): admin-only todos_force_archive GraphQL mutation
patrickleet Jul 14, 2026
e4c53fe
refactor(e2e-ui): gate force_archive session checks in command guard
patrickleet Jul 14, 2026
884da20
refactor(e2e-ui): require session user in all command guards
patrickleet Jul 14, 2026
28cdc4e
feat(e2e-ui): complete hardening epic — security tests, DRY, CI, bounds
patrickleet Jul 14, 2026
03a7bd7
test(e2e-ui): exercise GraphQL todos_reopen for non-owner IDOR
patrickleet Jul 14, 2026
918f2c6
fix: address GraphQL hardening review comments
patrickleet Jul 14, 2026
934f146
fix: avoid negative GraphQL pagination wrap
patrickleet Jul 14, 2026
2c4edde
fix: resolve m2m permission join columns
patrickleet Jul 14, 2026
4c3a436
chore: gitignore ATC prefetch cache and make PID files
patrickleet Jul 14, 2026
ea81ce3
fix: support ES256 OIDC JWKS keys
patrickleet Jul 14, 2026
e8138be
fix: clean up review verification failures
patrickleet Jul 14, 2026
3ea3bff
docs: expand README GraphQL query service coverage
patrickleet Jul 14, 2026
1adb767
feat(e2e-ui): command client — typed TS functions over GraphQL wire
patrickleet Jul 14, 2026
c2f3dfe
feat(e2e-ui): use generated command client for all write call sites
patrickleet Jul 14, 2026
90483d4
feat(e2e-ui): command docs in operations.gql; functions take bound cl…
patrickleet Jul 14, 2026
2d16106
fix(e2e-ui): restore authFromPageData for chat WebSocket subscribe
patrickleet Jul 14, 2026
8712936
feat(e2e-ui): gql.subscribe on bound client (shared HTTP auth)
patrickleet Jul 14, 2026
a56548e
feat(e2e-ui): register commands on GraphQL client as gql.commands.*
patrickleet Jul 14, 2026
6c00337
refactor!: clearer GraphQL read-permission API (grant/read/rows)
patrickleet Jul 15, 2026
664c738
test: close pre-GA gaps — subs claim isolation, m2m client where, err…
patrickleet Jul 15, 2026
ad893f1
fix: emit extensions.code for command and empty-role GraphQL errors
patrickleet Jul 15, 2026
4f91095
chore: remove docs/ tree; framework guides live in GitKB
patrickleet Jul 16, 2026
c23de0a
chore: point README and skills at GitKB instead of docs/
patrickleet Jul 16, 2026
dd922f8
docs: make README self-sufficient (no docs/ or GitKB links)
patrickleet Jul 16, 2026
4166c23
feat(graphql): surface IR, command pipeline cache, projection return …
patrickleet Jul 16, 2026
521b084
feat(e2e-ui): migrate todos/chat/admin to command pipeline + QueryCache
patrickleet Jul 16, 2026
61f81e8
refactor(e2e-ui): Houdini-style gql.store/live — cache is transparent
patrickleet Jul 16, 2026
7697fa7
fix(e2e-ui): document store refetch writes cache without client write…
patrickleet Jul 16, 2026
9e7eba8
fix(e2e-ui): Svelte 5 syntax hygiene across the template
patrickleet Jul 16, 2026
3226a90
fix(e2e-ui): navbar Create account + Sign in (not two Sign Ins)
patrickleet Jul 16, 2026
44ff684
fix(e2e-ui): clear errors when Zitadel down; enable allowRegister on …
patrickleet Jul 16, 2026
807c560
fix(e2e-ui): no immediate post-command refetch (archive flicker)
patrickleet Jul 16, 2026
627a4a6
feat(graphql): systems-harden client integrity, role SDL, red-team units
patrickleet Jul 17, 2026
bd6e7ef
feat(graphql): prega residual — IR grants/runtime, export dual-check,…
patrickleet Jul 17, 2026
136d902
fix(e2e-ui): C-U18 identity key uses JWT sub not header prefix
patrickleet Jul 17, 2026
9bddb07
feat(e2e-ui): blob game, Zitadel ingress/scrape, and auth_users joins
patrickleet Jul 19, 2026
b88de71
feat(e2e-ui): polish demos, event domains, blob URL routes
patrickleet Jul 20, 2026
675c5ab
fix(e2e-ui): wait for move confirms before blob next level
patrickleet Jul 20, 2026
c9a72f1
fix(e2e-ui): restore todo/chat event wire formats
patrickleet Jul 20, 2026
d9fddf6
fix(e2e-ui): drop fake board from blob empty state
patrickleet Jul 20, 2026
0a9a1e3
test(e2e-ui): add Playwright browser e2e suite
patrickleet Jul 20, 2026
a9a78e5
ci: run e2e-ui offline suite and Playwright on PR/main
patrickleet Jul 20, 2026
51c9b1f
fix: green CI for e2e-ui HTTP surface, m2m where, blob start
patrickleet Jul 20, 2026
834cced
fix(e2e-ui): hydrate-safe blob start + align offline UI contracts
patrickleet Jul 20, 2026
ed7d590
feat: extract Distributed JS client package
patrickleet Jul 21, 2026
15ea103
feat: select normalized cache engine
patrickleet Jul 22, 2026
5aba603
feat: emit authorized client manifests
patrickleet Jul 22, 2026
88f09b1
chore: refresh e2e GraphQL artifacts
patrickleet Jul 22, 2026
ba208da
chore: refresh e2e command artifacts
patrickleet Jul 22, 2026
84866e1
feat: add normalized client replica
patrickleet Jul 22, 2026
8410d4a
feat: add typed causal command contracts
patrickleet Jul 22, 2026
6d85afe
feat: add durable causal command dispatch
patrickleet Jul 23, 2026
4694141
feat: harden causal projection protocol
patrickleet Jul 23, 2026
a0bfccb
feat: expose causal GraphQL client protocol
patrickleet Jul 23, 2026
4e20a83
feat: add unified client compiler foundation
patrickleet Jul 23, 2026
5359835
feat: harden client compiler contracts
patrickleet Jul 23, 2026
0ed6d47
feat: compile recursive client replica plans
patrickleet Jul 23, 2026
07f14f5
feat: complete compiler-backed client plans
patrickleet Jul 23, 2026
d4cfe35
docs: move durable decisions to distributed kb
patrickleet Jul 23, 2026
6b6fd86
feat: bind clients to authorization surfaces
patrickleet Jul 23, 2026
963afd5
fix: keep manifest validation test current
patrickleet Jul 23, 2026
9e31204
feat!: complete compiler-backed client replica
patrickleet Jul 24, 2026
b71dad2
fix: isolate GraphiQL introspection limits
patrickleet Jul 24, 2026
b82641a
fix!: split query authority from causal comparability
patrickleet Jul 24, 2026
201e826
fix: retain projection poll liveness
patrickleet Jul 24, 2026
6c6130d
fix: preserve stale replica views during revalidation
patrickleet Jul 24, 2026
f476ad8
fix: stabilize optimistic command feedback
patrickleet Jul 24, 2026
dfd7af5
fix: keep todo command controls visually stable
patrickleet Jul 24, 2026
d3e51be
fix: preserve optimistic order while revalidating
patrickleet Jul 24, 2026
d20e020
fix: fence stale revalidation after projected commands
patrickleet Jul 24, 2026
f74cf67
fix: retain projected rows until read-model echo
patrickleet Jul 25, 2026
27f4abb
feat: add direct-only projection owners
patrickleet Jul 25, 2026
4592a49
fix(cli): treat exact --documents paths as literal files (#136)
patrickleet Jul 25, 2026
a7a71eb
fix: enforce asserted roles in strict OIDC mode
patrickleet Jul 25, 2026
d79bfd1
fix: share expiring OIDC JWKS cache per engine
patrickleet Jul 25, 2026
20d7cc9
test: cover exact GraphQL document paths
patrickleet Jul 25, 2026
9045bea
fix: address GraphQL query service review findings
patrickleet Jul 25, 2026
953ace3
fix: keep projected fences against stale high-revision snapshots
patrickleet Jul 25, 2026
2d56722
fix: fence projected rows by response start
patrickleet Jul 26, 2026
d9103c8
docs: position Distributed as full-stack CQRS + GraphQL + JS
patrickleet Jul 26, 2026
1726753
docs: lead README with Fieldnote, Blob, and live demos
patrickleet Jul 26, 2026
06010ab
docs: highlight first-class OIDC and multi-IdP e2e
patrickleet Jul 26, 2026
eddf173
docs: lead demos with e2e-ui code index
patrickleet Jul 26, 2026
f76901e
docs(e2e-ui): refresh home walkthrough for latest patterns
patrickleet Jul 26, 2026
b740844
refactor(e2e-ui): nest CSS natively; keep postcss for custom-media
patrickleet Jul 26, 2026
8e0ba5c
revert(e2e-ui): undo CSS nesting rewrite
patrickleet Jul 26, 2026
7e3cdbd
refactor(e2e-ui): product components + split global CSS
patrickleet Jul 26, 2026
a471292
fix(e2e-ui): polish chat and blob after product shell migration
patrickleet Jul 26, 2026
8ddb6e8
fix(e2e-ui): read Zitadel project roles from access token
patrickleet Jul 26, 2026
b17a4b5
fix(e2e-ui): type-cast refreshed token when storing groups
patrickleet Jul 26, 2026
65a1a8d
fix(e2e-ui): always request Zitadel project role scopes at login
patrickleet Jul 26, 2026
517771f
fix(e2e-ui): let admin use the normal fieldnote app surface
patrickleet Jul 26, 2026
12a6d8f
refactor: split distributed-replica into folder modules
patrickleet Jul 26, 2026
e3d71d3
fix(e2e-ui): align Playwright with product shell and admin hydration
patrickleet Jul 26, 2026
c7c808e
refactor: split command-runtime into folder modules
patrickleet Jul 26, 2026
8167d7e
refactor: split cache-engine into folder modules
patrickleet Jul 26, 2026
8bb733b
refactor: split query-plan into filter/order/pagination modules
patrickleet Jul 26, 2026
344c9bd
refactor(js): extract shared helpers into src/lib
patrickleet Jul 26, 2026
d039874
fix(js): clear unused imports so tsc check matches CI
patrickleet Jul 26, 2026
576fad3
refactor(js): split commands into types, prepare, presets, receipt
patrickleet Jul 26, 2026
a528395
refactor(js): split identity, helpers barrels, persistence, index, di…
patrickleet Jul 26, 2026
d93e628
refactor(js): extract distributed-replica impl concern modules
patrickleet Jul 26, 2026
e52751f
refactor(js): body-split commands, identity, helpers, persistence, in…
patrickleet Jul 26, 2026
4412560
refactor(js): move command-runtime helpers into lib/
patrickleet Jul 26, 2026
f2a1c27
refactor(js): drop command-runtime helpers.ts barrel
patrickleet Jul 26, 2026
fbe6470
refactor: split graphql compile modules
patrickleet Jul 26, 2026
1d2f61d
refactor: split client compiler manifest module
patrickleet Jul 26, 2026
d6a5bc4
refactor: split client compiler graphql pipeline
patrickleet Jul 26, 2026
768fb1e
refactor: split client compiler render module
patrickleet Jul 26, 2026
74cc03b
refactor: split client manifest module
patrickleet Jul 26, 2026
c49a50e
refactor: split command ledger module
patrickleet Jul 26, 2026
50657cc
refactor: split sqlx repository core
patrickleet Jul 26, 2026
e51fdda
refactor: split command manifest compiler
patrickleet Jul 26, 2026
2d540b2
refactor: split graphql protocol helpers
patrickleet Jul 26, 2026
9480a95
refactor: split GraphQL command contract modules
patrickleet Jul 26, 2026
7d3e413
fix(macros): update trybuild paths after command_contract split
patrickleet Jul 26, 2026
628ddb1
refactor: split projection protocol store module
patrickleet Jul 26, 2026
cd28a5b
fix: re-export ProjectionPartitionSnapshot from store split
patrickleet Jul 26, 2026
6b86bfc
refactor: split projection protocol codec
patrickleet Jul 26, 2026
e4a7d9b
refactor: split hot rust modules
patrickleet Jul 26, 2026
ac91bc8
refactor: split projector runtime module
patrickleet Jul 26, 2026
2109e4d
refactor: split sqlx read model module
patrickleet Jul 26, 2026
e756f6d
refactor: split distributed macros entry modules
patrickleet Jul 26, 2026
380ef5f
refactor: split graphql surface modules
patrickleet Jul 26, 2026
bb78d02
refactor: split graphql engine orchestration
patrickleet Jul 26, 2026
a6cd9d7
refactor: split microsvc service module
patrickleet Jul 26, 2026
2547673
refactor: folderize SQLx projection protocol
patrickleet Jul 26, 2026
11a947e
refactor: folderize in-memory projection protocol
patrickleet Jul 26, 2026
a293aa5
refactor: share pure projection backend helpers
patrickleet Jul 26, 2026
6dd94f1
refactor: share projection kind storage decoding
patrickleet Jul 27, 2026
003e848
refactor: share projection digest helper
patrickleet Jul 27, 2026
a0d1db2
refactor: share projection failure batch predicate
patrickleet Jul 27, 2026
b1d9302
refactor: share projection ownership validation
patrickleet Jul 27, 2026
a05849d
test: share projection protocol scenarios
patrickleet Jul 27, 2026
5f6372b
refactor!: rename client GraphQL protocol version 2 → 1
patrickleet Jul 27, 2026
a59dd91
fix: update postgres/cli fingerprint goldens for protocol v1
patrickleet Jul 27, 2026
6cd1703
refactor!: ship unreleased wire versions as v1
patrickleet Jul 27, 2026
e5d21d3
fix: update orders harness schema fingerprint for v1 wire versions
patrickleet Jul 27, 2026
847e419
fix: update postgres role-surface schema fingerprint for v1
patrickleet Jul 27, 2026
7d5d31b
chore: drop NPM_RELEASE_READY gate from tag publish
patrickleet Jul 27, 2026
f84dd20
fix(e2e-ui): drop dead Manage Account and Protected Page links
patrickleet Jul 27, 2026
a69690a
chore(e2e-ui): refresh generated clients after protocol v1 wire renames
patrickleet Jul 27, 2026
0d6b931
chore: apply cargo fix for unused re-exports
patrickleet Jul 27, 2026
a324d43
chore: silence false dead_code noise without deleting protocol surface
patrickleet Jul 27, 2026
f1a78d7
fix: restore test-only re-exports removed by cargo fix
patrickleet Jul 27, 2026
8781a9d
refactor(e2e-ui): rename Fieldnote demo to Todos
patrickleet Jul 27, 2026
2f0755f
refactor(e2e-ui): name template e2e-ui; keep Todos as one demo
patrickleet Jul 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
44 changes: 40 additions & 4 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ existing unbounded-tech quality provider plus the integration/* jobs below —
|----------|-----------------|----------|
| [`quality.yaml`](./quality.yaml) | yes | **Consumers:** fmt → clippy → build → test + coverage (sticky PR comment) |
| [`test-all-features.yaml`](./test-all-features.yaml) | yes | **This repo:** workspace `--all-features` |
| [`integration-*.yaml`](./) | yes | **This repo:** broker / DB / CLI / observability |
| [`integration-*.yaml`](./) | yes | **This repo:** broker / DB / CLI / observability / GraphQL identity+OIDC |
| [`integration-e2e-ui.yaml`](./integration-e2e-ui.yaml) | yes | **This repo:** `tests/e2e-ui` offline suite + Playwright browser e2e |
| [`integration-js.yaml`](./integration-js.yaml) | yes | **This repo:** install, typecheck, test, build, and packed-consumer smoke test for `js/` |
| [`on-pr-quality.yaml`](./on-pr-quality.yaml) | entry | **This repo** PR gate (not the consumer quality contract) |
| [`on-push-main-version-and-tag.yaml`](./on-push-main-version-and-tag.yaml) | entry | **This repo** main → **vnext** tag |
| [`on-v-tag-publish.yaml`](./on-v-tag-publish.yaml) | entry | **This repo** crates.io + `dctl` binary release |
| [`on-v-tag-publish.yaml`](./on-v-tag-publish.yaml) | entry | **This repo** crates.io + npm + `dctl` binary release |

**Version tagging (anywhere):** `unbounded-tech/workflow-vnext-tag`
**GitHub Release only (domain crates):** `unbounded-tech/workflow-simple-release`
Expand Down Expand Up @@ -90,12 +92,46 @@ jobs:

**Pinning:** prefer a released tag once cut (`@vX.Y.Z` or git SHA). During development of quality, `@feat/shared-workflows` is fine.

## npm release setup

Version tags publish the package under [`js/`](../../js/) to npm as
`@hops-ops/distributed`. The tag must have the exact form `vX.Y.Z`; the workflow
uses `X.Y.Z` for both `js/package.json` and `js/package-lock.json`, runs the same
package quality gate used on pull requests, and publishes with npm provenance.

Configure an npm **Trusted Publisher** for `@hops-ops/distributed` with these
exact GitHub Actions coordinates:

- Organization or user: `hops-ops`
- Repository: `distributed`
- Workflow filename: `on-v-tag-publish.yaml`
- Environment: `npm`
- Allowed action: `npm publish`

Trusted Publisher configuration is available only after the npm package exists.
One-time bootstrap (already completed for this repo):

1. Publish a throwaway non-release version such as `0.0.0` for
`@hops-ops/distributed` on the public npm registry.
2. Configure the npm Trusted Publisher using the exact coordinates above
(`npm trust github @hops-ops/distributed --file on-v-tag-publish.yaml
--repo hops-ops/distributed --env npm --allow-publish`).
3. Create the GitHub `npm` deployment environment (optional protection rules:
tag pattern `v*`, required reviewers).

Release preflight validates the tag form and that `@hops-ops/distributed`
exists on the public registry before any npm or crates.io write starts. Tagged
npm releases authenticate through GitHub Actions OIDC. The workflow
intentionally has job-scoped `id-token: write`, uses npm 11.5.1 or newer, and
does **not** require or accept a long-lived `NPM_TOKEN` repository secret.

## Why this monorepo doesn’t call `quality.yaml`

The framework workspace needs a different gate: default-features tests via
unbounded quality (or similar), plus **all-features**, Postgres/NATS/Kafka/…
integrations, and CLI/observability jobs. Consumer domain crates are single
packages (or small libs) and only need the reusable quality contract.
integrations, CLI/observability, and GraphQL identity/OIDC jobs. Consumer
domain crates are single packages (or small libs) and only need the reusable
quality contract.

## Out of scope (for now)

Expand Down
182 changes: 182 additions & 0 deletions .github/workflows/integration-e2e-ui.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
name: e2e-ui fixture (offline + browser)

# Nested Todos template under tests/e2e-ui — not the root workspace.
# Local parity:
# cd tests/e2e-ui && make check-client
# cd tests/e2e-ui && make test
# cd tests/e2e-ui && make up && make run # then make test-browser
on:
workflow_call:

env:
CARGO_TERM_COLOR: always
# Playwright / Auth.js over HTTP on localhost
CI: true

jobs:
offline:
name: e2e-ui offline (domain + suite + UI unit)
runs-on: ubuntu-latest
defaults:
run:
working-directory: tests/e2e-ui
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
persist-credentials: false

- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8
with:
toolchain: stable

- uses: Swatinem/rust-cache@v2
with:
workspaces: tests/e2e-ui -> target
shared-key: e2e-ui-offline

- uses: actions/setup-node@v4
with:
node-version: "22"
cache: npm
cache-dependency-path: |
js/package-lock.json
tests/e2e-ui/ui/package-lock.json

- name: Verify generated client artifacts
run: make check-client

- name: Offline test suite
run: make test

browser:
name: e2e-ui Playwright (live stack)
runs-on: ubuntu-latest
timeout-minutes: 45
defaults:
run:
working-directory: tests/e2e-ui
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
persist-credentials: false

- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8
with:
toolchain: stable

- uses: Swatinem/rust-cache@v2
with:
workspaces: tests/e2e-ui -> target
shared-key: e2e-ui-browser

- uses: actions/setup-node@v4
with:
node-version: "22"
cache: npm
cache-dependency-path: |
js/package-lock.json
tests/e2e-ui/package-lock.json
tests/e2e-ui/ui/package-lock.json

- name: Install host tools
run: sudo apt-get update && sudo apt-get install -y jq openssl curl

- name: Docker stack + OIDC bootstrap (make up)
run: |
chmod +x scripts/up.sh
make up

- name: Build e2e-ui API binary
run: cargo build -p e2e-runner --bin e2e-ui

- name: Install UI deps
run: make ui-install

- name: Start API + UI
run: |
set -euo pipefail
set -a
# shellcheck disable=SC1091
. ./e2e-ui.env
set +a
export AUTH_URL="${E2E_UI_ORIGIN:-http://localhost:5180}"
export AUTH_USE_SECURE_COOKIES=false
export AUTH_TRUST_HOST=true

./target/debug/e2e-ui > .make-runner.log 2>&1 &
echo $! > .make-runner.pid

ok=0
for i in $(seq 1 90); do
code=$(curl -s -o /dev/null -w '%{http_code}' -X POST "http://127.0.0.1:8791/graphql" \
-H 'content-type: application/json' \
-d '{"query":"{ __typename }"}' 2>/dev/null || echo 000)
if [ "$code" = "200" ] || [ "$code" = "401" ]; then ok=1; break; fi
sleep 0.5
done
if [ "$ok" != "1" ]; then
echo "API failed to become ready"; tail -100 .make-runner.log; exit 1
fi
echo "API ready (HTTP $code)"

cd ui
npm run dev -- --host localhost --port 5180 > ../.make-ui.log 2>&1 &
echo $! > ../.make-ui.pid
cd ..

ok=0
for i in $(seq 1 60); do
code=$(curl -s -o /dev/null -w '%{http_code}' "http://localhost:5180/" 2>/dev/null || echo 000)
# 200 home, or 303 redirect when auth wraps routes — not 000/5xx
if [ "$code" = "200" ] || [ "$code" = "303" ] || [ "$code" = "302" ]; then ok=1; break; fi
sleep 0.5
done
if [ "$ok" != "1" ]; then
echo "UI failed to become ready (last HTTP $code)"; tail -80 .make-ui.log; exit 1
fi
echo "UI ready (HTTP $code)"

- name: Install Playwright + Chromium
run: |
npm install
npx playwright install chromium --with-deps

- name: Run browser e2e
run: npm run test:browser
env:
E2E_UI_ORIGIN: http://localhost:5180
E2E_API_ORIGIN: http://127.0.0.1:8791
CI: true

- name: Upload Playwright report
if: failure()
uses: actions/upload-artifact@v4
with:
name: e2e-ui-playwright-report
path: |
tests/e2e-ui/playwright-report
tests/e2e-ui/test-results
if-no-files-found: ignore
retention-days: 7

- name: Dump logs on failure
if: failure()
run: |
echo '=== API log ==='
tail -150 .make-runner.log || true
echo '=== UI log ==='
tail -80 .make-ui.log || true
docker compose -f docker/docker-compose.yml ps -a || true
docker compose -f docker/docker-compose.yml logs --tail=100 || true

- name: Stop API/UI
if: always()
run: |
[ -f .make-ui.pid ] && kill "$(cat .make-ui.pid)" 2>/dev/null || true
[ -f .make-runner.pid ] && kill "$(cat .make-runner.pid)" 2>/dev/null || true
lsof -ti:8791 2>/dev/null | xargs -r kill -9 2>/dev/null || true
lsof -ti:5180 2>/dev/null | xargs -r kill -9 2>/dev/null || true

- name: Tear down Docker
if: always()
run: docker compose -f docker/docker-compose.yml down -v || true
Loading
Loading