Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 46 additions & 2 deletions openspec/project.md
Original file line number Diff line number Diff line change
Expand Up @@ -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` にマウントされる。
Expand Down Expand Up @@ -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 などの既述の横断方針は繰り返さない)。
これは「意思決定の指針」を骨格設計に当てはめたもの。

Comment on lines +113 to +155

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Issue `#27`, `#28`, `#30`, `#32` に前提訂正の注記が追加されているか確認する。
gh issue view 27 --comments 2>/dev/null | tail -n 30
gh issue view 28 --comments 2>/dev/null | tail -n 30
gh issue view 30 --comments 2>/dev/null | tail -n 30
gh issue view 32 --comments 2>/dev/null | tail -n 30

Repository: traPtitech/Checkin

Length of output: 156


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 対象リポジトリを特定し、関連ファイル/Diff/Issue refs を調べる。
pwd
git remote -v || true
git status --short
git diff --stat HEAD~1..HEAD 2>/dev/null || git diff --stat origin/main..HEAD 2>/dev/null || true
rg -n "#(27|28|30|32)|前提訂正|訂正|受け入れ条件|accept|requirement|requirement" . --glob '!node_modules' 2>/dev/null | head -n 200

Repository: traPtitech/Checkin

Length of output: 729


🌐 Web query:

GitHub REST API issue comments list issue_url comments_url

💡 Result:

In the GitHub REST API, there is a clear distinction between the base URL for listing issue comments and the comments_url field returned within an issue resource [1][2][3]. 1. REST API Endpoints for Listing Issue Comments: To programmatically retrieve comments for an issue, you use specific endpoints based on the scope: - For a specific issue: Use GET /repos/{owner}/{repo}/issues/{issue_number}/comments [1][4]. - For an entire repository: Use GET /repos/{owner}/{repo}/issues/comments [1][4]. 2. The comments_url Field: When you retrieve an issue resource (e.g., via GET /repos/{owner}/{repo}/issues/{issue_number}), the response object includes a comments_url field [3]. This field is a pre-constructed, absolute URL provided by GitHub that points directly to the API endpoint for listing comments specifically for that issue [3]. This allows you to navigate to the comments endpoint without needing to manually construct the URL string from the owner, repository name, and issue number [3]. Note that in the GitHub REST API, pull requests are treated as issues [1][5]. Therefore, the same issue comment endpoints are used to manage comments on pull requests [5]. Top results: [1][2][3][5]

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import os, subprocess, json
owner = "traPtitech"
repo = "Checkin"
for n in [27,28,30,32]:
    raw = subprocess.check_output(["gh","api",f"repos/{owner}/{repo}/issues/{n}"], text=True, stderr=subprocess.DEVNULL)
    data = json.loads(raw)
    print(f"#{n} state={data.get('state')} title={data.get('title')} body_len={len(data.get('body',''))}")
PY

echo "--- comments ---"
python3 - <<'PY'
import subprocess, json
owner = "traPtitech"
repo = "Checkin"
for n in [27,28,30,32]:
    raw = subprocess.check_output(["gh","api",f"repos/{owner}/{repo}/issues/{n}/comments"], text=True, stderr=subprocess.DEVNULL)
    comments = json.loads(raw)
    print(f"#{n} comment_count={len(comments)}")
    for c in comments:
        print("  ----")
        print(c.get('body','')[:400].replace('\n','\\n'))
        print("  author=", c.get('user',{}).get('login'))
PY

echo "--- accepts/requirement text in open specs ---"
rg -n "受け入れ条件|requirement|requirement|accept|acceptance|前提訂正|訂正|fix|前提" . --glob '!node_modules' 2>/dev/null

Repository: traPtitech/Checkin

Length of output: 1769


Issue 側の前提訂正注記を追加してください。

openspec/project.md には #27#28#30#32 への言及はありますが、各 Issue に前提訂正が必要なことを伝える注記がありません。対象 Issue に前提訂正の注記を追加してください。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@openspec/project.md` around lines 113 - 155, openspec/project.md の Issue
`#27`–#28、#30、#32 への言及に、それぞれ前提訂正が必要であることを示す注記を追加してください。既存の設計方針や他の Issue
への記述は変更せず、対象 Issue を確認・修正すべき旨だけを明記してください。

## ローカル開発

```bash
Expand Down