P0: ローカル環境ブートストラップ(Pythonロジックのみ)
目的: VSCodeで最小の“純ロジック”を動かす(モックで完結)。
作業
- Python 3.11+、venv作成
python -m venv .venv && . .venv/bin/activate(Windowsは.\.venv\Scripts\activate)pip install -U pip
- 依存
pip install pytest ruff black
- ひな形(前回提案のパッケージ名そのまま)
nlq_core/ __init__.py dto.py ports.py sql_guard.py sql_planner.py diff_packager.py usecases.py adapters/ __init__.py mock_ports.py tests/ test_guard.py # 最小1本(SELECT限定/LIMIT付与) - VSCode 推奨設定
- 拡張: Python, Ruff, Black
.vscode/settings.json{ "python.defaultInterpreterPath": ".venv/bin/python", "python.testing.pytestEnabled": true, "editor.formatOnSave": true, "python.formatting.provider": "black", "ruff.lint.args": ["--select=E,F,I,UP","--line-length=100"] }
完了条件
pytest -qが通る- サンプル
demo.pyでhandle_plan()→handle_execute()がモックで動く
P1: Postgres を使った“実行ポート”だけ導入(Odooなし)
目的: SQL実行結果を本物のPostgresで得る(スキーマはダミー)。
作業
docker-compose.yml(最小:アプリ用 Postgres)services: pg: image: postgres:16 environment: POSTGRES_USER: dev POSTGRES_PASSWORD: dev POSTGRES_DB: appdb ports: [ "5432:5432" ] volumes: - ./infra/sql:/docker-entrypoint-initdb.dinfra/sql/001_seed.sql(NLQ用のダミー・テーブル)CREATE TABLE product_product (id serial PRIMARY KEY, name text); CREATE TABLE sale_order (id serial PRIMARY KEY, date_order timestamp); CREATE TABLE sale_order_line (id serial PRIMARY KEY, order_id int, product_id int, price_total numeric); INSERT INTO product_product (name) VALUES ('Product A'), ('Product B'); INSERT INTO sale_order (date_order) VALUES (now()), (now() - interval '10 days'); INSERT INTO sale_order_line (order_id, product_id, price_total) VALUES (1,1,12345),(1,2,9876),(2,1,5000);- アダプタ追加
adapters/pg_ports.pySchemaPort:SELECT 1 FROM information_schema.tables ...table_has_rows:SELECT 1 FROM table LIMIT 1ExecutePort:psycopgでSELECT実行(LIMITはロジックで付与済み)
- 依存
pip install psycopg[binary]==3.2.*
完了条件
handle_plan()が 存在&非空チェックを通し、handle_execute()が Postgresから実データを返す
P2: Metabase 組み込み(お試し運用)
目的: 同じ Postgres を Metabase に接続し、結果をMetabaseで可視化してみる。
作業
docker-compose.ymlに Metabase 追加(メタデータ用DB込みが安定)services: metabase-db: image: postgres:16 environment: POSTGRES_USER: meta POSTGRES_PASSWORD: meta POSTGRES_DB: metabase volumes: [ "metabase-db:/var/lib/postgresql/data" ] metabase: image: metabase/metabase:latest environment: MB_DB_TYPE: postgres MB_DB_DBNAME: metabase MB_DB_PORT: 5432 MB_DB_USER: meta MB_DB_PASS: meta MB_DB_HOST: metabase-db ports: [ "3000:3000" ] depends_on: [ metabase-db ] volumes: { metabase-db: {} }- 初期セットアップ:
http://localhost:3000→ Admin で App DB (pg:5432, db=appdb) をデータソースとして追加 - ダッシュボード/カードを1つ作成(例:製品別売上バー)
- フロント(既存ガワ)に Metabaseの公開リンク or 埋め込みURL を貼る場所だけ用意(いまは手動URLでもOK)
完了条件 - Metabase で App DB が見え、ダミーデータがグラフ化できる
- ガワから Metabase を iframe表示できる(URL直貼りでも可)
P3: “差分パッケージ”プレビュー(Chromaには送らない)
目的: HistoryItem → ChromaPackage までをローカルで生成して確認(Upsertはしない)。
作業
- 既存
diff_packager.pyを使用 - 小さな CLI / Jupyter で、
handle_plan/handle_executeの戻りChromaPackageを JSON保存(/out/chroma_preview/*.json) - VSCode で diff表示(prev→curr)を簡易テキストで確認
完了条件 - 1問→1実行で ChromaPackage の JSONが落ちる
- JSONの
doc_textに SQL・Diff・Used Tables・Outcome が整う
P4: “出力の粒度”と“モード”をスイッチで制御(ロジックのみ)
目的: 「SQLだけ/グラフまで/説明まで/全部」や「dry_run/sample/full」をロジック側で切替できる。
作業
usecases.handle_plan/executeの戻り値にoutput_levelを反映(sql_onlyならSQLのみ返す等)dry_runは 実行せずexplain相当の要約だけ返す分岐を追加
完了条件- スイッチで返却内容が切り替わる(ガワ側のUIに合わせやすい)
P5: テスト・整備(将来の結合に備える)
目的: ロジックの回帰を守りつつ、後でアダプタを差し替えても壊れにくくする。
作業
pytestで ゴールデンテスト(代表NLQ→生成SQLのスナップショット)ruff&blackを pre-commit で有効化pip install pre-commit && pre-commit install
README.mdに セットアップ・起動手順・想定I/O を記載
完了条件pytest -qが安定、pre-commit が動作、READMEの手順で誰でも再現可
P6: バックエンド結合準備(差し替えポイントだけ整える)
目的: オフショアの FastAPI が上がったら一瞬で接続できるようにする。
作業
adapters/fastapi_ports.pyの空クラスだけ用意(実装は後で)SchemaPort→/schema/tables等(仮URL & docstring だけ)ExecutePort→/nlq/executeHistoryPort→/nlq/historyChromaPort→/chroma/package(今は未使用)
.envorconfig.pyにADAPTER=mock|pg|fastapiの切替フラグmain_cli.pyなどで引数や環境で切替
完了条件- アダプタ切替の差し替え面が明確(実装ゼロでもビルドは通る)
実行コマンド(まとめ)
# P0
python -m venv .venv
source .venv/bin/activate
pip install -U pip pytest ruff black psycopg[binary]==3.2.*
# P1/P2: コンテナ起動
docker compose up -d # pg と metabase 起動
# 初回のみ Metabase UI で App DB 接続を設定
# テスト
pytest -q
成果物の見え方
- Pythonロジック:
nlq_core/*(純ロジック & ポート) - 実データ実行:Postgres に対して
ExecutePort(pg)で実走 - Metabase:ローカルで可視化し、URL/iframe をガワに貼る
- 差分学習:
ChromaPackageを JSON で確認(後で/chroma/packageに送るだけ) - 後日結合:
adapters/fastapi_ports.pyに HTTP 実装を入れて 切替
コメントを残す