Skip to content

fix: promote REST route contracts to controller decorators - #1008

Merged
kang-heewon merged 4 commits into
trunkfrom
fix/974-contract-first-rest
Jun 21, 2026
Merged

fix: promote REST route contracts to controller decorators#1008
kang-heewon merged 4 commits into
trunkfrom
fix/974-contract-first-rest

Conversation

@kang-heewon

@kang-heewon kang-heewon commented Jun 19, 2026

Copy link
Copy Markdown
Member

Fixes #974.

Summary

REST route contracts can now drive controller decorators directly: HTTP method decorators accept matching RouteContractSpec objects, and @Param, @Query, @Body, and @ResponseSchema can bind from the same contract.

The contract graph preserves route contract id, operation id, source location, and input/output schemas, then reports drift when controller path, method, path/query bindings, body schema, or response metadata diverges from the contract. OpenAPI and RPC generation both handle contract-first routes.

The SPA split REST template now declares typed route contracts as the source of truth for its user routes, with updated guide/API docs, public API snapshots, tests, and a patch changeset.

Verification

  • pnpm --filter @croco/protocols-rest exec vitest run src/tests/RouteContractTypes.spec.ts src/tests/decorators/Route.spec.ts - passed, 19 tests.
  • pnpm --filter @croco/protocols-core exec vitest run src/tests/extractRouteIR.spec.ts src/tests/ContractGraph.spec.ts - passed, 36 tests.
  • pnpm --filter @croco/openapi-spec exec vitest run src/tests/emitOpenAPI.spec.ts - passed, 19 tests.
  • pnpm --filter @croco/rpc-codegen exec vitest run src/tests/codegen.spec.ts - passed, 33 tests.
  • pnpm --filter create-croco-app exec vitest run src/tests/templates-build.spec.ts src/tests/e2e-generation.spec.ts - passed, 16 tests.
  • pnpm --filter @croco/protocols-rest test - passed, 124 tests.
  • pnpm --filter @croco/protocols-core test - passed, 37 tests.
  • pnpm --filter @croco/openapi-spec test - passed, 28 tests.
  • pnpm --filter @croco/rpc-codegen test - passed, 59 tests.
  • pnpm create-croco-app:smoke - passed; all generated app smoke cases passed.
  • pnpm typecheck - passed, 202/202 Turbo tasks.
  • pnpm test - passed, 203/203 Turbo tasks.
  • pnpm check - passed.
  • pnpm changeset-required:check -- --base origin/trunk --head HEAD - passed.
  • pnpm docs:examples:check and pnpm docs:catalog:check - passed.
  • git diff --check and git diff --cached --check - passed.
  • Pre-commit hook passed: staged oxlint and oxfmt.
  • Pre-push hook passed: existing changeset detected, full pnpm test passed with 203/203 Turbo tasks, and full pnpm typecheck passed with 202/202 Turbo tasks.

Self-review gates

  • Correctness/regression: PASS. The generated REST template now uses typed route contracts for its main user routes. Type fixtures cover path/params mismatch and wrong HTTP method/body usage. ContractGraph tests cover body/response drift diagnostics and route contract identity/source location preservation. OpenAPI/RPC tests and generated app smoke prove contract-first and existing decorator routes both emit usable artifacts.
  • API/security/compatibility/release: PASS. The decorator overloads are additive and preserve existing string/schema decorator paths. Public exports, generated API docs, public API snapshot, README, migration guide, and patch changeset are in sync. No new dependencies, lockfile changes, secrets, or external service assumptions were introduced.
  • Maintainability/minimality: PASS. The diff stays scoped to REST decorator typing/metadata, protocol-core IR/diagnostics, OpenAPI/RPC coverage, generated template/docs, and release metadata. It reuses existing schema/metadata utilities and keeps route contracts authoritative for body/path/query while preserving decorator header schemas for the header-only route surface.

Independent review

An independent review found two documentation drift issues before the PR was opened: a stale defineRouteSchema() reference in the guide and an incomplete README API list. Both were fixed, and the docs/static checks were rerun successfully.

Risk

Low-medium. This adds public contract-first decorator overloads and stricter diagnostics for contract-first routes while preserving the existing loose decorator path for compatibility.

Summary by CodeRabbit

๋ฆด๋ฆฌ์Šค ๋…ธํŠธ

  • New Features
    • REST ๋ผ์šฐํŠธ ๊ณ„์•ฝ(Contract-first)์„ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์ž…๋ ฅ์œผ๋กœ ์ง์ ‘ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ–ˆ๊ณ , ์ปจํŠธ๋กค๋Ÿฌ ๋ฐ”์ธ๋”ฉ/์‘๋‹ต ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๋ถˆ์ผ์น˜๋ฅผ ์ง„๋‹จํ•ด ๋ณด๊ณ ํ•ฉ๋‹ˆ๋‹ค.
    • ๊ณ„์•ฝ ๊ธฐ๋ฐ˜ ๋ผ์šฐํŠธ ์ •๋ณด๊ฐ€ OpenAPI/RPC ์ƒ์„ฑ์— ์šฐ์„  ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค.
  • Documentation
    • REST ํ”„๋กœํ† ์ฝœ API ๋ฌธ์„œ์™€ โ€œ์Šคํ‚ค๋งˆ ์†Œ์Šค ์˜ค๋ธŒ ํŠธ๋ฃจ์Šคโ€ ๊ฐ€์ด๋“œ๋ฅผ ๊ณ„์•ฝ ๊ธฐ๋ฐ˜ ํ๋ฆ„์œผ๋กœ ์—…๋ฐ์ดํŠธํ–ˆ์Šต๋‹ˆ๋‹ค.
    • SPA split ์Šคํƒ€ํ„ฐ ํ…œํ”Œ๋ฆฟ ์˜ˆ์ œ๋ฅผ ๊ณ„์•ฝ-first REST ๋ผ์šฐํŠธ๋กœ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • Chores
    • ๊ด€๋ จ ํŒจํ‚ค์ง€์— patch ๋ฒ„์ „ ์—…๋ฐ์ดํŠธ๋ฅผ ๋ฐ˜์˜ํ–ˆ์Šต๋‹ˆ๋‹ค.

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@kang-heewon, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 21 minutes and 32 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running โ€” you're only billed for reviews past your plan's rate limits ($0.25/file).

โŒ› How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

๐Ÿšฆ How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

โ„น๏ธ Review info
โš™๏ธ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 013f38bd-488f-4b32-81cd-7ec75d75eb3b

๐Ÿ“ฅ Commits

Reviewing files that changed from the base of the PR and between 3c3f933 and 90ff67e.

๐Ÿ“’ Files selected for processing (13)
  • packages/cli/src/tests/projectMap.spec.ts
  • packages/docs/scripts/sanitize-typedoc-index.mjs
  • packages/docs/src/content/docs/api/protocols-rest/src/functions/Body.md
  • packages/docs/src/content/docs/api/protocols-rest/src/functions/Param.md
  • packages/docs/src/content/docs/api/protocols-rest/src/functions/Query.md
  • packages/docs/src/content/docs/api/protocols-rest/src/functions/ResponseSchema.md
  • packages/docs/src/content/docs/api/protocols-rest/src/functions/isRouteContractSpec.md
  • packages/docs/src/content/docs/api/protocols-rest/src/functions/routeParamSchema.md
  • packages/docs/src/content/docs/api/protocols-rest/src/functions/routeQueryParamSchema.md
  • packages/docs/src/content/docs/api/protocols-rest/src/type-aliases/RouteContractWithBody.md
  • packages/docs/src/content/docs/api/protocols-rest/src/type-aliases/RouteContractWithParams.md
  • packages/docs/src/content/docs/api/protocols-rest/src/type-aliases/RouteContractWithQuery.md
  • packages/docs/src/content/docs/api/protocols-rest/src/type-aliases/RouteContractWithResponse.md
๐Ÿ“ Walkthrough

Walkthrough

RouteContractSpec์„ REST ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ(@Get, @Post, @Param, @Body, @ResponseSchema)์—์„œ ์ง์ ‘ ์†Œ๋น„ํ•˜๋Š” ์˜ค๋ฒ„๋กœ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , ContractGraph๊ฐ€ ๊ณ„์•ฝ์˜ identity/sourceLocation์„ ๋ณด์กดํ•˜๋ฉฐ controller ๋ฐ”์ธ๋”ฉ๊ณผ์˜ drift๋ฅผ ์ง„๋‹จํ•˜๋„๋ก ํ™•์žฅํ•ฉ๋‹ˆ๋‹ค. SPA ์Šคํ”Œ๋ฆฟ ํ…œํ”Œ๋ฆฟ์˜ UserController๋„ contract-first ๋ฐฉ์‹์œผ๋กœ ์ „ํ™˜๋ฉ๋‹ˆ๋‹ค.

Changes

Contract-first REST ๋ผ์šฐํŠธ ๊ตฌํ˜„

Layer / File(s) Summary
RouteContractSpec ๋ฐ ๊ด€๋ จ ํƒ€์ž… ์ •์˜
packages/protocols-rest/src/libs/types/RouteContract.ts, packages/protocols-rest/src/libs/types/index.ts, packages/protocols-rest/src/libs/types.ts, packages/protocols-core/src/libs/sharedTypes.ts
RouteContractSpec์— id?/sourceLocation? ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , RouteContractSourceLocation ํƒ€์ž…, isRouteContractSpec ํƒ€์ž… ๊ฐ€๋“œ, routeParamSchema/routeQueryParamSchema ํ—ฌํผ๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. defineRouteContract ์ œ๋„ค๋ฆญ ์ œ์•ฝ์— NoInfer ์ ์šฉ, sharedTypes์— RouteContractMetadata/RouteMetadata.contract ์ถ”๊ฐ€.
HTTP ๋ฉ”์„œ๋“œ/ํŒŒ๋ผ๋ฏธํ„ฐ/๋ฐ”๋””/์‘๋‹ต ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์˜ค๋ฒ„๋กœ๋“œ
packages/protocols-rest/src/libs/decorators/HttpMethod.ts, packages/protocols-rest/src/libs/decorators/Params.ts, packages/protocols-rest/src/libs/decorators/ResponseSchema.ts, packages/protocols-rest/src/libs/decorators/Controller.ts
HttpMethodDecoratorFactory<Method> ์ œ๋„ค๋ฆญ ํƒ€์ž…์„ ๋„์ž…ํ•˜๊ณ  @Get/@Post ๋“ฑ์ด ๊ณ„์•ฝ์„ ์ธ์ž๋กœ ๋ฐ›๋„๋ก ํ™•์žฅํ•ฉ๋‹ˆ๋‹ค. @Param/@Query/@Body/@ResponseSchema๊ฐ€ RouteContractSpec์„ ๋ฐ›๋Š” ์˜ค๋ฒ„๋กœ๋“œ ํ•จ์ˆ˜๋กœ ์žฌ์ž‘์„ฑ๋ฉ๋‹ˆ๋‹ค. @Controller๋Š” contract.path๋ฅผ ์ปจํŠธ๋กค๋Ÿฌ ์ƒ๋Œ€ ๊ฒฝ๋กœ๋กœ ์ •๊ทœํ™”ํ•ฉ๋‹ˆ๋‹ค.
RouteIR ๊ณ„์•ฝ ํ•„๋“œ ๋ฐ extractRouteIR ํ™•์žฅ
packages/protocols-core/src/libs/RouteIR.ts, packages/protocols-core/src/libs/extractRouteIR.ts, packages/protocols-core/src/index.ts
RouteIR์— routeContract?: RouteContractIR | null ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , RouteContractIR/RouteContractSourceLocation ํƒ€์ž…์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. extractRouteIR์ด ๊ณ„์•ฝ ์กด์žฌ ์‹œ ์ž…๋ ฅ ์Šคํ‚ค๋งˆ๋ฅผ ๋ณ‘ํ•ฉํ•˜๊ณ  path๋ฅผ ๊ณ„์•ฝ ์šฐ์„ ์œผ๋กœ ์ ์šฉํ•˜๋„๋ก extractRouteContract/mergeContractInputSchemas/normalizeFullPath ์œ ํ‹ธ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
ContractGraph ๊ณ„์•ฝ ์ •ํ•ฉ์„ฑ ๊ฒ€์ฆ ๋ฐ ์Šค๋ƒ…์ƒท ํ™•์žฅ
packages/protocols-core/src/libs/ContractGraph.ts, packages/protocols-core/src/libs/ContractGraphSnapshot.ts
ContractDiagnostic์— contractId/sourceLocation ๋“ฑ ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , validateRouteContract ๋ฐ method/path/params/body/response ๋ถˆ์ผ์น˜ ๊ฒ€์ฆ ํ•จ์ˆ˜๋“ค์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. operationId๋ฅผ ๊ณ„์•ฝ ์šฐ์„ ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ณ , ContractGraphSnapshot์— routeContract ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
CLI ํ…Œ์ŠคํŠธ ํ—ฌํผ ๋ผ์šฐํŠธ ๊ณ„์•ฝ ํ•„๋“œ ์—…๋ฐ์ดํŠธ
packages/cli/src/tests/contractsCheck.spec.ts, packages/cli/src/tests/contractsDiff.spec.ts, packages/cli/src/tests/projectMap.spec.ts
createGraph() ๋ฐ createContractSnapshot() ํ…Œ์ŠคํŠธ ํ—ฌํผ์˜ routes ์š”์†Œ์— routeContract: null ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์ƒˆ๋กœ์šด ๋ผ์šฐํŠธ ๋ฐ์ดํ„ฐ ์Šคํ‚ค๋งˆ์™€ ํ˜ธํ™˜์„ฑ์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋ฐ ํƒ€์ž… ๋‹จ์–ธ ํ…Œ์ŠคํŠธ
packages/protocols-rest/src/tests/decorators/Route.spec.ts, packages/protocols-rest/src/tests/RouteContractTypes.spec.ts
Route.spec.ts์— typed contract๋ฅผ @Get/@ResponseSchema์— ์ ์šฉํ•˜๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. RouteContractTypes.spec.ts์— ๊ณ„์•ฝ ๊ฐ์ฒด ์ค‘์‹ฌ ์ปจํŠธ๋กค๋Ÿฌ ์‹œ๋‚˜๋ฆฌ์˜ค, routeParamSchema ๋‹จ์–ธ, ์ž˜๋ชป๋œ ๊ณ„์•ฝ ์—ฐ๊ฒฐ์— ๋Œ€ํ•œ @ts-expect-error ์Œ์ˆ˜ ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
extractRouteIR ๋ฐ ContractGraph ๊ณ„์•ฝ ๊ฒ€์ฆ ํ…Œ์ŠคํŠธ
packages/protocols-core/src/tests/extractRouteIR.spec.ts, packages/protocols-core/src/tests/ContractGraph.spec.ts
extractRouteIR.spec.ts์— contract ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ฃผ์ž… ํ›„ routeContract/inputSchemas/outputSchema ๊ฒ€์ฆ ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ContractGraph.spec.ts์— body/response ๋“œ๋ฆฌํ”„ํŠธ ์ง„๋‹จ ์ฝ”๋“œ ๋‹จ์–ธ ํ…Œ์ŠคํŠธ์™€ attachRouteContract ํ—ฌํผ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
OpenAPI emit ๋ฐ rpc-codegen ๊ณ„์•ฝ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ
packages/openapi-spec/src/tests/emitOpenAPI.spec.ts, packages/rpc-codegen/src/tests/codegen.spec.ts
emitOpenAPI.spec.ts์— defineRouteContract ๊ธฐ๋ฐ˜ ์ปจํŠธ๋กค๋Ÿฌ์˜ operationId/requestBody/responses[200] ์ƒ์„ฑ ๊ฒ€์ฆ ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. codegen.spec.ts์— routeContract ํ•„๋“œ ํฌํ•จ RouteIR๋กœ ํด๋ผ์ด์–ธํŠธ ํƒ€์ž…/๋ฉ”์„œ๋“œ ์ƒ์„ฑ ๊ฒ€์ฆ ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
SPA ํ…œํ”Œ๋ฆฟ ๊ณ„์•ฝ ๊ธฐ๋ฐ˜ ์ „ํ™˜
packages/create-croco-app/templates/spa-be-split/apps/api-server/src/controllers/userSchemas.ts, packages/create-croco-app/templates/spa-be-split/apps/api-server/src/controllers/UserController.ts, packages/create-croco-app/src/tests/templates-build.spec.ts, packages/create-croco-app/templates/spa-be-split/README.md.hbs
userSchemas.ts์— 5๊ฐœ์˜ RouteContract ์ƒ์ˆ˜๋ฅผ defineRouteContract๋กœ ์ •์˜ํ•˜๊ณ , UserController.ts์˜ ๋ชจ๋“  ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๋ผ์šฐํŠธ ์ƒ์ˆ˜๋ฅผ ์ง์ ‘ ์ธ์ž๋กœ ์‚ฌ์šฉํ•˜๋„๋ก ์ „ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ํ…œํ”Œ๋ฆฟ ๋นŒ๋“œ ์ŠคํŽ™๊ณผ README ์˜ˆ์‹œ๋„ ๊ฐฑ์‹ ๋ฉ๋‹ˆ๋‹ค.
API ๋ฌธ์„œ, ๊ฐ€์ด๋“œ ๋ฐ ๊ณต๊ฐœ API ์Šค๋ƒ…์ƒท ๊ฐฑ์‹ 
packages/docs/src/content/docs/api/protocols-rest/src/functions/*, packages/docs/src/content/docs/api/protocols-rest/src/variables/*, packages/docs/src/content/docs/api/protocols-rest/src/type-aliases/*, packages/docs/src/content/docs/en/guides/schema-source-of-truth.mdx, packages/protocols-rest/README.md, public-api-surface.snapshot.json, .changeset/contract-first-rest-routes.md
Body/Param/Query/ResponseSchema ๋ฌธ์„œ์— ์ œ๋„ค๋ฆญ ์˜ค๋ฒ„๋กœ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , HTTP ๋ฉ”์„œ๋“œ ๋ณ€์ˆ˜ ๋ฌธ์„œ๋ฅผ HttpMethodDecoratorFactory ํƒ€์ž…์œผ๋กœ ๊ฐฑ์‹ ํ•ฉ๋‹ˆ๋‹ค. isRouteContractSpec/routeParamSchema/routeQueryParamSchema ์‹ ๊ทœ ๋ฌธ์„œ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. schema-source-of-truth ๊ฐ€์ด๋“œ๋ฅผ defineRouteContract ์ค‘์‹ฌ์œผ๋กœ ๊ต์ฒดํ•˜๊ณ  Migration ์„น์…˜์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ๊ณต๊ฐœ API ์Šค๋ƒ…์ƒท์„ ๊ฐฑ์‹ ํ•ฉ๋‹ˆ๋‹ค.

Sequence Diagram(s)

sequenceDiagram
  participant Dev as ๊ฐœ๋ฐœ์ž
  participant RouteContract as defineRouteContract
  participant Decorator as `@Get/`\n@Param/@Body
  participant Controller as `@Controller`
  participant ExtractRouteIR as extractRouteIR
  participant ContractGraph as buildContractGraph
  participant Diagnostic as ContractDiagnostic

  Dev->>RouteContract: defineRouteContract({ method, path, params, body, response })
  RouteContract-->>Dev: typed contract ๊ฐ์ฒด ๋ฐ˜ํ™˜

  Dev->>Decorator: `@Get`(contract), `@Param`(contract, "id"), `@Body`(contract)
  Decorator->>Decorator: isRouteContractSpec ํŒ๋ณ„ โ†’ ์Šคํ‚ค๋งˆ ์ถ”์ถœ
  Dev->>Controller: `@Controller`("/users")
  Controller->>Controller: normalizeContractRoutePaths โ†’ contract.path๋ฅผ ์ƒ๋Œ€ ๊ฒฝ๋กœ๋กœ ์ •๊ทœํ™”

  ExtractRouteIR->>ExtractRouteIR: extractRouteContract โ†’ RouteContractIR ๊ตฌ์„ฑ
  ExtractRouteIR->>ExtractRouteIR: mergeContractInputSchemas โ†’ body/params/query ๋ณ‘ํ•ฉ
  ExtractRouteIR-->>ContractGraph: RouteIR (routeContract ํฌํ•จ)

  ContractGraph->>ContractGraph: validateRouteContract โ†’ method/path/params/body/response ๊ฒ€์‚ฌ
  ContractGraph-->>Diagnostic: ๋ถˆ์ผ์น˜ ์‹œ contractId/sourceLocation ํฌํ•จ ์ง„๋‹จ ์ƒ์„ฑ
Loading

Estimated code review effort

๐ŸŽฏ 4 (Complex) | โฑ๏ธ ~60 minutes

Possibly related PRs

  • croco-dev/framework#815: ContractGraph/IR ํŒŒ์ดํ”„๋ผ์ธ ๋ฐ buildContractGraph ๊ธฐ๋ฐ˜ OpenAPI/RPC ์ƒ์„ฑ ๊ฒ€์ฆ ์ธํ”„๋ผ๋ฅผ ๊ตฌ์ถ•ํ•œ PR์œผ๋กœ, ์ด๋ฒˆ PR์˜ ๊ณ„์•ฝ ์ •ํ•ฉ์„ฑ ๊ฒ€์ฆ๊ณผ ์Šค๋ƒ…์ƒท ํ™•์žฅ์ด ๋™์ผํ•œ ํŒŒ์ดํ”„๋ผ์ธ ์œ„์—์„œ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.
๐Ÿšฅ Pre-merge checks | โœ… 4 | โŒ 1

โŒ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage โš ๏ธ Warning Docstring coverage is 2.27% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
โœ… Passed checks (4 passed)
Check name Status Explanation
Description Check โœ… Passed Check skipped - CodeRabbitโ€™s high-level summary is enabled.
Title check โœ… Passed ์ œ๋ชฉ์€ ์ฃผ์š” ๋ณ€๊ฒฝ์‚ฌํ•ญ์ธ 'REST route contracts๋ฅผ controller decorators๋กœ ์Šน๊ฒฉ'์„ ๋ช…ํ™•ํ•˜๊ณ  ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.
Linked Issues check โœ… Passed PR์˜ ๋ชจ๋“  ์ฃผ์š” ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์ด์Šˆ #974์˜ ์š”๊ตฌ์‚ฌํ•ญ์„ ์ถฉ์กฑํ•ฉ๋‹ˆ๋‹ค. RouteContract๋ฅผ controller ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ์ง์ ‘ ์‚ฌ์šฉํ•˜๋Š” API ์ถ”๊ฐ€, @Param/@Query/@Body/@ResponseSchema์˜ contract ์˜ค๋ฒ„๋กœ๋“œ, ContractGraph์˜ route contract ์ •๋ณด ๋ณด์กด, ํ…œํ”Œ๋ฆฟ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜, ํƒ€์ž… ๊ฒ€์ฆ fixture ๋“ฑ์ด ๋ชจ๋‘ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
Out of Scope Changes check โœ… Passed ๋ชจ๋“  ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด issue #974์˜ ๋ฒ”์œ„ ๋‚ด์— ์žˆ์Šต๋‹ˆ๋‹ค. REST route contract ์ž‘์„ฑ ๊ฒฝํ—˜ ๊ฐœ์„ ์— ์ง‘์ค‘ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, GraphQL/tRPC ๊ณ„์•ฝ์€ ํฌํ•จ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

โœ๏ธ Tip: You can configure your own custom pre-merge checks in the settings.

โœจ Finishing Touches
๐Ÿงช Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/974-contract-first-rest

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

โค๏ธ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 19, 2026

Copy link
Copy Markdown

๐Ÿ“Š Benchmark Results

โŒ Some benchmarks failed

Gate failures

  • CrocoApp constructor: p75 6.9ฮผs exceeds baseline 3.4ฮผs by more than 20%
  • CrocoApp lambdaHandler (10 controllers): p75 189.4ฮผs exceeds baseline 33.3ฮผs by more than 20%
  • Lambda cold-start simulation: p75 338.0ฮผs exceeds baseline 70.2ฮผs by more than 20%
  • Lambda cold-start with headers: p75 333.7ฮผs exceeds baseline 66.7ฮผs by more than 20%
  • Lambda cold-start with binary body: p75 270.5ฮผs exceeds baseline 63.2ฮผs by more than 20%
  • Lambda cold-start with query params: p75 239.0ฮผs exceeds baseline 63.9ฮผs by more than 20%
  • Lambda cold-start with authorizer context: p75 242.6ฮผs exceeds baseline 59.8ฮผs by more than 20%
  • Lambda cold-start realistic scenario: p75 241.1ฮผs exceeds baseline 60.2ฮผs by more than 20%
  • EventBusConfig.start (10 handlers): p75 1.4ฮผs exceeds baseline 0.9ฮผs by more than 20%
  • EventPublisher.publishNow single event: p75 1.7ฮผs exceeds baseline 1.1ฮผs by more than 20%
  • DefaultHandlerResolver.resolve ร— 10: p75 0.1ฮผs exceeds baseline 0.0ฮผs by more than 20%
  • Container.get singleton (cold): p75 73.7ฮผs exceeds baseline 0.6ฮผs by more than 20%
  • Container.register ร— 50 components: p75 3.0ms exceeds baseline 12.1ฮผs by more than 20%
  • Container.validate (50 components): p75 3.2ms exceeds baseline 29.7ฮผs by more than 20%
  • Container.get singleton (warm): p75 1.7ฮผs exceeds baseline 0.3ฮผs by more than 20%
  • lambdaPreset config creation: p75 1.5ฮผs exceeds baseline 1.0ฮผs by more than 20%
Benchmark p75 Threshold Baseline vs Baseline Status Notes
CrocoApp constructor 6.9ฮผs 30.0ms 3.4ฮผs +104.2% โŒ -
CrocoApp lambdaHandler (10 controllers) 189.4ฮผs 50.0ms 33.3ฮผs +468.8% โŒ -
Lambda cold-start simulation 338.0ฮผs 80.0ms 70.2ฮผs +381.6% โŒ -
Lambda cold-start with headers 333.7ฮผs 80.0ms 66.7ฮผs +400.0% โŒ -
Lambda cold-start with binary body 270.5ฮผs 80.0ms 63.2ฮผs +328.2% โŒ -
Lambda cold-start with query params 239.0ฮผs 80.0ms 63.9ฮผs +274.1% โŒ -
Lambda cold-start with authorizer context 242.6ฮผs 80.0ms 59.8ฮผs +305.7% โŒ -
Lambda cold-start realistic scenario 241.1ฮผs 80.0ms 60.2ฮผs +300.7% โŒ -
EventBusConfig.start (10 handlers) 1.4ฮผs 10.0ms 0.9ฮผs +59.2% โŒ -
EventPublisher.publishNow single event 1.7ฮผs 2.0ms 1.1ฮผs +52.6% โŒ -
DefaultHandlerResolver.resolve ร— 10 0.1ฮผs 5.0ms 0.0ฮผs +90.5% โŒ -
Container.get singleton (cold) 73.7ฮผs 5.0ms 0.6ฮผs +11688.3% โŒ -
Container.register ร— 50 components 3.0ms 10.0ms 12.1ฮผs +24240.2% โŒ -
Container.validate (50 components) 3.2ms 20.0ms 29.7ฮผs +10561.1% โŒ -
Container.get singleton (warm) 1.7ฮผs 500.0ฮผs 0.3ฮผs +469.5% โŒ -
TelemetryRuntime.init (lambda preset) 1.1ms 200.0ms 69.3ms -98.4% โœ… -
lambdaPreset config creation 1.5ฮผs 2.0ms 1.0ฮผs +46.3% โŒ -

Updated: 2026-06-21T07:00:52.387Z ยท Commit: 3f302f7

@kang-heewon
kang-heewon force-pushed the fix/974-contract-first-rest branch from 58f20fa to 8f8c93c Compare June 19, 2026 16:18
@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{}

@kang-heewon
kang-heewon force-pushed the fix/974-contract-first-rest branch 2 times, most recently from f190766 to c62672d Compare June 19, 2026 17:06
@kang-heewon
kang-heewon force-pushed the fix/974-contract-first-rest branch from c62672d to 9c810da Compare June 19, 2026 17:23

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

๐Ÿค– Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/docs/src/content/docs/api/protocols-rest/src/functions/Body.md`:
- Around line 8-44: The type constraint for TContract in the Body function
documentation is incorrect and doesn't match the actual implementation. Update
line 18 where TContract is defined to change the constraint from
RouteContractSpec & object to RouteContractSpec & { body: z.ZodType } to
accurately reflect what the implementation requires. Additionally, resolve the
markdown lint MD024 violation by renaming the duplicate "## Call Signature"
headings at lines 8 and 30 to descriptive names like "## Overload with Contract"
for the first occurrence and "## Overload with Schema" for the second occurrence
to clearly distinguish between the two function overloads.

In
`@packages/docs/src/content/docs/api/protocols-rest/src/functions/isRouteContractSpec.md`:
- Around line 1-18: The return type for the isRouteContractSpec function is
overly complex with fully expanded generic parameters making it hard to read.
Simplify both the return type in the function signature and in the Returns
section by replacing the lengthy parameterized type with a more concise form
like `value is RouteContractSpec`. Additionally, add a new Description or
Example section to explain the function's purpose, runtime behavior, and
demonstrate how the type guard works with example code.

In `@packages/docs/src/content/docs/api/protocols-rest/src/functions/Param.md`:
- Around line 8-56: Update the Param function documentation to accurately
reflect the actual type constraints from the implementation in
packages/protocols-rest/src/libs/decorators/Params.ts. Change the TContract type
constraint from `RouteContractSpec & object` to `RouteContractSpec & { params:
AnyZodObject }`, and update the Name type constraint from simply `string` to the
complete constraint `RoutePathParamName<TContract["path"]> & keyof
RoutePathParams<TContract> & string`. Additionally, resolve the markdown linting
violation (MD024) by removing the duplicate "## Call Signature" heading that
appears in the second overload documentation and replace it with a different
heading structure or use a different approach to distinguish the two function
signatures.

In `@packages/docs/src/content/docs/api/protocols-rest/src/functions/Query.md`:
- Around line 8-56: The documentation for the Query function contains three
issues that need to be corrected. First, update the TContract type parameter
constraint from `RouteContractSpec & object` to `RouteContractSpec & { query:
AnyZodObject }` to match the actual implementation. Second, update the Name type
parameter constraint from simply `string` to `keyof RouteQuery<TContract> &
string` to accurately reflect the constraint used in the implementation. Third,
remove the duplicate "## Call Signature" heading that appears at the second
function overload definition and replace it with a unique heading (such as "##
Call Signature (Schema-based)") to comply with markdown lint rule MD024 which
prohibits duplicate headings.

In
`@packages/docs/src/content/docs/api/protocols-rest/src/functions/ResponseSchema.md`:
- Around line 8-40: Update the ResponseSchema documentation to match its actual
implementation and add missing Korean descriptions. First, change the TContract
type parameter constraint from `RouteContractSpec & object` to
`RouteContractSpec & { response: z.ZodType }` to accurately reflect the
implementation in packages/protocols-rest/src/libs/decorators/ResponseSchema.ts.
Second, add Korean descriptions after each Call Signature section (after the
Returns statements) by including the text "์‘๋‹ต ์Šคํ‚ค๋งˆ๋ฅผ ๋ฉ”์„œ๋“œ์— ๋ฐ”์ธ๋”ฉํ•ฉ๋‹ˆ๋‹ค" for both
overloads, following the same pattern used in the Body and Param decorator
documentation. Third, fix the markdown linting MD024 violation by changing the
second "## Call Signature" heading to a different heading level such as "###" or
providing a unique title to eliminate the duplicate heading.

In
`@packages/docs/src/content/docs/api/protocols-rest/src/functions/routeParamSchema.md`:
- Around line 1-32: The type parameter constraints documented for
routeParamSchema, routeQueryParamSchema, routeBodySchema, and routeQuerySchema
functions do not match their actual TypeScript implementation. The documentation
shows overly generic constraints while the actual implementations have more
specific constraints including specific type extensions like params properties
and keyof restrictions. Review and update the documentation generation logic or
the source documentation to accurately reflect the precise type constraints from
the TypeScript source code, ensuring that TContract and Name parameters include
all the specific type bounds and constraints that exist in the actual
implementation.

In
`@packages/docs/src/content/docs/api/protocols-rest/src/functions/routeQueryParamSchema.md`:
- Around line 1-32: The generated API documentation for the
routeQueryParamSchema function contains inaccurate type parameter constraints
that diverge from the actual implementation. The TContract type parameter
constraint is documented as extending RouteContractSpec & object, but should
extend RouteContractSpec & { query: AnyZodObject } to match the implementation.
The Name type parameter is documented as extending just string, but should
extend keyof RouteQuery<TContract> & string to accurately reflect the actual
constraint. Since this same pattern occurs across multiple files
(routeParamSchema.md, Param.md, Query.md), the fix needs to be applied to the
API documentation generation logic itself rather than individual markdown files,
ensuring all generic type constraints are extracted and represented with
complete accuracy.

In `@packages/protocols-core/src/libs/extractRouteIR.ts`:
- Around line 75-96: The id field assignment in the extractRouteContract
function currently uses operationId as a fallback value when id is missing,
which creates confusion between two independent fields and causes potential
duplication. According to the test expectations and the field definitions, id
and operationId should remain separate. Remove the fallback to
contract.operationId from the id field assignment on line 83 so that id only
uses contract.id directly, ensuring both fields maintain their distinct purposes
and avoid duplication when operationId exists but id does not.

In `@packages/protocols-core/src/libs/RouteIR.ts`:
- Line 9: The routeContract field in the RouteIR type definition uses both the
optional property modifier (?) and null in the union type, allowing three
possible states (undefined, null, or RouteContractIR). However, the runtime
implementation in extractRouteIR.ts always assigns either a RouteContractIR
object or null to this field, never leaving it undefined. Remove the optional
property modifier from routeContract so the type is defined as simply a union of
RouteContractIR or null, without the question mark, to accurately reflect that
the field is always explicitly assigned and will never be undefined.

In `@packages/protocols-core/src/tests/extractRouteIR.spec.ts`:
- Line 235: Remove the explicit `any` type cast `z.ZodObject<any>` used
throughout the test file (there are 6 occurrences total) and replace all
instances with `z.AnyZodObject` instead. This aligns with the codebase coding
guidelines that forbid explicit `any` types in TypeScript files and matches the
pattern already established in sharedTypes.ts.

In `@packages/protocols-rest/src/libs/types/RouteContract.ts`:
- Around line 115-123: The isRouteContractSpec type guard function is too
permissive as it only checks if method and path are strings, which can cause
false positives when used in conditional branches for different overload types.
This leads to objects that are not actual RouteContractSpec instances being
incorrectly classified as such, resulting in runtime errors like
getObjectShape(undefined). Enhance the type guard by adding checks for all
required properties and constraints that define a complete RouteContractSpec
(beyond just method and path), ensuring that only objects matching the full
contract specification return true from this function.
๐Ÿช„ Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

โ„น๏ธ Review info
โš™๏ธ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: daeb15b1-3383-4ae5-a3dd-bf188c9dfa54

๐Ÿ“ฅ Commits

Reviewing files that changed from the base of the PR and between 0ee7f3e and 9c810da.

๐Ÿ“’ Files selected for processing (46)
  • .changeset/contract-first-rest-routes.md
  • packages/create-croco-app/src/tests/templates-build.spec.ts
  • packages/create-croco-app/templates/spa-be-split/README.md.hbs
  • packages/create-croco-app/templates/spa-be-split/apps/api-server/src/controllers/UserController.ts
  • packages/create-croco-app/templates/spa-be-split/apps/api-server/src/controllers/userSchemas.ts
  • packages/docs/src/content/docs/api/protocols-rest/src/functions/Body.md
  • packages/docs/src/content/docs/api/protocols-rest/src/functions/Param.md
  • packages/docs/src/content/docs/api/protocols-rest/src/functions/Query.md
  • packages/docs/src/content/docs/api/protocols-rest/src/functions/ResponseSchema.md
  • packages/docs/src/content/docs/api/protocols-rest/src/functions/defineRouteContract.md
  • packages/docs/src/content/docs/api/protocols-rest/src/functions/isRouteContractSpec.md
  • packages/docs/src/content/docs/api/protocols-rest/src/functions/routeParamSchema.md
  • packages/docs/src/content/docs/api/protocols-rest/src/functions/routeQueryParamSchema.md
  • packages/docs/src/content/docs/api/protocols-rest/src/interfaces/RouteMetadata.md
  • packages/docs/src/content/docs/api/protocols-rest/src/type-aliases/RouteContractSourceLocation.md
  • packages/docs/src/content/docs/api/protocols-rest/src/type-aliases/RouteContractSpec.md
  • packages/docs/src/content/docs/api/protocols-rest/src/variables/All.md
  • packages/docs/src/content/docs/api/protocols-rest/src/variables/Delete.md
  • packages/docs/src/content/docs/api/protocols-rest/src/variables/Get.md
  • packages/docs/src/content/docs/api/protocols-rest/src/variables/Head.md
  • packages/docs/src/content/docs/api/protocols-rest/src/variables/Options.md
  • packages/docs/src/content/docs/api/protocols-rest/src/variables/Patch.md
  • packages/docs/src/content/docs/api/protocols-rest/src/variables/Post.md
  • packages/docs/src/content/docs/api/protocols-rest/src/variables/Put.md
  • packages/docs/src/content/docs/en/guides/schema-source-of-truth.mdx
  • packages/openapi-spec/src/tests/emitOpenAPI.spec.ts
  • packages/protocols-core/src/index.ts
  • packages/protocols-core/src/libs/ContractGraph.ts
  • packages/protocols-core/src/libs/ContractGraphSnapshot.ts
  • packages/protocols-core/src/libs/RouteIR.ts
  • packages/protocols-core/src/libs/extractRouteIR.ts
  • packages/protocols-core/src/libs/sharedTypes.ts
  • packages/protocols-core/src/tests/ContractGraph.spec.ts
  • packages/protocols-core/src/tests/extractRouteIR.spec.ts
  • packages/protocols-rest/README.md
  • packages/protocols-rest/src/libs/decorators/Controller.ts
  • packages/protocols-rest/src/libs/decorators/HttpMethod.ts
  • packages/protocols-rest/src/libs/decorators/Params.ts
  • packages/protocols-rest/src/libs/decorators/ResponseSchema.ts
  • packages/protocols-rest/src/libs/types.ts
  • packages/protocols-rest/src/libs/types/RouteContract.ts
  • packages/protocols-rest/src/libs/types/index.ts
  • packages/protocols-rest/src/tests/RouteContractTypes.spec.ts
  • packages/protocols-rest/src/tests/decorators/Route.spec.ts
  • packages/rpc-codegen/src/tests/codegen.spec.ts
  • public-api-surface.snapshot.json

Comment thread packages/docs/src/content/docs/api/protocols-rest/src/functions/Body.md Outdated
Comment thread packages/docs/src/content/docs/api/protocols-rest/src/functions/Param.md Outdated
Comment thread packages/docs/src/content/docs/api/protocols-rest/src/functions/Query.md Outdated
Comment thread packages/docs/src/content/docs/api/protocols-rest/src/functions/ResponseSchema.md Outdated
Comment thread packages/protocols-core/src/libs/extractRouteIR.ts
Comment thread packages/protocols-core/src/libs/RouteIR.ts Outdated
Comment thread packages/protocols-core/src/tests/extractRouteIR.spec.ts Outdated
Comment thread packages/protocols-rest/src/libs/types/RouteContract.ts Outdated
@kang-heewon
kang-heewon force-pushed the fix/974-contract-first-rest branch from fdbb95f to 1a01621 Compare June 21, 2026 06:03

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

๐Ÿค– Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/cli/src/tests/projectMap.spec.ts`:
- Around line 1-12: Reorder the imports to follow the correct hierarchy:
external packages like vitest should come first, followed by `@croco/`* package
imports, and finally relative imports from "../commands/projectMap.js".
Additionally, within the relative import statement, separate the type imports
(ProjectMapDirent, ProjectMapIo, ProjectMapPackage) into a dedicated type import
statement, keeping the value imports (createProjectMapManifest, runProjectMap,
stringifyProjectMapManifest) in their own separate import statement.
๐Ÿช„ Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

โ„น๏ธ Review info
โš™๏ธ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 539bb2da-beff-41bc-af26-1ed23ff08b9a

๐Ÿ“ฅ Commits

Reviewing files that changed from the base of the PR and between 9c810da and 3c3f933.

๐Ÿ“’ Files selected for processing (5)
  • packages/cli/src/tests/contractsCheck.spec.ts
  • packages/cli/src/tests/contractsDiff.spec.ts
  • packages/cli/src/tests/projectMap.spec.ts
  • packages/create-croco-app/src/tests/templates-build.spec.ts
  • packages/create-croco-app/templates/spa-be-split/README.md.hbs
๐Ÿ’ค Files with no reviewable changes (2)
  • packages/create-croco-app/src/tests/templates-build.spec.ts
  • packages/create-croco-app/templates/spa-be-split/README.md.hbs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

๐Ÿค– Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/cli/src/tests/projectMap.spec.ts`:
- Around line 1-12: Reorder the imports to follow the correct hierarchy:
external packages like vitest should come first, followed by `@croco/`* package
imports, and finally relative imports from "../commands/projectMap.js".
Additionally, within the relative import statement, separate the type imports
(ProjectMapDirent, ProjectMapIo, ProjectMapPackage) into a dedicated type import
statement, keeping the value imports (createProjectMapManifest, runProjectMap,
stringifyProjectMapManifest) in their own separate import statement.
๐Ÿช„ Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

โ„น๏ธ Review info
โš™๏ธ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 539bb2da-beff-41bc-af26-1ed23ff08b9a

๐Ÿ“ฅ Commits

Reviewing files that changed from the base of the PR and between 9c810da and 3c3f933.

๐Ÿ“’ Files selected for processing (5)
  • packages/cli/src/tests/contractsCheck.spec.ts
  • packages/cli/src/tests/contractsDiff.spec.ts
  • packages/cli/src/tests/projectMap.spec.ts
  • packages/create-croco-app/src/tests/templates-build.spec.ts
  • packages/create-croco-app/templates/spa-be-split/README.md.hbs
๐Ÿ’ค Files with no reviewable changes (2)
  • packages/create-croco-app/src/tests/templates-build.spec.ts
  • packages/create-croco-app/templates/spa-be-split/README.md.hbs
๐Ÿ›‘ Comments failed to post (1)
packages/cli/src/tests/projectMap.spec.ts (1)

1-12: โš ๏ธ Potential issue | ๐ŸŸ  Major

๐Ÿงฉ Analysis chain

๐Ÿ Script executed:

#!/bin/bash
# ํŒŒ์ผ ์ƒ๋‹จ import ์„ ์–ธ ํ™•์ธ
sed -n '1,30p' packages/cli/src/tests/projectMap.spec.ts

# ๊ฐ’ import์— inline type specifier๊ฐ€ ์„ž์—ฌ ์žˆ๋Š”์ง€ ํ™•์ธ
rg -nP '^\s*import\s*\{[^}]*\btype\s+[A-Za-z_]\w*' packages/cli/src/tests/projectMap.spec.ts

Repository: croco-dev/framework

Length of output: 1322


Import ์ •๋ ฌ ์ˆœ์„œ์™€ ํƒ€์ž… import ๋ถ„๋ฆฌ๋ฅผ ์ˆ˜์ •ํ•˜์„ธ์š”.

ํ˜„์žฌ @croco/* ํƒ€์ž… import๊ฐ€ ์™ธ๋ถ€ ํŒจํ‚ค์ง€ vitest๋ณด๋‹ค ๋จผ์ € ์„ ์–ธ๋˜์–ด ์žˆ๊ณ , ์ƒ๋Œ€๊ฒฝ๋กœ import์—์„œ ํƒ€์ž…๊ณผ ๊ฐ’์ด ์„ž์—ฌ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝ”๋”ฉ ๊ฐ€์ด๋“œ์— ๋”ฐ๋ผ ์™ธ๋ถ€ ํŒจํ‚ค์ง€ โ†’ @croco/* โ†’ ์ƒ๋Œ€๊ฒฝ๋กœ ์ˆœ์„œ๋กœ ์ •๋ ฌํ•˜๊ณ , ํƒ€์ž… import๋ฅผ ๋ณ„๋„ ์„ ์–ธ์œผ๋กœ ๋ถ„๋ฆฌํ•˜์„ธ์š”.

์ˆ˜์ •์•ˆ
-import type { PolicyTable, RuntimeCapabilityName } from "`@croco/framework-context`";
-import type { FrameworkManifest } from "`@croco/framework-routes`";
-import type { ContractDiagnostic, ContractGraphSnapshot } from "`@croco/protocols-core`";
 import { describe, expect, it } from "vitest";
+import type { PolicyTable, RuntimeCapabilityName } from "`@croco/framework-context`";
+import type { FrameworkManifest } from "`@croco/framework-routes`";
+import type { ContractDiagnostic, ContractGraphSnapshot } from "`@croco/protocols-core`";
+import type {
+  ProjectMapDirent,
+  ProjectMapIo,
+  ProjectMapPackage,
+} from "../commands/projectMap.js";
 import {
   createProjectMapManifest,
   runProjectMap,
   stringifyProjectMapManifest,
-  type ProjectMapDirent,
-  type ProjectMapIo,
-  type ProjectMapPackage,
 } from "../commands/projectMap.js";
๐Ÿ“ Committable suggestion

โ€ผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

import { describe, expect, it } from "vitest";
import type { PolicyTable, RuntimeCapabilityName } from "`@croco/framework-context`";
import type { FrameworkManifest } from "`@croco/framework-routes`";
import type { ContractDiagnostic, ContractGraphSnapshot } from "`@croco/protocols-core`";
import type {
  ProjectMapDirent,
  ProjectMapIo,
  ProjectMapPackage,
} from "../commands/projectMap.js";
import {
  createProjectMapManifest,
  runProjectMap,
  stringifyProjectMapManifest,
} from "../commands/projectMap.js";
๐Ÿค– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/tests/projectMap.spec.ts` around lines 1 - 12, Reorder the
imports to follow the correct hierarchy: external packages like vitest should
come first, followed by `@croco/`* package imports, and finally relative imports
from "../commands/projectMap.js". Additionally, within the relative import
statement, separate the type imports (ProjectMapDirent, ProjectMapIo,
ProjectMapPackage) into a dedicated type import statement, keeping the value
imports (createProjectMapManifest, runProjectMap, stringifyProjectMapManifest)
in their own separate import statement.

Source: Coding guidelines

@kang-heewon
kang-heewon merged commit f3951f3 into trunk Jun 21, 2026
8 checks passed
@kang-heewon
kang-heewon deleted the fix/974-contract-first-rest branch June 21, 2026 07:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant