yongol — AIコーディングSaaSの竜骨

200番目のエンドポイント

バイブコーディングでSaaSを作る。最初は速い。テーブル5つ、エンドポイント12個——20分で動く。

だが50エンドポイントを超えたあたりから、おかしなことが起きる。AIが昨日と矛盾するパターンを今日作る。100を超えると、既存の機能が静かに壊れる。200を超えると、新機能1つの追加に最初の10個の10倍かかる。

モデルが馬鹿なわけではない。


意思決定と実装

ソースコードには3つのものが混在している:

  • ユーザーの意思決定 — このカラムはBIGINT、このエンドポイントはオーナーのみ、ページネーションはカーソル方式。
  • ビジネスロジック — 価格設定、ワークフロー、ライフサイクルルール。
  • 実装の詳細 — 変数名、ライブラリ呼び出し順、エラーラッピング。

AIがこのコードを読むとき、どの行が意思決定でどの行が詳細かを区別できない。だから「リファクタリング」や「クリーンアップ」をするとき、意思決定を詳細と誤認して静かに上書きする。ユーザーが気づくのは、動作がすでにおかしくなった後だ。

これが200エンドポイントでバイブコーディングが崩壊する理由だ。より大きなモデルを使っても解決しない。媒体——生のコード——が意思決定を保存しないからだ。 どのモデルも結局同じ壁にぶつかる。


竜骨

船を造るとき最初に据える骨格が竜骨だ。船体の重量を支え、左右の揺れを防ぎ、他のすべての構造物は竜骨の上に建てられる。竜骨のない船は穏やかな海では浮くが、波が来ると歪む。

バイブコーディングで作ったSaaSも同じだ。小さいうちは浮く。大きくなると歪む。

yongolはAIコーディングSaaSの竜骨だ。


意思決定をコードの外へ

yongolの核心はシンプルだ。意思決定をコードから分離する。

10の宣言的仕様(SSOT)がそれぞれ1つの関心事を担当する:

SSOT関心事
features.yaml機能カタログ — 何を作るか
manifest.yamlプロジェクト設定 — 認証、ミドルウェア、インフラ
OpenAPIAPIコントラクト — ルート、パラメータ、レスポンス
SQL DDL + sqlcデータモデル — テーブル、カラム、制約、クエリ
SSaCサービスフロー — エンドポイント内部の意思決定順序
Rego認可 — 誰が何をできるか
Mermaid stateDiagram状態遷移 — エンティティのライフサイクル
FuncSpecカスタム関数 — CRUDで表現できないロジック
Hurlテストシナリオ — ランタイム検証
STMLフロントエンド — ページ構造とデータバインディング

10のうち8つは業界標準(OpenAPI、SQL、sqlc、Rego、Mermaid、Hurl、YAML)だ。SSaCとSTMLだけがyongolが作ったDSLだ。AIがゼロから学ぶ必要があるものは最小化されている。

各SSOTには意思決定だけが入っている。実装の詳細はない。AIがSSOTを編集し、yongol generateがSSOTからコードをレンダリングする。意思決定はSSOTに永続的に生き、コードは使い捨ての投影だ。


整合性を強制する

意思決定が10のファイルに分散したので、矛盾が生じうる。DDLはBIGINTなのにOpenAPIはstring?SSaCが@authを宣言しているのにRegoに対応するルールがない?状態図に遷移があるのにSSaCに対応する関数がない?

矛盾したSSOTは破損した意思決定だ。コードがどれだけきれいでも、意思決定が矛盾すれば動作は間違う。

yongol validateがこれを捕捉する。

✓ manifest        ✓ openapi_ddl       ✓ ssac_rego
✓ openapi         ✓ openapi_ssac      ✓ ssac_authz
✓ ddl             ✓ hurl_openapi      ✓ ssac_sqlc
✓ query           ✓ hurl_statemachine ✓ ddl_statemachine
✓ ssac            ✓ hurl_manifest     ✓ ddl_rego
✓ statemachine    ✓ openapi_manifest  ✓ rego_manifest
✓ rego            ✓ ssac_ddl          ✓ stml_openapi
✓ hurl            ✓ ssac_statemachine
✓ funcspec        ✓ ssac_func

0 errors, 0 warnings

まず各SSOTを個別に検証し、次にレイヤー間のクロスチェックを実行する。約287のルールが10のSSOT間のすべてのシンボル参照を検査する。矛盾が1つでもあればコンパイルを拒否する。

AIは自由に書く。レールを外れればvalidateが即座に捕捉する。レールの上の自由。


operationIdがキーストーンだ

10のレイヤーをどう結びつけるか?1つのPascalCase識別子で。

operationId ExecuteWorkflowを入力する:

── Feature Chain: ExecuteWorkflow ──

  OpenAPI    api/openapi.yaml                POST /workflows/{id}/execute
  SSaC       service/workflow/execute_workflow.ssac   @get @empty @auth @state @call @publish @response
  DDL        db/workflows.sql                CREATE TABLE workflows
  DDL        db/execution_logs.sql           CREATE TABLE execution_logs
  Rego       policy/authz.rego               resource: workflow
  StateDiag  states/workflow.md              diagram: workflow → ExecuteWorkflow
  FuncSpec   func/billing/check_credits.go   @func billing.CheckCredits
  FuncSpec   func/billing/deduct_credit.go   @func billing.DeductCredit
  FuncSpec   func/worker/process_actions.go  @func worker.ProcessActions
  FuncSpec   func/webhook/deliver.go         @func webhook.Deliver
  Hurl       tests/scenario-happy-path.hurl  scenario: scenario-happy-path.hurl

APIスペックからDBスキーマ、認可ポリシーから状態遷移、関数実装からテストシナリオまで——1つの機能の全トポロジーが1画面に見える。数十回のgrepが1つのコマンドに置き換わる。

operationIdがキーストーンである理由は、フルスタックアプリケーションにおいて機能の単位がAPIエンドポイントだからだ。ユーザーがボタンを押し、APIが呼ばれ、そのAPIが他のすべてのレイヤーを貫通する。1つの名前が10のレイヤーを物理的にチェーンする。


ベンチマーク:ZenFlow

ZenFlow——マルチテナントのワークフロー自動化SaaS。Claude Sonnet 4.6がSSOTを書き、yongolが検証した。

段階内容時間累計
初期ビルドマルチテナント、認証、ステートマシン、テーブル6、エンドポイント1023分23分
+ バージョニングワークフロー複製、バージョン一覧、INSERT…SELECTアクションコピー16分39分
+ Webhookイベント発行、Webhook CRUD、キューバックエンド8分47分
+ テンプレートマーケットプレイスカーソルページネーション、クロスOrg複製、公開エンドポイント7分54分
+ ファイル添付実行レポート、ファイルバックエンド7分61分
+ スケジューリングセッションベースcronスケジュール、TTL10分71分
+ 監査ログキャッシュバックエンド、ページネーション、フィルター6分77分
+ ダッシュボード集約API、リレーション結合、詳細ビュー14分91分
+ バッチ操作アクション一括保存、JSONシリアライゼーション10分101分
+ 外部API連携ジオコーディングAPIインポート、座標保存14分115分
+ 条件付き更新自動割り当て、信頼度スコアリング、条件分岐16分131分

最終結果:30エンドポイント、12テーブル、64テストリクエスト。すべてグリーン。

10個の機能を順次追加した。機能追加で速度が落ちることはなかった。既存のテストが壊れることもなかった。200エンドポイントの壁は存在しなかった。

Opusで同じスペックを実行すると、30エンドポイント、73テストリクエスト、約76分。モデルが変わっても、レールは同じだ。


なぜ大きなモデルが答えではないか

「GPT-6が出れば解決する。」

しない。問題はモデルの知能ではなく媒体だ。

コードという媒体は意思決定と実装を区別しない。どのモデルがコードを読んでも、意思決定と詳細が入り交じったテキストを見る。モデルがどれだけ賢くても、媒体が区別を提供しなければ、モデルは区別できない。

yongolは媒体を変える。AIが編集する対象をコードから宣言的仕様に移す。仕様には意思決定だけがあり実装の詳細がないので、AIが意思決定を詳細と誤認することは決してない。意思決定の生存がモデルサイズから独立する。

小さなLLMがSSOTだけを編集し、validateが毎回のミスに正確なフィードバックを返せば、はるかに大きなモデルが生のコードを編集するのと同じレベルの意思決定整合性を維持できる。yongolがその差を埋める。


はじめる

npx skills add park-jun-woo/yongol

AIエージェント(Claude Code、Cursor、Copilotなど)にyongol skillをインストールすると、エージェントがワークフローを自動的に学習する。

CLIを直接使う場合:

go install github.com/park-jun-woo/yongol/cmd/yongol@latest

git clone https://github.com/park-jun-woo/yongol && cd yongol
yongol validate examples/zenflow

0 errors, 0 warnings.

この仕様の上でAIに機能追加を指示してみてほしい。validateがレールを敷き、AIがレールの上を走る。壁はない。


関連記事

コード:github.com/park-jun-woo/yongol