Skip to content

fix: generate SaaS golden path preset - #819

Merged
kang-heewon merged 3 commits into
trunkfrom
fix/718-saas-golden-path
Jun 16, 2026
Merged

fix: generate SaaS golden path preset#819
kang-heewon merged 3 commits into
trunkfrom
fix/718-saas-golden-path

Conversation

@kang-heewon

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

Copy link
Copy Markdown
Member

Fixes #718.

Summary

create-croco-app --preset saas now generates an installable SaaS golden path baseline that wires tenant, membership, invitation, RBAC/auth, access tuples, billing, metering, entitlements, health, and diagnostics through public Croco package APIs.

The generated app includes REST controllers, contract-first RPC/OpenAPI generation commands, seed/smoke commands, in-memory providers, focused demo tests, and a README quickstart. Unsupported provider/deploy/database combinations are rejected for SaaS in both noninteractive and partial interactive CLI paths.

The generated-app smoke matrix now covers the SaaS preset with install, typecheck, build, test, OpenAPI contract generation, RPC client typecheck, and demo smoke validation.

Verification

  • pnpm --filter create-croco-app exec vitest run src/tests/options.spec.ts
  • pnpm --filter create-croco-app typecheck
  • pnpm --filter create-croco-app test - 49 tests passed.
  • pnpm --filter create-croco-app build
  • pnpm check
  • pnpm changeset-required:check -- --base origin/trunk --head HEAD
  • git diff --check
  • Focused generated SaaS contract:openapi smoke after install.
  • pnpm create-croco-app:smoke - all generated app smoke cases passed, including SaaS typecheck/build/test/OpenAPI contract/demo flow.
  • Pre-push hook passed: full pnpm test 197/197 tasks and full pnpm typecheck 196/196 tasks.

Self-review gates

  • Correctness/regression: PASS. The generated SaaS app installs without manual package edits and passes typecheck, build, unit tests, OpenAPI generation, RPC client typecheck, and end-to-end demo smoke.
  • API/security/compatibility/release: PASS. The preset rejects unsupported provider/deploy/database combinations, generated manifests use published Croco ranges for external installs, and a patch changeset covers create-croco-app.
  • Maintainability/minimality: PASS. The implementation is scoped to create-croco-app preset plumbing, the SaaS template, generator tests, and generated-app smoke coverage.

Independent review

  • Review found one actionable validation gap: partial interactive SaaS invocations could drop unsupported flags before validation. Fixed by validating raw --preset saas CLI options before prompting, with regression coverage for API, web app, database, backend deploy, and frontend deploy flags.

Risk

This preset intentionally uses local in-memory providers for the golden path. Production auth providers, payment providers, persistent storage, admin UI, and multi-region deployment automation remain outside this first SaaS preset slice.

Summary by CodeRabbit

Release Notes

  • New Features

    • create-croco-app --preset saas 명령으로 SaaS 애플리케이션을 위한 "golden path" 기본 구성을 생성할 수 있습니다.
    • SaaS 프리셋은 간소화된 초기화 흐름과 데모 시드/스모크 테스트 기능을 제공합니다.
  • Tests

    • SaaS 프리셋 생성 및 검증을 위한 E2E 및 단위 테스트가 추가되었습니다.

@coderabbitai

coderabbitai Bot commented Jun 16, 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 16 minutes and 37 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.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

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: 1926e10b-f65d-4fe1-8201-08e3150909e2

📥 Commits

Reviewing files that changed from the base of the PR and between ead994c and a6d8908.

📒 Files selected for processing (15)
  • packages/create-croco-app/src/cli.ts
  • packages/create-croco-app/src/helpers/croco-ranges.ts
  • packages/create-croco-app/src/libs/problems/InvalidSaasPresetOptionProblem.ts
  • packages/create-croco-app/src/options.ts
  • packages/create-croco-app/src/tests/e2e-generation.spec.ts
  • packages/create-croco-app/src/tests/options.spec.ts
  • packages/create-croco-app/src/tests/templates-build.spec.ts
  • packages/create-croco-app/templates/saas/apps/api-server/package.json.hbs
  • packages/create-croco-app/templates/saas/apps/api-server/src/controllers/SaasController.ts
  • packages/create-croco-app/templates/saas/apps/api-server/src/inMemoryAdapters.ts
  • packages/create-croco-app/templates/saas/apps/api-server/src/index.ts
  • packages/create-croco-app/templates/saas/apps/api-server/src/problems.ts
  • packages/create-croco-app/templates/saas/apps/api-server/src/saasDemo.ts
  • packages/create-croco-app/templates/saas/apps/api-server/src/tests/SaasDemo.spec.ts
  • scripts/create-croco-app-generated-smoke.mts
📝 Walkthrough

Walkthrough

create-croco-app--preset saas 옵션을 추가한다. CLI 타입/옵션 검증/프롬프트에 saas 분기가 삽입되고, 인메모리 어댑터 7종과 saasDemo.ts 기반의 SaaS 골든 패스 템플릿이 생성된다. REST 컨트롤러, Zod 스키마, 데모 seed/smoke 스크립트가 포함되며, 템플릿 빌드·옵션·E2E·CI 스모크 테스트가 함께 추가된다.

Changes

SaaS Golden Path Preset

Layer / File(s) Summary
CLI 타입 및 지원 옵션 계약 확장
packages/create-croco-app/src/types.ts, packages/create-croco-app/src/supported-options.ts, packages/create-croco-app/src/helpers/croco-ranges.ts, .changeset/saas-golden-path.md
GeneratorOptions.preset 유니온에 "saas" 추가, 지원 프리셋 목록 확장, 외부 패키지 버전 범위를 ^0.0.2로 일괄 정렬, 릴리스 노트 추가.
saas 옵션 검증·정규화·프롬프트 분기
packages/create-croco-app/src/options.ts, packages/create-croco-app/src/prompts.ts, packages/create-croco-app/src/cli.ts
assertSaasOptions 헬퍼 도입 및 validateCliOptions/validateResolvedOptions/normalizeNonInteractiveOptions에 saas 분기 추가. 프롬프트에 saas 선택지 및 early-return 분기 추가. CLI --preset 허용값에 saas 포함 및 generator 동적 import 전환.
generator saas early-return 경로
packages/create-croco-app/src/generator.ts
generate()preset === "saas" 분기를 추가해 blanksaas 템플릿 순차 머지 후 finalize() 조기 반환.
saas 템플릿 워크스페이스 스캐폴드
packages/create-croco-app/templates/saas/package.json.hbs, templates/saas/turbo.json.hbs, templates/saas/README.md.hbs, templates/saas/libs/shared/provider-rpc/...
루트 package.json(turbo 빌드/계약 스크립트), turbo 파이프라인, README 문서, provider-rpc 라이브러리 패키지 스캐폴드 추가.
인메모리 어댑터 구현
packages/create-croco-app/templates/saas/apps/api-server/src/inMemoryAdapters.ts
InMemoryTenantStore, InMemoryAccessProvider, InMemoryMeterRepository, InMemoryUsageStorage(quota 체크/idempotency 포함), InMemoryRedisClient(eval 시뮬레이션), InMemoryEventBus, NoopTxAdapter 7종 구현.
SaaS 런타임 조립 및 데모 플로우
packages/create-croco-app/templates/saas/apps/api-server/src/saasDemo.ts
createSaasRuntime()으로 도메인 컴포넌트 조립, runSaasDemoFlow()에서 테넌트 생성~진단 수집까지 순차 실행, assertSaasDemoSnapshot()으로 스냅샷 검증. 더미 BillingGateway/NotificationService/EventPublisher 포함.
api-server 앱 엔트리포인트·컨트롤러·스키마
templates/saas/apps/api-server/src/app.ts, src/index.ts, src/controllers/..., src/demo/..., apps/api-server/package.json.hbs, apps/api-server/tsconfig.json.hbs
createCrocoApp()(미들웨어+컨트롤러), OperationsController(/ops/health, /ops/diagnostics), SaasController(/saas/demo/seed, /saas/demo/smoke), Zod 스키마 3종, seed/smoke 실행 스크립트, 패키지 설정 파일 추가.
테스트 및 CI 스모크
templates/saas/apps/api-server/src/tests/SaasDemo.spec.ts, src/tests/templates-build.spec.ts, src/tests/options.spec.ts, src/tests/e2e-generation.spec.ts, scripts/create-croco-app-generated-smoke.mts
골든 패스 유닛 테스트, 템플릿 구조 검증(checkSaasStructure), options 정규화/검증 단위 테스트, saas E2E 생성 테스트(assertAllSourceBareImportsDeclared 포함), CI saas-golden-path 스모크 케이스 추가.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant CLI as create-croco-app CLI
    participant Options as options.ts
    participant Generator as generator.ts
    participant Template as saas template

    User->>CLI: --preset saas 실행
    CLI->>Options: validateCliOptions (assertSaasOptions)
    Options-->>CLI: 비호환 플래그 있으면 에러
    CLI->>Options: normalizeNonInteractiveOptions (saas 조기 반환)
    CLI->>Generator: generate(targetDir, {preset: "saas"})
    Generator->>Template: mergeInto("blank")
    Generator->>Template: mergeInto("saas")
    Generator->>Generator: installAgentRules (조건부)
    Generator->>Generator: finalize()
    Generator-->>User: saas 프로젝트 생성 완료
Loading
sequenceDiagram
    participant DemoScript as demo:smoke
    participant runSaasDemoFlow
    participant InMemoryTenantStore
    participant InMemoryAccessProvider
    participant BillingService
    participant MeteringService
    participant HealthCheckService
    participant assertSaasDemoSnapshot

    DemoScript->>runSaasDemoFlow: 실행
    runSaasDemoFlow->>InMemoryTenantStore: 테넌트 생성 및 멤버십/초대 처리
    runSaasDemoFlow->>InMemoryAccessProvider: RBAC 부여 및 권한 체크
    runSaasDemoFlow->>BillingService: 체크아웃 생성 및 구독 저장
    runSaasDemoFlow->>MeteringService: 메터 등록 및 사용량 기록/조회
    runSaasDemoFlow->>HealthCheckService: 헬스/진단 리포트 수집
    runSaasDemoFlow-->>DemoScript: SaasDemoSnapshot 반환
    DemoScript->>assertSaasDemoSnapshot: 스냅샷 검증
    assertSaasDemoSnapshot-->>DemoScript: 통과 또는 에러
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 Pull request title clearly summarizes the main change: implementing the SaaS golden path preset for the create-croco-app CLI tool.
Linked Issues check ✅ Passed All major coding requirements from issue #718 are met: SaaS preset implementation, tenant/membership/invitation/auth/access/billing/metering/entitlements wiring, contract-first API generation, health/diagnostics endpoints, demo flow, and comprehensive test coverage.
Out of Scope Changes check ✅ Passed All changes are scoped to preset plumbing in create-croco-app, the SaaS template, generator tests, and generated-app smoke coverage, with no out-of-scope changes detected.

✏️ 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/718-saas-golden-path

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 16, 2026

Copy link
Copy Markdown

📊 Benchmark Results

❌ Some benchmarks failed

Gate failures

  • Lambda cold-start simulation: p75 214.3μs exceeds baseline 70.2μs by more than 20%
  • Lambda cold-start with headers: p75 145.8μs exceeds baseline 66.7μs by more than 20%
  • Lambda cold-start with binary body: p75 127.6μs exceeds baseline 63.2μs by more than 20%
  • Lambda cold-start with query params: p75 113.4μs exceeds baseline 63.9μs by more than 20%
  • Lambda cold-start with authorizer context: p75 118.4μs exceeds baseline 59.8μs by more than 20%
  • Lambda cold-start realistic scenario: p75 115.2μs exceeds baseline 60.2μs by more than 20%
  • EventBusConfig.start (10 handlers): p75 1.3μs exceeds baseline 0.9μs by more than 20%
  • EventPublisher.publishNow single event: p75 1.5μ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 1.0μs exceeds baseline 0.6μs by more than 20%
  • Container.get singleton (warm): p75 0.4μ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 3.0μs 30.0ms 3.4μs -10.0% -
CrocoApp lambdaHandler (10 controllers) 39.1μs 50.0ms 33.3μs +17.5% -
Lambda cold-start simulation 214.3μs 80.0ms 70.2μs +205.4% -
Lambda cold-start with headers 145.8μs 80.0ms 66.7μs +118.4% -
Lambda cold-start with binary body 127.6μs 80.0ms 63.2μs +102.0% -
Lambda cold-start with query params 113.4μs 80.0ms 63.9μs +77.5% -
Lambda cold-start with authorizer context 118.4μs 80.0ms 59.8μs +98.1% -
Lambda cold-start realistic scenario 115.2μs 80.0ms 60.2μs +91.5% -
EventBusConfig.start (10 handlers) 1.3μs 10.0ms 0.9μs +49.9% -
EventPublisher.publishNow single event 1.5μs 2.0ms 1.1μs +40.6% -
DefaultHandlerResolver.resolve × 10 0.1μs 5.0ms 0.0μs +90.5% -
Container.get singleton (cold) 1.0μs 5.0ms 0.6μs +55.5% -
Container.register × 50 components 11.8μs 10.0ms 12.1μs -2.5% -
Container.validate (50 components) 28.9μs 20.0ms 29.7μs -2.6% -
Container.get singleton (warm) 0.4μs 500.0μs 0.3μs +44.2% -
TelemetryRuntime.init (lambda preset) 1.1ms 200.0ms 69.3ms -98.4% -
lambdaPreset config creation 1.5μs 2.0ms 1.0μs +48.2% -

Updated: 2026-06-16T13:35:26.194Z · Commit: e2e3fd4

@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: 10

🤖 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/create-croco-app/src/options.ts`:
- Around line 258-273: The assertSaasOptions function is throwing generic Error
instances, which violates the RFC 7807 Problem-based error handling guideline.
Replace all throw new Error statements within the assertSaasOptions function
(checking options.api, options.apiHosting, options.backendDeploy,
options.frontendDeploy, options.webApps, and options.db) with appropriate
Problem subclass throws instead of generic Error instances to maintain
consistency with the codebase error handling contract.

In
`@packages/create-croco-app/templates/saas/apps/api-server/src/controllers/SaasController.ts`:
- Around line 6-18: The seedDemo and smokeDemo methods in the SaasController
class are exposed without any protection, allowing external callers to execute
demo flows in production. Add environment or authentication guards to both
methods to prevent execution in production environments. Either implement an
environment check that blocks execution when the app is running in production
mode, or add an authentication decorator that enforces admin-level access. Apply
the same protection to both the seedDemo and smokeDemo methods to ensure demo
endpoints cannot be triggered by unauthorized users in production.

In `@packages/create-croco-app/templates/saas/apps/api-server/src/index.ts`:
- Around line 1-10: The startup code in the main function is missing the
required global initialization of TelemetryRuntime. According to the coding
guidelines for files matching the **/apps/**/*.ts pattern, TelemetryRuntime must
be initialized at application startup at the global scope. Add an import
statement for TelemetryRuntime at the top of the file and then call
TelemetryRuntime.getInstance().init() at the module level (before the void
main() invocation) or as the first statement within the main function to ensure
it runs before any other application logic in createCrocoApp().
- Around line 4-7: The port parsing on line 4 where Number(process.env.PORT ??
3000) is assigned lacks validation, meaning invalid PORT environment variables
(e.g., PORT=abc) will result in NaN being passed directly to app.listen(port) on
line 7, causing runtime failure. Add validation after the port assignment to
check that the parsed port is a valid number (not NaN) and within the valid port
range (1-65535). If validation fails, log an explicit error message and
terminate the process using process.exit(1) before attempting to listen.

In
`@packages/create-croco-app/templates/saas/apps/api-server/src/inMemoryAdapters.ts`:
- Around line 85-105: The code is throwing generic Error instances at lines 86
(in the update method) and 104 (in the updateSettings method) when a tenant is
not found. Replace both occurrences of throw new Error(...) with an appropriate
Problem subclass that aligns with your domain's error handling contract, such as
a NotFoundProblem or equivalent Problem subclass that represents a missing
tenant scenario. This ensures consistent error handling throughout the template
and adheres to the guideline of throwing only Problem subclasses.
- Around line 68-78: The create method in the tenant adapter generates an ID
from the slug using createTenantId and directly sets it in the Map without
checking for duplicates, which silently overwrites existing tenants on ID
collision. Before calling this.tenants.set(tenant.id, tenant), add a check to
verify that tenant.id does not already exist in this.tenants, and if it does
exist, throw an appropriate error to explicitly reject the duplicate instead of
silently overwriting the existing data.

In `@packages/create-croco-app/templates/saas/apps/api-server/src/saasDemo.ts`:
- Around line 482-484: Replace the generic Error thrown when smoke validation
fails with an appropriate Problem subclass. In the condition checking if
failures.length is greater than 0, instead of throwing new Error with the "SaaS
demo smoke failed" message, instantiate and throw the relevant Problem subclass
that aligns with your codebase's error handling standards. This ensures
consistency across the template by using Problem subclasses exclusively for
error handling rather than generic Error instances.
- Around line 134-136: The publish method has two issues: First, replace any
generic Error throws (at line 483) with appropriate Problem subclass throws per
coding guidelines. Second, the singleton state cross-contamination problem
exists because the EventBusConfig singleton is retrieved dynamically in the
publish method via getEventBus(). Instead, capture the eventBus instance once
when the publisher is initialized (in the constructor or initialization code at
lines 149-153) and store it as a field on the publisher class. Then modify the
publish method to use this stored eventBus field directly, rather than
dynamically re-querying getEventBus() each time, so that each runtime instance
maintains its own isolated bus reference.

In
`@packages/create-croco-app/templates/saas/apps/api-server/src/tests/SaasDemo.spec.ts`:
- Around line 4-64: The test suite "SaaS golden path demo" is missing the
required DI Container reset for proper test isolation. Add a beforeEach hook
inside the describe block that calls Container.reset() before each test case.
This hook should be placed at the beginning of the describe block, before all
the it() test declarations, to ensure each test starts with a clean DI Container
state as per the coding guidelines.

In `@scripts/create-croco-app-generated-smoke.mts`:
- Around line 230-236: The validations array in the smoke test is missing a
check for the demo:seed script. Currently it only validates demo:smoke, which
means the demo:seed command could break without failing the validation matrix.
Add a new validation entry to the validations array with a descriptive label
(e.g., "demo seed") and the args property set to ["demo:seed"] to ensure both
seed and smoke demo commands are verified as part of the SaaS golden path smoke
test.
🪄 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: 579bf21c-97b2-433c-810e-0500ad6ef8c7

📥 Commits

Reviewing files that changed from the base of the PR and between 595c786 and ead994c.

📒 Files selected for processing (30)
  • .changeset/saas-golden-path.md
  • packages/create-croco-app/src/cli.ts
  • packages/create-croco-app/src/generator.ts
  • packages/create-croco-app/src/helpers/croco-ranges.ts
  • packages/create-croco-app/src/options.ts
  • packages/create-croco-app/src/prompts.ts
  • packages/create-croco-app/src/supported-options.ts
  • packages/create-croco-app/src/tests/e2e-generation.spec.ts
  • packages/create-croco-app/src/tests/options.spec.ts
  • packages/create-croco-app/src/tests/templates-build.spec.ts
  • packages/create-croco-app/src/types.ts
  • packages/create-croco-app/templates/saas/README.md.hbs
  • packages/create-croco-app/templates/saas/apps/api-server/package.json.hbs
  • packages/create-croco-app/templates/saas/apps/api-server/src/app.ts
  • packages/create-croco-app/templates/saas/apps/api-server/src/controllers/OperationsController.ts
  • packages/create-croco-app/templates/saas/apps/api-server/src/controllers/SaasController.ts
  • packages/create-croco-app/templates/saas/apps/api-server/src/controllers/schemas.ts
  • packages/create-croco-app/templates/saas/apps/api-server/src/demo/seed.ts
  • packages/create-croco-app/templates/saas/apps/api-server/src/demo/smoke.ts
  • packages/create-croco-app/templates/saas/apps/api-server/src/inMemoryAdapters.ts
  • packages/create-croco-app/templates/saas/apps/api-server/src/index.ts
  • packages/create-croco-app/templates/saas/apps/api-server/src/saasDemo.ts
  • packages/create-croco-app/templates/saas/apps/api-server/src/tests/SaasDemo.spec.ts
  • packages/create-croco-app/templates/saas/apps/api-server/tsconfig.json.hbs
  • packages/create-croco-app/templates/saas/libs/shared/provider-rpc/package.json.hbs
  • packages/create-croco-app/templates/saas/libs/shared/provider-rpc/src/index.ts
  • packages/create-croco-app/templates/saas/libs/shared/provider-rpc/tsconfig.json.hbs
  • packages/create-croco-app/templates/saas/package.json.hbs
  • packages/create-croco-app/templates/saas/turbo.json.hbs
  • scripts/create-croco-app-generated-smoke.mts

Comment thread packages/create-croco-app/src/options.ts
Comment thread packages/create-croco-app/templates/saas/apps/api-server/src/index.ts Outdated
Comment thread packages/create-croco-app/templates/saas/apps/api-server/src/index.ts Outdated
Comment thread scripts/create-croco-app-generated-smoke.mts
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.

Croco SaaS Golden Path Kit

1 participant