建築
SubLane ガイド: アーキテクチャ。
現在の実装
SubLane は、chi ルーティングとクライアントレンダリングの React フロントエンドを備えた 1 つの Go プロセスです。実稼働ビルドでは、Vite が生成したファイルが実行可能ファイルに埋め込まれます。 SQLite は唯一の永続的なサービス依存関係です。ドライバーは純粋な Go であるため、実稼働ビルドには CGO は必要ありません。アプリケーションクエリは SQL で生成された Go over を使用します database/sql; sqlc は開発ツールであり、ランタイム サービスではありません。
flowchart LR
Browser[Browser] --> HTTP[chi HTTP server]
Clients[Responses and Chat clients] --> HTTP
HTTP --> SPA[Embedded React application]
HTTP --> Tenant[Workspace routing and membership]
Tenant --> Accounts[Workspace accounts and encrypted credentials]
Accounts --> DB[(SQLite)]
HTTP --> Gateway[Key-bound workspace routing and affinity]
Gateway --> Accounts
Gateway --> Adapter[Provider adapters and SDK executors]
Adapter --> Providers[Codex, Claude, Antigravity and Grok Build]開発中、Vite は React アプリとプロキシを提供します /api, /v1 WebSocket アップグレードを含む、 /healthz、 そして /readyz Go バックエンドに。運用環境では、ブラウザと API は同じオリジンと 1 つのポートを使用します。個別の Node.js サービス、Redis、または PostgreSQL の要件はありません。
所有
| モジュール | 所有しています | 所有していない |
|---|---|---|
cmd/sublane | プロセス信号、起動、配線、停止 | ドメインポリシー |
internal/config | 検証済みのプロセス環境 | 永続的なチーム設定 |
internal/backup | ストリーミングされたアーカイブ、整合性とキーの検証、分離されたリストア、およびアトミックな非置換パブリケーション | HTTP 認証、プロバイダーの実行、またはライブ データの置換 |
internal/alerts | ワークスペースの Webhook 設定、ローカル インシデントの監視、暗号化された宛先、配信の再試行とリカバリ | モデルの実行またはブラウザの承認 |
internal/content | 暗号化されたワークスペース コンテンツ ルール、コンパイルされたローカル マッチャー、制限されたデコードされたテキスト チェック、および安全な一致メタデータ | プロバイダーの実行、リクエスト アカウンティングまたはブラウザーの承認 |
internal/versions | 永続的な Codex、Grok、および Claude バージョン ポリシー、公式リリースのメタデータ チェック、および同期ライフサイクル | SDK の実行、アカウント認証情報、またはバイナリのインストール |
internal/timezone | 永続インスタンスのタイムゾーンとその公開場所 | ブラウザのフォーマット、使用状況のアカウンティング、またはホストのクロック設定 |
internal/auth | グローバル ログイン ID、パスワード、およびセッション | ワークスペースのメンバーシップまたはアップストリームの資格情報 |
internal/tenants | ワークスペースのメンバーシップ、役割、ライフサイクル | グローバルパスワードまたはプロバイダーの実行 |
internal/groups | リソースグループ、メンバー付与、個人プールの選択、および範囲限定の準備 | 認証情報またはモデルプロトコル |
internal/audit | 境界のある管理メタデータ、アクター コンテキスト、トランザクション イベントの書き込み、管理者の読み取り | リクエストの本文、資格情報、または認証 |
internal/apikey | パーソナルゲートウェイキーのメタデータ、ハッシュ、不変プールバインディング、失効、および検索 | ブラウザセッションまたはアップストリーム認証情報 |
internal/accounts | サブスクリプションのメタデータ、永続化されたモデルのスナップショットとライフサイクルのリビジョン、暗号化されたワークスペース プロキシとアカウント バインディング、資格情報のライフサイクル、および更新のシリアル化 | HTTP ディスパッチまたはクライアントキー |
internal/resets | 任意のカード使用規則、正規化した利用条件と期限順序、カードとリクエストの永続的な予約、日次上限と制限付きスケジュール | プロバイダー認証情報、外部通信、上流での適格性判断、推論 |
internal/vault | AES-GCM 暗号化と秘密ローカルキーのロード | OAuth またはアカウント ポリシー |
internal/oauth | セッション限定、単回使用 OAuth 試行 | ブラウザログインまたはモデル転送 |
internal/upstream | パブリック SDK エグゼキューター、変換、トークン交換、プロバイダー プロトコル、および選択されたアウトバウンド トランスポート | チームの役割またはデータベースの所有権 |
internal/gateway | 制限されたゲートウェイ/アカウント/メンバーの入場、永続的なクールダウン/レートウィンドウ、リクエスト履歴と毎日の集計、アカウントアフィニティ、クォータスナップショット、およびリクエストごとのオーケストレーション | 公的管理認可 |
internal/storage | SQLite ライフサイクル、スキーマ初期化、およびクエリ SQL | プロバイダー認証 |
internal/storage/db | 生成されたクエリメソッドとデータベース行タイプ | ドメイン ポリシーまたはパブリック JSON 契約 |
internal/server | カイ ルート、応答境界、SPA サービス | 今後のルーティング/アカウントポリシー |
web/src/lib/request.ts | 応答の検証とキャンセル | コンポーネントのプレゼンテーション |
web/src/locales | ローカライズされた UI 文字列 | サーバー診断 |
持続性
データベースは、有効な外部キー、制限されたビジー タイムアウト、および 1 つのオープン接続を使用して WAL モードで実行されます。新規インストールでは、組み込みの 001_schema.sql 初期化ファイルと、ワークスペース プロキシ テーブルや null 許容アカウント バインディングを含む、順序付けられた追加の移行。グローバル ログイン ID とワークスペース スコープのアカウント、プール、プロキシ、キー、許可、リクエスト履歴、使用状況、監査記録が保存されます。最初の管理者はワークスペース 1 を所有します。サポートされていない古いプレリリース データベースは拒否されます。新しいディレクトリを初期化する前に、データ ディレクトリを保存してください。プール カタログは、アカウント スナップショットと現在のポリシーから派生したままになります。見る モデルカタログ。見る ワークスペース, ネットワークプロキシ, 経営監査, リソースグループ、 そして プールのランタイム.
新しいデータベース ファイル使用モード 0600;新しく作成されたデータ ディレクトリは使用します 0700。既存のディレクトリ権限は上書きされません。データベース構成では適切にエスケープされたファイル URL が使用されるため、パス内の特殊文字がサポートされます。
トランザクションは短くする必要があります。上流のネットワーク応答を待っている間は保持しないでください。同時ライターや長時間実行ワーカーを導入する前に、接続数をやみくもに増やすのではなく、競合を測定してください。
名前付きクエリは以下に存在します internal/storage/queries/. sqlc.yaml アプリケーションが埋め込むのと同じ初期化スキーマを読み取り、個別に保持されるスキーマのコピーを回避します。ドメイン サービスはトランザクションの所有権を保持し、 WithTx 生成されたメソッドをアクティブなトランザクションにバインドします。パブリック応答はドメイン タイプのままであるため、生成された行によってパスワードやトークン ハッシュが誤って公開されることはありません。スキーマ ブートストラップは明示的な SQL をストレージ内に残します。生成された Go はバージョン管理され、次のようにチェックされます。 make generate-check.
HTTP と資産
- ち
Routeグループとメソッド固有の登録は HTTP ディスパッチを所有します。ハンドラはリクエスト メソッドやゲートウェイ パスをオンにしません。ルータースコープUse404/405 処理の前に、セッション、ロール、ベアラー チェックを適用します。パブリック認証の用途GroupそしてWith可用性、オリジン、およびログインのスロットルについて。ドメイン サービスは HTTP から独立したままになります。 - 管理ルートおよび不明な管理パスは管理者認証を保持します。パブリック認証と個人キーのエンドポイントは明示的な例外です。不明なパスは管理者の保護にフォールバックされます。 JSON 405 応答は、chi のルート テーブルから許可ヘッダーを取得します。静的アセットは、API ルーターの外部の GET/HEAD に対してのみ登録されます。
- 生存性は SQLite には依存しません。準備はできています。
- 下の管理ルート
/api/デフォルトで有効な管理者セッションが必要です。 4 つの明示的な認証エンドポイントのみがパブリックです。状態を変更するブラウザー要求により、正確な送信元チェックが強制されます。個人的/api/keysそして明示的な/api/me履歴、パスワード、制限、および使用ルートは、有効なロールのいずれかを受け入れ、セッションから所有権を取得します。履歴は、ページネーションの前に SQL で所有権をフィルターし、個人の応答からサブスクリプション ID を隠します。/v1モデル検出、Responses HTTP/SSE/WebSocket、圧縮、Chat Completions、およびネイティブ Claude メッセージに別個のゲートウェイ キー認証を使用します。/v1beta同じ認可サービスとライフサイクル サービスを使用してネイティブ Gemini 世代を公開します。見る ネイティブプロトコル。 WebSocket は、キーの有効性とメンバーの有効性を再チェックします。 - システムとヘルス JSON の応答では、
Cache-Control: no-store. - SPA 文書は再検証されます。ハッシュ化された
/assets/ファイルは不変にキャッシュされる可能性があります。 - 不明な API ルートは JSON エラー (保護されたサブツリーでの認証前は 401、それ以外の場合は 404) を返し、欠落している静的ファイルは 404 を返します。これらは成功した HTML 応答にはなりません。
- ヘッダーは、MIME スニッフィングとフレーミングを防止し、リファラーの開示を同じオリジンに制限します。
- ストリーム全体への一括書き込みタイムアウトはありません。ゲートウェイは設定された
SUBLANE_GATEWAY_REQUEST_TIMEOUT(既定 30 分)、本文・イベント・履歴の上限、キャンセル伝播を使用します。 - SIGINT/SIGTERM は新しい作業の受け入れを停止し、HTTP のシャットダウンに最大 10 秒かかります。
フロントエンド
TanStack Router はナビゲーションを所有し、オンデマンドでページ コンポーネントを読み込みます。 TanStack Query はリモート要求状態を所有します。 Zod はシステム応答を検証します。失敗は、捏造された正常なデータではなく、再試行アクションを伴うエラーとして表示されます。
Shadcn Admin サブセットは、サイドバーと共有プリミティブを提供します。アプリケーション ページは SubLane 固有であり、デモ ビジネス レコードは含まれません。テーマの設定は次によって管理されます。 next-themes;翻訳で使用 i18next そして react-i18next。中国語ブラウザでもデフォルトは英語です。サポートされているすべての辞書には、コンパイル時に英語のキーが含まれている必要があります。最初は英語と簡体字中国語がバンドルされています。追加の言語辞書はオンデマンドでロードされます。アラビア語では右から左の方向が使用されますが、コードと識別子は左から右のままです。
ルート認証ゲートは、保護されたページをマウントする前にサーバーの状態を待ちます。管理クエリは、リダイレクト移行中も含め、管理者に対してのみ有効になります。 1 つのフロントエンド アクセス ポリシーは、ナビゲーションとダイレクト ルート ガードを制御します。メンバーは、システムやメンバー管理データを照会することなく、個人のホームページと共有の外観/言語設定を利用できます。個人キー、リクエスト履歴、および使用状況のクエリには、キャッシュ キーに所有者 ID が含まれており、その ID が最新である間のみメンバー アクセスをオプトインします。ログアウトすると、未処理のリクエストがキャンセルされ、認証状態が更新され、プライベート クエリ データが削除されます。セッションでは、ブラウザ ストレージ トークンではなく HttpOnly Cookie が使用されます。完全なサーバー契約については、次の文書に記載されています。 認証.md.
プロバイダーの実行境界
独立したインスタンス全体の Codex、Grok、および Claude バージョン ポリシーは、管理者専用のポリシーを通じて管理されます。 システム設定 個人の好みとは別にサイドバーページ。 internal/versions 既存のプロバイダー JSON 値を個別に保持します。 settings テーブルを作成し、ロックフリーのバージョン リゾルバーを上流アダプターに提供します。制限付きバックグラウンド チェックは、デフォルトで 6 時間ごとに公式の安定版リリースに従います (Codex GitHub リリースおよび Grok npm) latest dist-tag と Claude コード npm stable 距離タグ);手動オーバーライドが優先されます。 Claude 推論は、クライアント バージョンごとに不変の SDK エグゼキュータ設定をキャプチャするため、そのユーザー エージェント、課金メタデータ、および最終的な CCH 署名が一致します。一時バージョンのブートストラップ リスナーは閉じられており、資格情報はストアに入りません。ゲートウェイの操作はバージョン サービスとリリース トランスポートが閉じる前に停止し、ワーカーは SQLite が閉じる前に参加します。見る システム設定.
internal/upstream CLIProxyAPI v8.0.35 をパブリック SDK を通じて初期化し、組み込みエグゼキュータを取得します。ランタイム アカウント ポリシーでは、Codex、Claude、Antigravity、および Grok Build サブスクリプションと、管理者が構成した OpenAI 互換の API アカウントが許可されます。上流はありません internal パッケージがインポートされます。 SDK マネージャーには空の書き込み拒否ストアがあり、ライブ アカウント登録を受け取りません。 no-op ウォッチャーは、ファイルベースの認証情報の同期を回避します。 SDK ライフサイクルは、ループバック専用の一時的な HTTP リスナーを開始します。すべてのルートがブロックされ、個別のランダムな API キーがあり、管理/パネル アクセスが無効になります。クライアントは SubLane の chi サーバーのみを使用します。ホーム モードと Redis は有効になっていません。
SubLane は永続的なライフサイクル所有者を保持します。 OAuth 交換とリフレッシュは、制限されたピン留めされたプロバイダー エンドポイントを使用します。ローテーションされた資格情報は、モデルの実行前に暗号化されて保存されます。 SDK 自動リフレッシュが停止されました。一時的なサブスクリプション認証には、アクセス トークンと許可されたプロバイダーのメタデータ、更新しないトークン、インポートされたエンドポイントのオーバーライド、またはクライアント提供のプロキシ設定が含まれます。 API チャネルはプラットフォームとプロトコル設定を暗号化キーと検証済みベース URL とともに保持します。実行には選択された公開 SDK 実行器を使い、Responses には公開の認証付き HTTP と変換器を使います。モデル探索は制限付きで設定に従い、共通の /models 形式を前提にしません。キーは OAuth 更新や SDK ストアに入りません。グループ権限、アフィニティ、集計を共有し、キー交換では ID と設定を維持します。プラットフォーム、プロトコル、接続先の変更には別チャネルが必要です。 Antigravity はパブリックを使用します sdk/auth authorization-code ヘルパーと永続所有者内の明示的な executor リフレッシュ呼び出し。そのリフレッシュ呼び出しのみがリフレッシュ トークンを受け取ります。その結果は SDK マネージャーには決して登録されません。挿入されたトランスポートは、SDK がそのリフレッシュ コンテキストを切り離した場合でも、呼び出し元の期限、応答限界、リダイレクト拒否、およびサニタイズされたエラーを強制します。プロジェクトの準備もこのパス内で完了します。この境界により、SDK マネージャーの永続化前の公開動作が回避されます。これを保護されていない Manager.Register/Update 呼び出しに置き換えないでください。
ワークスペース管理者は、アカウントを暗号化されたアカウントにバインドできます。 ネットワークプロキシ。アップストリーム アダプターは、サーバー側 OAuth の交換、更新、検出、使用状況の読み取り、およびモデルの実行のためにアカウントのプロキシを選択します。 SDK 呼び出しは、分離されたリクエスト コンテキストを構築する場合でも、その選択を保持します。飛行中のストリームは元の接続を維持します。プロキシを変更しても、プロキシが再試行されたり、アカウント アフィニティが変更されたりすることはありません。ブラウザ認証ページは、このサーバー側ルートの外側に残ります。
パブリック モデル カタログは、チャネル プレフィックスを追加せず、プロバイダー間で重複を排除したネイティブ ID を使用します。対象となるプロバイダー全体でサポートするアカウントを選択するようリクエストします。従来の明示的に修飾されたリクエストには互換性が残ります。モデル検出はアカウントごとのスナップショットを保持し、現在のプール ポリシー内でそれらを集約します。推論では、要求されたモデルをサポートする使用可能なスナップショットを持つアカウントのみが選択されます。共有検出では、既存のアップストリーム スロットを最大 2 つ使用します。更新が実行されている間、古くなった正常なデータは最大 24 時間使用可能なままになります。クォータ リーダーは、Codex 使用量、Claude ウィンドウ、および Antigravity モデルの許容量を共有永続キャッシュに正規化します。圧縮は Codex のみのままです。新しいメイン クォータ ウィンドウ ゲート Codex および Claude アカウント。 Antigravity クォータ アドミッションは、要求されたネイティブ モデルのみに一致します。選択はポリシー トランザクション内で永続化されたメタデータを読み取りますが、制限された共有更新はポリシー トランザクションの外で実行されます。見る プロバイダーのセットアップ そして ゲートウェイの詳細.
The vault key is generated as a 0600 file beside SQLite.スタートアップは、既存の暗号化されたアップストリーム資格情報、プロキシ アドレス、および個人の API キー レコードを検証し、キーが見つからないか不一致の場合は失敗して終了します。これらは、個別の認証された暗号化バインディングを使用します。バックアップでは、キーをデータベースと一緒に保存する必要があります。更新および管理者の資格情報の変更には、シリアル化された所有者が 1 人います。ネットワーク IO はデータベース トランザクション内で実行されることはありません。
アフィニティの範囲は、メンバー、プール、およびクライアント セッションに限定されます。 auto scope for native requests and provider-specific scopes for legacy qualified requests.正規化されたモデルを記録し、通常のプロセスの再起動後も保持され、非アクティブな状態が 24 時間続くと期限切れになります。元のアカウントがバインディングをサポートしていない場合、完全なポータブル履歴を持つ別のモデルがバインディングを置き換える可能性があります。プロバイダーの継続と変更されていないモデルは固定されたままになります。無効化または削除されたアカウント、およびプールから削除されたアカウントは、安全でないアカウントの切り替えを引き起こす代わりに、既存の会話に失敗します。 WebSocket トランスクリプトの状態は接続ローカルで制限されたままです。 HTTP 上流の HTTP バックエンドがステートレスであるため、previous_response_id は拒否されます。呼び出し側は完全な入力を提供する必要があります。
Automated protocol tests use synthetic credentials and fake upstreams.オプトイン テストにより、Codex CLI 0.152.1 から HTTP/SSE および WebSocket モードが検証されました。実際のサブスクリプションとデスクトップ認証は依然として別個の承認手順です。ユニバーサル メモリやスループット バジェットは要求されません。意図したワークロードと導入プラットフォームを測定します。
Grok Build authorization uses bounded, session-bound device-code attempts with server-enforced polling intervals and single-use completion.秘密のデバイスのコードはサーバー上に残ります。キャンセルと期限切れにより、資格情報の公開が遅れることを防ぎます。 xAI SDK エグゼキュータは、サブスクリプション チャット プロキシを選択するための明示的な OAuth マーカーを受け取りますが、更新では、既存の永続アカウント所有者の下に固定された xAI トークン エンドポイントが使用されます。 Grok クォータは、同じアカウント プロキシと共有の永続的な使用量キャッシュを介して、公式 CLI 請求メタデータを読み取ります。含まれているサブスクリプション クレジットのみが正規化されます。
インスタンスのバックアップ
ストレージ層は、制限付きキャッシュ メモリと増分ページ コピーを備えた別の読み取り専用接続を介して、SQLite オンライン バックアップ API を使用します。アーカイブ層は、ストリーミング IO を使用してデータベース、暗号化キー、マニフェストをパッケージ化します。復元では、プライベート ステージング コピーのみを検証して移行し、ブラウザー セッションをクリアして、既存のパスを上書きせずに新しいディレクトリを公開します。管理者はシステム設定から復元をエクスポート、検証、準備できます。オペレータが再起動すると、復元されたディレクトリがアクティブになります。エクスポート/復元の準備は監査され、ファイル操作はライブ アプリケーション データベースにトランザクションを保持しません。見る バックアップと復元.
モデル制限メタデータは次のように正規化されます。 internal/upstream;生のエラー本体は保持されず、返されません。ゲートウェイは、アカウント/モデルのクールダウン、条件付きバージョン付き書き込み、制限されたアクティブ状態メモリ、および通常のリクエストの回復を所有します。 Antigravity SDK - ローカル冷却はこの所有者に委任され、モデルのスコープを失ったり、承認ライフサイクルを超えて存続する可能性がある非表示のタイマーを回避します。
API チャネル管理
internal/channels 共有暗号化実行リソース所有者に対して個別の API チャネル管理コントラクトを公開します。サブスクリプション リストには API チャンネルが含まれません。 /api/channels 管理者専用のチャネル ライフサイクルとモデル管理を提供します。ストレージ リソース ID は安定したままであるため、既存のメンバーシップ、アフィニティ、およびキー バインディングは存続します。
internal/groups owns typed subscription/channel resource membership and persisted routing preferences.新しい UI グループは、API フォールバックがオフのサブスクリプションを優先します。移行では、既存のプロトコル設定が保持されます。アドミッション、モデル カタログ、可用性、準備状況、およびアラート キャパシティは、同じルーティング ポリシーを共有します。既存の会話はリソース間で自動的に移動されません。ポータブルな履歴を伴う明示的なモデル変更は、ゲートウェイ モデル ルーティング ルールに従います。