[{"data":1,"prerenderedAt":1054},["ShallowReactive",2],{"navigation":3,"doc-/backend/migrations":217,"docs-all-paths":999},[4,19,39,63,87,111,127,195,211],{"title":5,"path":6,"stem":7,"children":8},"Welcome","/welcome","01.welcome",[9,11,15],{"title":5,"path":6,"stem":10},"01.welcome/index",{"title":12,"path":13,"stem":14},"Astar とは（5分）","/welcome/product-in-5-min","01.welcome/01.product-in-5-min",{"title":16,"path":17,"stem":18},"事業文脈","/welcome/business-context","01.welcome/02.business-context",{"title":20,"path":21,"stem":22,"children":23},"Getting Started","/getting-started","02.getting-started",[24,27,31,35],{"title":25,"path":21,"stem":26},"はじめかた","02.getting-started/index",{"title":28,"path":29,"stem":30},"リポジトリ取得と環境構築","/getting-started/repo-setup","02.getting-started/01.repo-setup",{"title":32,"path":33,"stem":34},"日々の開発ループ","/getting-started/dev-loop","02.getting-started/02.dev-loop",{"title":36,"path":37,"stem":38},"検証の 4 層","/getting-started/verification-tiers","02.getting-started/03.verification-tiers",{"title":40,"path":41,"stem":42,"children":43},"Architecture","/architecture","03.architecture",[44,47,51,55,59],{"title":45,"path":41,"stem":46},"アーキテクチャ","03.architecture/index",{"title":48,"path":49,"stem":50},"マルチテナンシーと RLS","/architecture/multi-tenancy-rls","03.architecture/01.multi-tenancy-rls",{"title":52,"path":53,"stem":54},"認可モデル","/architecture/authorization","03.architecture/02.authorization",{"title":56,"path":57,"stem":58},"AI サブシステム","/architecture/ai-subsystem","03.architecture/03.ai-subsystem",{"title":60,"path":61,"stem":62},"データモデル","/architecture/data-model","03.architecture/04.data-model",{"title":64,"path":65,"stem":66,"children":67},"Backend","/backend","04.backend",[68,71,75,79,83],{"title":69,"path":65,"stem":70},"バックエンド","04.backend/index",{"title":72,"path":73,"stem":74},"層構造","/backend/layering","04.backend/01.layering",{"title":76,"path":77,"stem":78},"規約","/backend/conventions","04.backend/02.conventions",{"title":80,"path":81,"stem":82},"テスト","/backend/testing","04.backend/03.testing",{"title":84,"path":85,"stem":86},"マイグレーション","/backend/migrations","04.backend/04.migrations",{"title":88,"path":89,"stem":90,"children":91},"Frontend","/frontend","05.frontend",[92,95,99,103,107],{"title":93,"path":89,"stem":94},"フロントエンド","05.frontend/index",{"title":96,"path":97,"stem":98},"モジュール内部構造","/frontend/module-anatomy","05.frontend/01.module-anatomy",{"title":100,"path":101,"stem":102},"API アクセスの一本道","/frontend/api-access-chain","05.frontend/02.api-access-chain",{"title":104,"path":105,"stem":106},"i18n","/frontend/i18n","05.frontend/03.i18n",{"title":108,"path":109,"stem":110},"デザインシステム","/frontend/design-system","05.frontend/04.design-system",{"title":112,"path":113,"stem":114,"children":115},"Go Agent And Cli","/go-agent-and-cli","06.go-agent-and-cli",[116,119,123],{"title":117,"path":113,"stem":118},"Go agent と CLI","06.go-agent-and-cli/index",{"title":120,"path":121,"stem":122},"Go agent","/go-agent-and-cli/go-agent","06.go-agent-and-cli/01.go-agent",{"title":124,"path":125,"stem":126},"CLI","/go-agent-and-cli/cli","06.go-agent-and-cli/02.cli",{"title":128,"path":129,"stem":130,"children":131},"Modules","/modules","07.modules",[132,135,139,143,147,151,155,159,163,167,171,175,179,183,187,191],{"title":133,"path":129,"stem":134},"モジュール","07.modules/index",{"title":136,"path":137,"stem":138},"テーブル","/modules/table","07.modules/01.table",{"title":140,"path":141,"stem":142},"ドキュメントツリー","/modules/document","07.modules/02.document",{"title":144,"path":145,"stem":146},"AIチャット","/modules/ai","07.modules/03.ai",{"title":148,"path":149,"stem":150},"認証・権限","/modules/auth","07.modules/04.auth",{"title":152,"path":153,"stem":154},"AI取込","/modules/organize","07.modules/05.organize",{"title":156,"path":157,"stem":158},"ストレージ","/modules/storage","07.modules/06.storage",{"title":160,"path":161,"stem":162},"NAS同期","/modules/sync","07.modules/07.sync",{"title":164,"path":165,"stem":166},"ワークスペース","/modules/workspace","07.modules/08.workspace",{"title":168,"path":169,"stem":170},"テナントとメンバーシップ","/modules/tenant-membership","07.modules/09.tenant-membership",{"title":172,"path":173,"stem":174},"検索","/modules/search","07.modules/10.search",{"title":176,"path":177,"stem":178},"表示ビュー","/modules/display","07.modules/11.display",{"title":180,"path":181,"stem":182},"テンプレート","/modules/template","07.modules/12.template",{"title":184,"path":185,"stem":186},"メール","/modules/mail","07.modules/13.mail",{"title":188,"path":189,"stem":190},"電話","/modules/phone","07.modules/14.phone",{"title":192,"path":193,"stem":194},"リアルタイム","/modules/realtime","07.modules/15.realtime",{"title":196,"path":197,"stem":198,"children":199},"Infra And Deploy","/infra-and-deploy","08.infra-and-deploy",[200,203,207],{"title":201,"path":197,"stem":202},"インフラとデプロイ","08.infra-and-deploy/index",{"title":204,"path":205,"stem":206},"環境の種類","/infra-and-deploy/environments","08.infra-and-deploy/01.environments",{"title":208,"path":209,"stem":210},"セルフホスト構成","/infra-and-deploy/self-host","08.infra-and-deploy/02.self-host",{"title":212,"path":213,"stem":214,"children":215},"docs-map","/docs-map","09.docs-map/index",[216],{"title":212,"path":213,"stem":214},{"id":218,"title":84,"body":219,"description":993,"extension":994,"meta":995,"navigation":996,"path":85,"seo":997,"stem":86,"__hash__":998},"docs/04.backend/04.migrations.md",{"type":220,"value":221,"toc":979},"minimark",[222,225,239,244,255,275,286,290,296,335,338,346,353,358,376,409,412,418,458,465,493,496,499,576,589,593,603,689,723,753,757,812,830,834,854,869,873,899,903,918,922,969,975],[223,224,84],"h1",{"id":84},[226,227,228,229,233,234,238],"p",{},"スキーマ変更は Flyway で管理していて、本番に一度適用したファイルは",[230,231,232],"strong",{},"元に戻せません","。不明点があれば書く前にユーザーに確認する、というのが ",[235,236,237],"code",{},"backend/src/main/resources/db/migration/CLAUDE.md","（このディレクトリの正本）の一貫した姿勢です。",[240,241,243],"h2",{"id":242},"exposed-first-ワークフロー","Exposed-first ワークフロー",[226,245,246,247,250,251,254],{},"Astar は Exposed ORM を使っていて（JPA ではありません、",[248,249,76],"a",{"href":77}," 参照）、",[230,252,253],{},"Exposed table object がカラム定義の SSoT"," です。構造変更（新規テーブル・カラム追加/変更）は次の順で進めます。",[256,257,258,266,272],"ol",{},[259,260,261,262,265],"li",{},"Exposed table object（",[235,263,264],{},"core/{module}/infrastructure/persistence/table/{Entity}sTable.kt","）を作成・変更する",[259,267,268,271],{},[235,269,270],{},"./gradlew generateMigration -Pdescription=\"...\""," を実行する — 新テーブルには RLS と標準制約が自動付与される",[259,273,274],{},"生成された SQL をレビューし、複合 FK の TODO コメントを解決する",[226,276,277,278,281,282,285],{},"一方、SECURITY DEFINER 関数・CHECK 制約・インデックス最適化・seed データのような",[230,279,280],{},"非構造的な変更","は、Exposed table object を経由せず手動で SQL を書きます。この場合も ",[235,283,284],{},"db/migration/CLAUDE.md"," のチェックリストに従います。",[240,287,289],{"id":288},"v-番号運用","V 番号運用",[226,291,292,295],{},[230,293,294],{},"次の番号は filesystem が SSoT"," です。着手直前に必ず確認します。",[297,298,303],"pre",{"className":299,"code":300,"language":301,"meta":302,"style":302},"language-bash shiki shiki-themes github-light github-dark","ls backend/src/main/resources/db/migration/V*.sql | tail -1\n","bash","",[235,304,305],{"__ignoreMap":302},[306,307,310,314,318,322,325,329,332],"span",{"class":308,"line":309},"line",1,[306,311,313],{"class":312},"sScJk","ls",[306,315,317],{"class":316},"sZZnC"," backend/src/main/resources/db/migration/V",[306,319,321],{"class":320},"sj4cs","*",[306,323,324],{"class":316},".sql",[306,326,328],{"class":327},"szBVR"," |",[306,330,331],{"class":312}," tail",[306,333,334],{"class":320}," -1\n",[226,336,337],{},"ハードコードした番号を使い回さないでください。実際、直近の履歴には欠番があります。",[297,339,344],{"className":340,"code":342,"language":343},[341],"language-text","V412  V413  (V414 は存在しない)  V415  V416 ...\n","text",[235,345,342],{"__ignoreMap":302},[226,347,348,349,352],{},"これは事故ではなく、後述する ",[235,350,351],{},"/wt ship"," の自動 renumber ゲートが生んだ意図的な欠番です。番号は「連番」であることより「重複しない」ことの方が重要です。",[354,355,357],"h3",{"id":356},"並行-worktree-での採番衝突は構造的に起きる","並行 worktree での採番衝突は構造的に起きる",[226,359,360,361,364,365,368,369,372,373],{},"Astar は複数の worktree（並行 AI エージェントセッション）で同時に開発が進みます。あるブランチを作った時点で ",[235,362,363],{},"ls V*.sql | tail -1"," が ",[235,366,367],{},"V420"," を返しても、別の worktree が同時に ",[235,370,371],{},"V420__foo.sql"," を作っていれば、後から merge しようとした側は衝突します。",[230,374,375],{},"これは 3 回連続で実際に起きたことがある、珍しくない事故パターンです。",[377,378,379,386,399,406],"ul",{},[259,380,381,382,385],{},"ブランチ作成時点で採番した番号は",[230,383,384],{},"仮番","だと理解してください。",[259,387,388,390,391,394,395,398],{},[235,389,351],{}," が merge 直前に、そのブランチで新規追加されたマイグレーションを ",[235,392,393],{},"main"," の ",[235,396,397],{},"max+1.."," へ機械的に renumber します。手動で番号を付け替える必要はありません。",[259,400,401,402,405],{},"「空いている番号」を判断するときは、自分の worktree だけでなく",[230,403,404],{},"全ブランチ横断","で確認するのが正確です。最終的に正しいのは「DB に適用済みの番号」であって、ローカルのファイル一覧だけではありません。",[259,407,408],{},"renumber の結果生まれる欠番（上記の V414 のようなもの）は許容されます。",[240,410,411],{"id":411},"ファイル命名とヘッダー",[297,413,416],{"className":414,"code":415,"language":343},[341],"V{NNN}__{snake_case_description}.sql     ← ダブルアンダースコア必須\n",[235,417,415],{"__ignoreMap":302},[297,419,423],{"className":420,"code":421,"language":422,"meta":302,"style":302},"language-sql shiki shiki-themes github-light github-dark","-- ============================================================================\n-- V{NNN}: {タイトル}\n-- ============================================================================\n-- Purpose: {なぜこのマイグレーションが必要か}\n-- Tables affected: {カンマ区切り}\n-- ============================================================================\n","sql",[235,424,425,430,436,441,447,453],{"__ignoreMap":302},[306,426,427],{"class":308,"line":309},[306,428,429],{},"-- ============================================================================\n",[306,431,433],{"class":308,"line":432},2,[306,434,435],{},"-- V{NNN}: {タイトル}\n",[306,437,439],{"class":308,"line":438},3,[306,440,429],{},[306,442,444],{"class":308,"line":443},4,[306,445,446],{},"-- Purpose: {なぜこのマイグレーションが必要か}\n",[306,448,450],{"class":308,"line":449},5,[306,451,452],{},"-- Tables affected: {カンマ区切り}\n",[306,454,456],{"class":308,"line":455},6,[306,457,429],{},[226,459,460,461,464],{},"実例（",[235,462,463],{},"V420__storage_device_roots.sql","）:",[297,466,468],{"className":420,"code":467,"language":422,"meta":302,"style":302},"-- ============================================================================\n-- V420: storage_device_roots — multi-root virtual mount namespace\n-- ============================================================================\n-- Purpose: Storage Device Multi-Root design\n--          (docs/designs/2026-07-10-device-multi-root.md §3). ...\n",[235,469,470,474,479,483,488],{"__ignoreMap":302},[306,471,472],{"class":308,"line":309},[306,473,429],{},[306,475,476],{"class":308,"line":432},[306,477,478],{},"-- V420: storage_device_roots — multi-root virtual mount namespace\n",[306,480,481],{"class":308,"line":438},[306,482,429],{},[306,484,485],{"class":308,"line":443},[306,486,487],{},"-- Purpose: Storage Device Multi-Root design\n",[306,489,490],{"class":308,"line":449},[306,491,492],{},"--          (docs/designs/2026-07-10-device-multi-root.md §3). ...\n",[240,494,495],{"id":495},"新テーブルの必須要素",[226,497,498],{},"新しいテーブルには次のカラムと制約が必須です。",[297,500,502],{"className":420,"code":501,"language":422,"meta":302,"style":302},"CREATE TABLE public.{table_name} (\n    id                 BIGINT GENERATED ALWAYS AS IDENTITY,\n    public_id          UUID   NOT NULL DEFAULT gen_random_uuid(),\n    tenant_id          BIGINT NOT NULL,\n    -- ドメインカラム --\n    created_by_user_id BIGINT,                                       -- V042 命名標準\n    created_at         TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,\n    updated_at         TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,\n    version            BIGINT NOT NULL DEFAULT 0,\n    CONSTRAINT {table}_pkey         PRIMARY KEY (id),\n    CONSTRAINT {table}_public_id_key UNIQUE (public_id),\n    CONSTRAINT {table}_tenant_id_id_unique UNIQUE (tenant_id, id)    -- 複合FK参照先\n);\n",[235,503,504,509,514,519,524,529,534,540,546,552,558,564,570],{"__ignoreMap":302},[306,505,506],{"class":308,"line":309},[306,507,508],{},"CREATE TABLE public.{table_name} (\n",[306,510,511],{"class":308,"line":432},[306,512,513],{},"    id                 BIGINT GENERATED ALWAYS AS IDENTITY,\n",[306,515,516],{"class":308,"line":438},[306,517,518],{},"    public_id          UUID   NOT NULL DEFAULT gen_random_uuid(),\n",[306,520,521],{"class":308,"line":443},[306,522,523],{},"    tenant_id          BIGINT NOT NULL,\n",[306,525,526],{"class":308,"line":449},[306,527,528],{},"    -- ドメインカラム --\n",[306,530,531],{"class":308,"line":455},[306,532,533],{},"    created_by_user_id BIGINT,                                       -- V042 命名標準\n",[306,535,537],{"class":308,"line":536},7,[306,538,539],{},"    created_at         TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,\n",[306,541,543],{"class":308,"line":542},8,[306,544,545],{},"    updated_at         TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,\n",[306,547,549],{"class":308,"line":548},9,[306,550,551],{},"    version            BIGINT NOT NULL DEFAULT 0,\n",[306,553,555],{"class":308,"line":554},10,[306,556,557],{},"    CONSTRAINT {table}_pkey         PRIMARY KEY (id),\n",[306,559,561],{"class":308,"line":560},11,[306,562,563],{},"    CONSTRAINT {table}_public_id_key UNIQUE (public_id),\n",[306,565,567],{"class":308,"line":566},12,[306,568,569],{},"    CONSTRAINT {table}_tenant_id_id_unique UNIQUE (tenant_id, id)    -- 複合FK参照先\n",[306,571,573],{"class":308,"line":572},13,[306,574,575],{},");\n",[226,577,578,581,582,585,586,588],{},[235,579,580],{},"id","（内部 BIGINT）と ",[235,583,584],{},"public_id","（API に露出する UUID）の dual-ID は全テーブル共通のパターンです。詳しくは ",[248,587,76],{"href":77}," の ID 命名を参照してください。",[240,590,592],{"id":591},"rls-ポリシー-4-種類必須","RLS ポリシー — 4 種類必須",[226,594,595,596,598,599,602],{},"Astar のマルチテナント分離は DB 側の Row Level Security で強制されています（全体像は ",[248,597,48],{"href":49}," を先に読んでください）。新しいテナントスコープテーブルには ",[230,600,601],{},"ENABLE + FORCE + 4 ポリシー全て","が必須です。",[297,604,606],{"className":420,"code":605,"language":422,"meta":302,"style":302},"ALTER TABLE public.{table} ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.{table} FORCE ROW LEVEL SECURITY;\n\nCREATE POLICY {table}_tenant_select ON public.{table}\n    FOR SELECT USING (tenant_id = public.current_tenant_id());\n\nCREATE POLICY {table}_tenant_insert ON public.{table}\n    FOR INSERT WITH CHECK (tenant_id = public.current_tenant_id());\n\nCREATE POLICY {table}_tenant_update ON public.{table}\n    FOR UPDATE\n    USING     (tenant_id = public.current_tenant_id())\n    WITH CHECK (tenant_id = public.current_tenant_id());          -- ← 両方必須\n\nCREATE POLICY {table}_tenant_delete ON public.{table}\n    FOR DELETE USING (tenant_id = public.current_tenant_id());\n",[235,607,608,613,618,624,629,634,638,643,648,652,657,662,667,672,677,683],{"__ignoreMap":302},[306,609,610],{"class":308,"line":309},[306,611,612],{},"ALTER TABLE public.{table} ENABLE ROW LEVEL SECURITY;\n",[306,614,615],{"class":308,"line":432},[306,616,617],{},"ALTER TABLE public.{table} FORCE ROW LEVEL SECURITY;\n",[306,619,620],{"class":308,"line":438},[306,621,623],{"emptyLinePlaceholder":622},true,"\n",[306,625,626],{"class":308,"line":443},[306,627,628],{},"CREATE POLICY {table}_tenant_select ON public.{table}\n",[306,630,631],{"class":308,"line":449},[306,632,633],{},"    FOR SELECT USING (tenant_id = public.current_tenant_id());\n",[306,635,636],{"class":308,"line":455},[306,637,623],{"emptyLinePlaceholder":622},[306,639,640],{"class":308,"line":536},[306,641,642],{},"CREATE POLICY {table}_tenant_insert ON public.{table}\n",[306,644,645],{"class":308,"line":542},[306,646,647],{},"    FOR INSERT WITH CHECK (tenant_id = public.current_tenant_id());\n",[306,649,650],{"class":308,"line":548},[306,651,623],{"emptyLinePlaceholder":622},[306,653,654],{"class":308,"line":554},[306,655,656],{},"CREATE POLICY {table}_tenant_update ON public.{table}\n",[306,658,659],{"class":308,"line":560},[306,660,661],{},"    FOR UPDATE\n",[306,663,664],{"class":308,"line":566},[306,665,666],{},"    USING     (tenant_id = public.current_tenant_id())\n",[306,668,669],{"class":308,"line":572},[306,670,671],{},"    WITH CHECK (tenant_id = public.current_tenant_id());          -- ← 両方必須\n",[306,673,675],{"class":308,"line":674},14,[306,676,623],{"emptyLinePlaceholder":622},[306,678,680],{"class":308,"line":679},15,[306,681,682],{},"CREATE POLICY {table}_tenant_delete ON public.{table}\n",[306,684,686],{"class":308,"line":685},16,[306,687,688],{},"    FOR DELETE USING (tenant_id = public.current_tenant_id());\n",[377,690,691,705,712],{},[259,692,693,696,697,700,701,704],{},[230,694,695],{},"絶対禁止",": ",[235,698,699],{},"current_setting('app.current_tenant_id')"," の直接使用。必ず ",[235,702,703],{},"public.current_tenant_id()"," 関数を経由します。",[259,706,707,708,711],{},"UPDATE ポリシーの ",[235,709,710],{},"WITH CHECK"," を忘れると、行を別テナントに書き換えられてしまいます（実際に過去バージョンで一括修正が入った実例があります）。",[259,713,714,715,718,719,722],{},"参照先には ",[235,716,717],{},"UNIQUE(tenant_id, id)"," が必要で、子テーブルからの FK はシングル FK ではなく複合 FK ",[235,720,721],{},"(tenant_id, parent_id)"," にします — シングル FK はクロステナント参照を防げません。",[226,724,725,726,729,730,733,734,737,738,737,741,744,745,748,749,752],{},"すべての新規テーブルに RLS が付くとは限りません。除外リストの SSoT はコード側の ",[235,727,728],{},"architecture/RlsCoverageExemptions.kt"," です（",[235,731,732],{},"AUTH_METADATA"," = 認証フロー自体が使う ",[235,735,736],{},"users","/",[235,739,740],{},"tenants",[235,742,743],{},"roles"," 等、",[235,746,747],{},"GLOBAL_NO_TENANT"," = ",[235,750,751],{},"tenant_id"," 列自体を持たない全テナント共有テーブルなど）。この一覧に新規テーブルを追加してよいかは必ずコード側を見て判断してください — ドキュメントの記述は古くなることがあります。",[240,754,756],{"id":755},"security-definer-関数","SECURITY DEFINER 関数",[297,758,760],{"className":420,"code":759,"language":422,"meta":302,"style":302},"CREATE OR REPLACE FUNCTION public.{fn_name}({params})\n    RETURNS {type}\n    LANGUAGE plpgsql\n    SECURITY DEFINER\n    SET search_path TO 'public'             -- 必須\nAS $$\nBEGIN\n    ...\nEND;\n$$;\n",[235,761,762,767,772,777,782,787,792,797,802,807],{"__ignoreMap":302},[306,763,764],{"class":308,"line":309},[306,765,766],{},"CREATE OR REPLACE FUNCTION public.{fn_name}({params})\n",[306,768,769],{"class":308,"line":432},[306,770,771],{},"    RETURNS {type}\n",[306,773,774],{"class":308,"line":438},[306,775,776],{},"    LANGUAGE plpgsql\n",[306,778,779],{"class":308,"line":443},[306,780,781],{},"    SECURITY DEFINER\n",[306,783,784],{"class":308,"line":449},[306,785,786],{},"    SET search_path TO 'public'             -- 必須\n",[306,788,789],{"class":308,"line":455},[306,790,791],{},"AS $$\n",[306,793,794],{"class":308,"line":536},[306,795,796],{},"BEGIN\n",[306,798,799],{"class":308,"line":542},[306,800,801],{},"    ...\n",[306,803,804],{"class":308,"line":548},[306,805,806],{},"END;\n",[306,808,809],{"class":308,"line":554},[306,810,811],{},"$$;\n",[226,813,814,817,818,821,822,825,826,829],{},[235,815,816],{},"SET search_path TO 'public'"," は必須です。Cloud SQL の ",[235,819,820],{},"cloudsqlsuperuser"," は ",[235,823,824],{},"BYPASSRLS"," を持たない（真の PostgreSQL superuser ではない）ため、SECURITY DEFINER 関数が INSERT/UPDATE するテーブルには",[230,827,828],{},"対応する RLS ポリシーが必ず必要","です。ここが欠けると dev では気付かず、Cloud SQL 本番だけで失敗します（過去に実際に発生したパターンです）。",[240,831,833],{"id":832},"check-制約","CHECK 制約",[297,835,837],{"className":420,"code":836,"language":422,"meta":302,"style":302},"ALTER TABLE public.{t} DROP CONSTRAINT IF EXISTS ck_{t}_{col}_valid;\nALTER TABLE public.{t} ADD  CONSTRAINT ck_{t}_{col}_valid\n    CHECK ({col}::text = ANY(ARRAY['VAL1','VAL2']));\n",[235,838,839,844,849],{"__ignoreMap":302},[306,840,841],{"class":308,"line":309},[306,842,843],{},"ALTER TABLE public.{t} DROP CONSTRAINT IF EXISTS ck_{t}_{col}_valid;\n",[306,845,846],{"class":308,"line":432},[306,847,848],{},"ALTER TABLE public.{t} ADD  CONSTRAINT ck_{t}_{col}_valid\n",[306,850,851],{"class":308,"line":438},[306,852,853],{},"    CHECK ({col}::text = ANY(ARRAY['VAL1','VAL2']));\n",[226,855,856,857,860,861,864,865,868],{},"既存の CHECK 制約を変更するときは、先に ",[235,858,859],{},"DROP CONSTRAINT IF EXISTS"," してから ",[235,862,863],{},"ADD CONSTRAINT"," するのが標準パターンです（直近の実例: ",[235,866,867],{},"V422__add_astar_cli_to_usage_provider_check.sql","）。",[240,870,872],{"id":871},"大きいテーブルへの変更は-expand-contract","大きいテーブルへの変更は expand-contract",[226,874,875,876,879,880,883,884,887,888,891,892,895,896,898],{},"推定 100K 行を超えるテーブルへの ",[235,877,878],{},"UPDATE"," 全行バックフィル・",[235,881,882],{},"SET NOT NULL","・",[235,885,886],{},"CREATE INDEX","（非 CONCURRENTLY）などを 1 マイグレーションの単一トランザクションで行うと、ロックを長時間保持して本番の書き込みをブロックします。実際にこれが原因で 30 分の本番ダウンが発生した事故があり、以後 100K 行超のテーブルへのこの種の変更は expand（即時 DDL）→ backfill（別 migration・バッチ）→ contract（",[235,889,890],{},"VALIDATE CONSTRAINT"," 等の online 操作）の 3 段階に分けることが必須になっています。",[235,893,894],{},"SET LOCAL statement_timeout = 0"," のようにタイムアウトを外すのは対症療法であって許可されていません。詳細な手順は ",[235,897,284],{}," の該当節を参照してください。",[240,900,902],{"id":901},"fixture-demo-データは-migration-に書かない","Fixture / demo データは migration に書かない",[226,904,905,906,909,910,913,914,917],{},"Migration は application layer をバイパスするため、",[235,907,908],{},"PropertyDefinition.validate()"," のようなバリデーションが一切走りません。デモテナントの content は ",[235,911,912],{},"shared/mock-data/*.json"," を SSoT とし、Service 層経由の idempotent upsert で投入されます。Migration で許可されるデータ操作は、アプリケーション起動前に存在が必要な core entity（SYSTEM user・DEMO tenant 等）と、テナント/ユーザーに依存しない reference data（",[235,915,916],{},"billing_plans"," 等）だけです。",[240,919,921],{"id":920},"提出前セルフチェック抜粋","提出前セルフチェック(抜粋)",[377,923,924,930,936,942,956,966],{},[259,925,926,927,929],{},"バージョン番号が最新 +1（または ",[235,928,351],{}," が renumber する前提でギャップを許容）",[259,931,932,933],{},"ファイル名がダブルアンダースコア ",[235,934,935],{},"V{NNN}__",[259,937,938,939],{},"全 DROP 文に ",[235,940,941],{},"IF EXISTS",[259,943,944,945,947,948,947,950,947,952,955],{},"新テーブルなら ",[235,946,580],{}," / ",[235,949,584],{},[235,951,751],{},[235,953,954],{},"version"," すべてある",[259,957,958,959,962,963,965],{},"ENABLE + FORCE + 4 ポリシー全部あり、UPDATE ポリシーに ",[235,960,961],{},"USING"," と ",[235,964,710],{}," 両方",[259,967,968],{},"100K 行超のテーブルなら expand-contract を検討したか",[226,970,971,972,974],{},"全項目は ",[235,973,284],{}," の「提出前セルフチェック」節にあります。書き始める前に一度目を通してください。",[976,977,978],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":302,"searchDepth":432,"depth":432,"links":980},[981,982,985,986,987,988,989,990,991,992],{"id":242,"depth":432,"text":243},{"id":288,"depth":432,"text":289,"children":983},[984],{"id":356,"depth":438,"text":357},{"id":411,"depth":432,"text":411},{"id":495,"depth":432,"text":495},{"id":591,"depth":432,"text":592},{"id":755,"depth":432,"text":756},{"id":832,"depth":432,"text":833},{"id":871,"depth":432,"text":872},{"id":901,"depth":432,"text":902},{"id":920,"depth":432,"text":921},"Flyway V 番号運用、RLS / SECURITY DEFINER / CHECK 制約の migration 規約、並行 worktree での採番衝突、Exposed-first ワークフロー。","md",{},{"title":84},{"title":84,"description":993},"49STodOoFaLz20H7LLQJBGn_1uACCkd_Lptf3r3iuDY",[1000,1002,1003,1005,1006,1007,1008,1009,1010,1011,1012,1013,1015,1016,1017,1018,1019,1021,1022,1023,1024,1025,1027,1029,1031,1032,1033,1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1049,1050,1051,1052],{"path":13,"title":1001},"Astar とは何か（5分で）",{"path":17,"title":16},{"path":6,"title":1004},"ようこそ",{"path":29,"title":28},{"path":33,"title":32},{"path":37,"title":36},{"path":21,"title":25},{"path":49,"title":48},{"path":53,"title":52},{"path":57,"title":56},{"path":61,"title":60},{"path":41,"title":1014},"システムアーキテクチャ",{"path":73,"title":72},{"path":77,"title":76},{"path":81,"title":80},{"path":85,"title":84},{"path":65,"title":1020},"バックエンドガイド",{"path":97,"title":96},{"path":101,"title":100},{"path":105,"title":104},{"path":109,"title":108},{"path":89,"title":1026},"フロントエンドガイド",{"path":121,"title":1028},"Go agent — NAS 同期エージェント",{"path":125,"title":1030},"astar CLI",{"path":113,"title":117},{"path":137,"title":136},{"path":141,"title":140},{"path":145,"title":144},{"path":149,"title":148},{"path":153,"title":152},{"path":157,"title":156},{"path":161,"title":160},{"path":165,"title":164},{"path":169,"title":168},{"path":173,"title":172},{"path":177,"title":176},{"path":181,"title":180},{"path":185,"title":184},{"path":189,"title":188},{"path":193,"title":192},{"path":129,"title":1048},"モジュール索引",{"path":205,"title":204},{"path":209,"title":208},{"path":197,"title":201},{"path":213,"title":1053},"docs/ 地図",1785452455058]