コンテンツにスキップ

Admin UI を使う

Admin UI は、Kozou がデータベースから生成する 3 つのサーフェスの 1 つです。あなたがスキャフォールドしたり手書きしたりするものではありません。@kozou/svelte-ui は、@kozou/introspect@kozou/core があなたの CREATE TABLECREATE VIEWCOMMENT ON 文から構築するスキーマを読み取り、イントロスペクトされたスキーマ内のすべてのテーブルとビューに対して、閲覧・編集可能なインターフェースをレンダリングします。カラムを追加し、新しい COMMENT を出荷すれば、次回起動時に UI がそれを反映します。同期を保つべき別個の UI コードベースは存在しません。

このページは実践的なウォークスルーです。サーバーを起動し、ダッシュボードを読み、リストビューを操作し、行を作成・編集します。COMMENT のテキストがここで見えるラベルや入力にどうなるかについては、COMMENT 規約 を参照してください。プロジェクトレベルのオーバーライドについては、ui-hints を参照してください。

kozou dev は、バンドルされた @kozou/svelte-ui Admin UI を MCP HTTP サーバーと並べて実行します。どちらもあなたの kozou.config.yaml から配線されています:

Terminal window
kozou dev

Admin UI はデフォルトでポート 3333 を、MCP HTTP サーバーは 3334 をリッスンします。UI は次の場所で開いてください:

http://localhost:3333

Ctrl-C (SIGINT / SIGTERM) で両方のサーバーが終了します。create-kozou でプロジェクトをスキャフォールドした場合、これは生成された docker-compose.yml 内で kozou サービスが実行するのと同じコマンドなので、docker compose up で同じポートに UI が立ち上がります。ポートを変更するには、kozou.config.yamlserver.ui.port を設定してください。コマンドの全サーフェスとフラグについては、kozou dev を参照してください。

v0.1.1 では、UI の背後にある REST サーフェスは PostgREST によって提供されます。v0.2 系列は 実験的な 自社製 REST レイヤー @kozou/api を追加し、kozou dev --adapter api で選択できます。実験的 API を参照してください。いずれの場合も Admin UI は変わりません。1 つのアダプターインターフェースを通じてバックエンドと通信します。

ルートルート (/) がダッシュボードです。イントロスペクトされたスキーマ内のすべてのテーブルとすべてのビューを 2 つのセクションに一覧表示します:

  • Tables — 各エントリは、行の読み取り・作成・編集・削除ができるそのテーブルのリストビューへリンクします。
  • Views — 各エントリは読み取り専用のリストビューへリンクします。

各エントリは ラベル と短い 説明 を表示します。どちらもあなたのスキーマ由来です。ラベルはテーブルまたはビューの表示名であり、説明はその COMMENT のプロース (説明文) です。Kozou は COMMENT をまずプロースとして扱い、@ 始まりのタグをオプトインの構造として扱うため、人間が読めるテキストがここに表れます。テーブルやビューに COMMENT がなければ、ラベルのみが表示されます。

ダッシュボードがテーブルなし、またはビューなしと報告する場合、イントロスペクトされたスキーマが空です。DATABASE_URLkozou.config.yaml 内の database.schemas リストを確認してください。

テーブルをクリックすると、そのリストビューが /tables/<table> で開きます。検索ボックス、ソート可能なカラムヘッダー、Prev / Next ページネーションを備えた行のテーブルがレンダリングされます。リスト状態のあらゆる要素は URL に存在するため、どのビューもブックマーク可能で共有可能です:

パラメータ意味デフォルト
?q=<text>解決されたテキスト系カラム全体にわたる大文字小文字を区別しない検索(なし)
?sort=col:asc,col2:desc1 つ以上のソートセグメント(なし)
?page=<n>1 始まりのページ番号1
?pageSize=<m>1 ページあたりの行数50

実践的な注意点:

  • 検索。 検索ボックスに入力すると、URL に ?q=… が追加され、行が絞り込まれます。検索は、Kozou がそのテーブルに対して解決するテキスト系カラムに対して ilike マッチを実行します。テキスト以外のカラム — たとえば uuid — は検索されないため、テキストマッチ演算子を持たないカラムで検索語がエラーになることは決してありません。
  • ソート。 カラムヘッダーをクリックするとそれでソートされ、同じヘッダーを再度クリックすると方向が ascdesc に切り替わります。?sort= パラメータがそれに合わせて更新されます。
  • ページネーション。 Prev / Next で結果をページ送りします。URL の ?pageSize= を調整してページサイズを変更します。

表示されるカラムはあなたのために選ばれています。Kozou はテーブルの 表示フィールド (各行に対して解決される、nametitle のような人間に分かりやすいカラム) を先頭にし、その横にいくつかの先頭カラムを表示します。どのカラムを表示フィールドにするかは ui-hints で変更できます。

各行は詳細ページへリンクし、リストビューには + New ボタンと行ごとの Edit・Delete コントロールが付いています。

テーブルのリストビューから、+ New (/tables/<table>/new) で作成フォームが開きます。行の詳細ページから、Edit (/tables/<table>/<id>/edit) で現在の値があらかじめ入力された同じフォームが開きます。どちらもカラムごとに 1 つの入力を生成し、各カラムの ウィジェット (後述) から入力コントロールを選びます。有効な作成フォームを送信すると新しい行の詳細ページに到達し、編集を送信すると変更が適用された詳細ページに戻ります。詳細ページの Delete は行を削除してリストに戻ります。

バリデーションは、フォームが送信される前にスキーマから導出されます。NOT NULL は必須フィールドになり、カラムのデータ型と抽出された列挙値があれば、入力できる内容を制約します。データベースが自前で投入できるカラムは尋ねられません。DEFAULT を持つカラム (たとえば gen_random_uuid() 主キーや、created_at DEFAULT now() のようなタイムスタンプ) はフォーム上で読み取り専用としてレンダリングされ、データベースが投入するために残されます。

各カラムは ウィジェット にマッピングされ、ウィジェットが入力コントロールを決定します。一般的なマッピング:

カラムの形ウィジェット入力コントロール
列挙 (CHECK ... IN (...) のセット、または PostgreSQL の enum 型)enum-select許可された値のドロップダウン
ブールbooleanチェックボックス
datedateネイティブの日付ピッカー
timestamp / timestamptz / timedatetime日付と時刻の入力
外部キーrelation-select検索可能なリレーションピッカー (後述)
数値 (int, numeric, float, …)number数値入力
json / jsonbjsonJSON テキスト入力
uuiduuidUUID テキスト入力
名前が URL / 画像のように見える textimage-urlURL テキスト入力
長文としてフラグ付けされた texttextarea複数行テキストエリア
それ以外のすべてtext単一行テキスト入力

このうちいくつかは実際に動作を見る価値があります:

  • 列挙 → ドロップダウン。 products テーブルの status text NOT NULL CHECK (status IN ('draft', 'published', 'archived')) カラムは、status を、選択肢がちょうど draftpublishedarchived であるドロップダウンとしてレンダリングします。PostgreSQL ネイティブの enum 型でも同じことが起こります。カラムがオプションの場合、ドロップダウンは空欄の -- の選択肢を追加し、未設定のままにできます。
  • ブール → チェックボックス。 published boolean カラムは 1 つのチェックボックスとしてレンダリングされます。
  • 日付 → 日付ピッカー。 published_at date カラムは、ブラウザのネイティブな日付ピッカーとしてレンダリングされます。

リレーションピッカー (外部キー)

Section titled “リレーションピッカー (外部キー)”

外部キーカラムは、生の id を入力するよう求める代わりに、検索可能なリレーションピッカー としてレンダリングされます。ピッカーは検索ボックスと候補行のドロップダウンを組み合わせます。入力するにつれて Kozou は参照先のテーブルにクエリを実行して選択肢を更新し、各選択肢は関連する行の表示フィールド — 主キーではなく — で表示されるため、あなたは人間が読めるラベルを選び、Kozou が内部の id を保存します。

たとえば、authors への author_id 外部キーを持つ books テーブルでは、author_id 入力で著者を名前で検索して 1 つ選択でき、フォームは一致した著者の id を送信します。詳細ページでは、同じ関係が著者のラベルに解決し直されるため、不透明な id の代わりに名前を読めます。(v0.1 はリレーションを 1 レベルの深さで編集します。関連行をインラインで作成するネストされたフローはありません。)

CREATE VIEW はダッシュボードの Views の下に表示され、/views/<view> で開きます。ビューのリストは、読み取りに関してはテーブルのリストと同じように振る舞います — 同じ検索・ソート・ページネーション — が、読み取り専用 です。+ New、Edit、Delete のコントロールはなく、行は編集可能な詳細ページにリンクしません。ビューは、書き込みアクセスを公開せずに閲覧用にキュレーションされた、結合された、あるいはフィルタされたデータの投影を公開するのにふさわしい場所です。

@widget と ui-hints が入力をどう形作るか

Section titled “@widget と ui-hints が入力をどう形作るか”

カラムのウィジェットは明確な優先順位で解決されるため、ゼロ設定から始めて、締めるべきところだけを締めることができます:

  1. ui-hintsui-hints.yaml 内のカラムに対する明示的な widget が勝ちます。
  2. カラムの COMMENT 内の @widget — 次の権威。
  3. ヒューリスティック — それ以外の場合、Kozou はカラムからウィジェットを推論します。外部キーは relation-select に、列挙は enum-select に、boolboolean に、datedate に、数値型は number に、といった具合です (上の表にデフォルトが一覧されています)。

ヒューリスティックがあなたの意図を見抜けないときに @widget を使ってください。最も一般的なケースは、固定の選択肢セットであるべきフリーテキストのカラム、あるいは PostgreSQL がテキストとして保存するがテキストエリアとしてレンダリングしたいカラムです:

COMMENT ON COLUMN products.status IS
'Lifecycle state of the product.
@widget: enum-select';
COMMENT ON COLUMN products.description IS
'Long-form product copy.
@widget: textarea';

@widgetカラムのみ で有効で、タグ行は Kozou が表示するプロースから取り除かれます — その上に書いた説明がフィールドのヘルプテキストとして表れます。タグの語彙全体 (@ai@widget@policy@example) は COMMENT 規約 に文書化されています。

オーバーライドがスキーマではなくプロジェクトに属する場合 — より良いテーブルラベル、別の表示フィールド、あるいは SQL にエンコードしたくない強制されたウィジェット — は、ui-hints.yaml に置いてください:

tables:
products:
label: Catalog
displayField: name
columns:
description:
widget: textarea
authors:
displayField: full_name

ui-hints は完全にオプションです。あなたの DDL と COMMENT だけで、使える UI をレンダリングするのに十分な情報を Kozou は得ています。キーの全セットと、オーバーライドレイヤーがスキーマとどう組み合わさるかについては ui-hints を参照してください。

  • kozou dev — Admin UI を提供するコマンド、そのフラグ、そして実験的な --adapter api オプション。
  • COMMENT 規約@widget タグと残りの COMMENT 語彙。
  • ui-hints — ラベル、表示フィールド、ウィジェットのプロジェクトレベルのオーバーライド。