From 5d3de00d1d07c716c73fadf7cbc49296b7d6899f Mon Sep 17 00:00:00 2001 From: rei <107461411+reiroop@users.noreply.github.com> Date: Tue, 4 Aug 2026 23:48:29 +0900 Subject: [PATCH] =?UTF-8?q?docs(project):=20=E3=82=A2=E3=83=BC=E3=82=AD?= =?UTF-8?q?=E3=83=86=E3=82=AF=E3=83=81=E3=83=A3=E3=81=AE=E9=AA=A8=E6=A0=BC?= =?UTF-8?q?=E3=81=AE=E6=96=B9=E9=87=9D=E3=82=92=E8=A6=81=E4=BB=B6=E3=81=8B?= =?UTF-8?q?=E3=82=89=E9=9A=94=E9=9B=A2=E3=81=99=E3=82=8B=E5=BD=A2=E3=81=A7?= =?UTF-8?q?=E6=98=8E=E6=96=87=E5=8C=96=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 要件の流動的な詳細に骨格を依存させず、サービスの定義から出る不変な性質に 依存して先に決め、変化点を seam の裏に隔離する方針を「アーキテクチャの骨格」 節として追加する。技術スタック節のバックエンド一体化の記述も、変化点として 保留する形に軟化する。#39 で整理した決定の記録。 Co-Authored-By: Claude Opus 4.8 --- openspec/project.md | 48 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/openspec/project.md b/openspec/project.md index 73fd5e7..e4ec63f 100644 --- a/openspec/project.md +++ b/openspec/project.md @@ -13,8 +13,9 @@ OpenSpec の提案(`/opsx:propose`)として始まり → 適用(`/opsx:apply`) - **言語**: TypeScript(strict)、Node.js 24、ESM。 - **モノレポ**: pnpm workspaces(Turborepo は使用しない)。パッケージは `workspace:*` で 互いを参照する。 -- **フロントエンド + サーバー**: Nuxt 4(`apps/web`)。バックエンドは独立したサービス**では - ない** — API は Nuxt の Nitro サーバー内でホストされる。 +- **フロントエンド + サーバー**: Nuxt 4(`apps/web`)。API は現状 Nuxt の Nitro サーバー内で + ホストされる。バックエンドを独立サービスとして切り出すかは確定せず、変化点として保留する + (「アーキテクチャの骨格」を参照)。実装は独立デプロイへ切り出せる seam を保つ。 - **API / RPC**: oRPC、コントラクトファースト。コントラクト(`@orpc/contract` の `oc`)は `packages/api-contract` にあり、`packages/api` が `implement(contract)` を通じてそれを 実装し、Nitro ルート `apps/web/server/routes/rpc/[...].ts` にマウントされる。 @@ -109,6 +110,49 @@ packages/db Drizzle スキーマ、MariaDB クライアント、マ - 暫定は黙って恒久化するので、暫定である印と見直す条件を必ず残す(issue 化、コメントに制約と拡張パスを 明記する)。 +## アーキテクチャの骨格 — 変化する要件から隔離する + +要件のうち流動的な詳細(どの機能から作るか・料金・UI・どの決済手段か)は上流ではなく、隔離すべき +変化点として扱う。骨格が依存してよいのは、サービスの定義(会員・会計の管理と、外部決済サービスの +利用)という最も安定した最上流の要件だけ。これに依存する不変な性質を先に決め、流動的な詳細は +seam の裏に置いて後から差し替えられるようにする。 + +seam は無料ではない。変化の軸を正しく捉えた seam だけが遅延を安くし、軸を取り違えた seam は現在の +コストと将来の書き直しの二重払いになる(例: 出力 allowlist は決済プロバイダの移植性を与えない — +移行には入力語彙・カーソル・ハンドラの書き換えも要る)。だから各不変項には、それが依存している +仮定と、その仮定が崩れる観測(見直す条件)を残す。 + +- 不変な性質にだけ依存する骨格(要件の詳細を待たず先に決める): + - データは RDB。会計は関係的で結合・集計が多く、これはドメインの構造から言える。 + - 会員集約を同定の単一ソースにする。内部 ID を正とし、決済プロバイダの顧客 ID は属性、traQ ID は + 任意として扱い、PII と会計記録を分離する。会員資格は期ごとの第一級レコードとして持つ(「(会員,期) + あたり課金 1 回」の一意強制は業務ルールなので暫定・見直し条件付き)。 + - 台帳は append-only の単一ソースとし、金額は整数の最小通貨単位で持つ。状態は拡張可能な符号付き + エントリの開いた集合として持ち、後から状態を加算できる(具体の状態集合はプロバイダとフローが + 固まってから)。 + - 決済プロバイダ非依存のドメイン層を設け、入金は外部イベントを webhook で受ける。取り込みは外部 + イベント ID で重複排除する inbox 境界を持ち(冪等)、内部台帳エントリと外部イベントが双方向に + 辿れて乖離を検出できる(突合可能性)。 + - 監査ログを append-only で持ち、機微な金銭の変更・閲覧は認可の裏に置き既定 deny(fail-closed)。 + 具体のロール・ポリシーは暫定。 +- 隔離して遅延する変化点(要件・運用先が決める。seam は今引き、確定は後): + - どの決済プロバイダを使うか。非依存層の実装として後で差す。状態はドメイン語彙で定義し、 + プロバイダ→ドメインの写像を seam にする(第 2 のプロバイダの生涯周期を一度写像するまで「非依存」 + は未検証)。 + - どの DB エンジンを使うか。RDB は確定。実データが無い間は移行コストが低いが、スキーマ定義の + 書き直しは要る。骨格をエンジン固有機能に依存させない。ドメインモデル(#27)の本実装前に確定する。 + - デプロイ・運用先。正しさは共有状態を DB に寄せて吸収するが、常駐サーバーか否かという実行形態は + 非同期実行基盤(#30)の成立を左右する。 + - バックエンドの構成(独立デプロイするか)。言語(TypeScript)はほぼ確定で残す価値が高く、開けて + おくのはプロセス構成の seam。RPC 契約から OpenAPI を出力できるため他言語へ移す余地も残る(その + 出力を維持される成果物として扱うことが条件)。 + - 機能スライスの順序。ただしこれは会員のカーディナリティや状態集合など骨格の暫定部分を確定する + 情報源でもある。 + +各項目の詳細設計は #27–#37 で詰める。ここに置くのは「不変な性質に依存し変化点を隔離する」方針と、 +確定した方向性まで(プロバイダを裏に隠す・出力 allowlist などの既述の横断方針は繰り返さない)。 +これは「意思決定の指針」を骨格設計に当てはめたもの。 + ## ローカル開発 ```bash