Skip to content

feat: Wave 4 — api-types from OpenAPI + regression test backfill#530

Open
tayebmokni wants to merge 2 commits into
feat/wave-3-large-featuresfrom
feat/wave-4-refactor
Open

feat: Wave 4 — api-types from OpenAPI + regression test backfill#530
tayebmokni wants to merge 2 commits into
feat/wave-3-large-featuresfrom
feat/wave-4-refactor

Conversation

@tayebmokni
Copy link
Copy Markdown
Contributor

Stacked on PR #529PR #528PR #527PR #523.

Final wave of the post-session #522 tracker.

Closes 2 issues

2 commits

  1. `feat(types): generate @gonext/api-types from OpenAPI spec — pilot in posts (Generate @gonext/api-types from existing OpenAPI spec — eliminate per-page envelope adapters #514)` — 3,179 lines of generated types, one pilot consumer
  2. `test: backfill regression tests for session bug fixes (Backfill regression tests for this session's bug fixes #521)` — 28 new tests (19 admin + 9 api)

Verification

Tracker close-out

With this PR merged, 27 of 28 child issues in tracker #522 are closed:

Remaining open child issues (with reasons):

Tracker #522 itself can close after this PR merges.

🤖 Generated with Claude Code

tib0o0o and others added 2 commits May 28, 2026 13:17
…posts (#514)

The admin and SDK each defined decoupled wire types that drifted from
the API. PR #523 documented 8+ impedance mismatches in the Post type
alone. Generate types from openapi.yaml so the wire shape has a
single source of truth.

### New workspace package

packages/ts/api-types/:
- package.json: \`@gonext/api-types\`, private workspace package.
  Scripts: \`generate\` (openapi-typescript), \`build\` (tsc),
  \`dev\` (--watch), \`typecheck\`.
- tsconfig.json: strict, declaration + sourcemaps, matches
  packages/ts/hooks-schemas house style.
- src/index.ts: re-exports from ./generated.
- src/generated.ts: committed output of \`openapi-typescript
  ../../../apps/api/openapi/openapi.yaml\` — 3,179 lines, exports
  paths/components/operations/webhooks/$defs.
- README.md: regeneration steps.

### Pilot consumer

apps/admin/src/app/(authenticated)/posts/page.tsx replaces its
hand-typed \`ApiPost\` with a generated derivation:

    type ApiPost = Partial<
      paths['/api/v1/posts']['get']['responses']['200']['content']['application/json']['data'][number]
    > & { id: string; author?: {...} };

\`Partial<>\` preserves the defensive adapter behavior — the list
endpoint doesn't emit the full Post projection the spec declares
(#515 follow-up). The \`author\` extension covers the display-name
enrichment the spec doesn't model. Once the API projection catches
up with the spec the Partial<> can drop.

### Not migrated (deliberate)

Every other admin consumer of wire types stays hand-typed for now.
Full migration is a follow-up — this PR ships the package + the
pattern + a working pilot so reviewers can evaluate it.

### Verification

- \`pnpm install\` clean.
- \`pnpm --filter @gonext/api-types generate\` emits 3,179-line
  generated.ts cleanly (no warnings on the YAML).
- \`pnpm --filter @gonext/api-types build\` emits dist/.
- \`cd apps/admin && pnpm exec tsc --noEmit\` clean.
- \`pnpm test --run posts/page\` passes.

Closes #514 (setup + pilot). Per-consumer migration is a follow-up.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Tayeb Mokni <tayeb.mokni@gmail.com>
Lock in fixes from PRs #523, #527, #528, #529 with explicit
regression tests. Future refactors get a loud signal if any of
these re-break.

### Admin (vitest) — 19 new tests

posts/page.test.tsx (+6): envelope shape variants — data/posts
keys, data:null tolerance, HTTP 400 error state, malformed JSON,
data-wins-over-posts precedence.

posts/PostListClient.test.tsx (+3): assert postEditHref omits /edit
suffix; percent-encoded ids; row title link.

comments/CommentListClient.test.tsx (+3): comments table post-link
omits /edit, points to bare post id, uses post id not comment id.

media/components/MediaGrid.test.tsx (+2): tolerates initial
\`data:null\` and fetch \`data:null\`.

media/components/FolderTree.test.tsx (+1): tolerates listCollections
\`data:null\`.

media/page.test.tsx (new file, +4): coerces null to empty array,
passes through array data, falls back on fetch failure, falls back
on fetch throw.

### API (go) — 9 new tests

cmd/server/adapters_test.go (new file, +6 testcontainers Postgres):
userLookupByEmail + userLookupByID project meta.roles correctly,
empty-roles array, missing-roles key, not-found path for both.

auth/login/service_test.go (+3): password-only path threads roles
into Sessions.Create data map; inline-TOTP path threads roles too;
empty-roles results in nil data map (not \`{roles: []}\`).

### Verified existing coverage

- lib/api-client.test.ts (added in #523) covers server + client
  branches with empty-string preservation. No gap.
- service_test.go::TestFinalizeTOTP_ThreadsRolesFromUserByID and
  TestFinalizeTOTP_NilUserByIDDoesNotPanic exist from #496. The
  3 new password-path tests fill the gap they didn't cover.

All test names carry \`Issue521\` or \`Issue523\` markers for
traceability. 657/657 admin tests pass; both api packages pass under
testcontainers Postgres.

Closes #521.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Tayeb Mokni <tayeb.mokni@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants