chore: initialize repository with project docs and tooling
- Add persistent docs: PRD, functional design, architecture, repository structure, development guidelines, milestones - Add brainstorming notes (docs/ideas/) - Configure tooling: package.json, tsconfig, eslint, prettier, vitest - Add opencode configuration (commands, skills, agents) - Add .gitignore for node_modules, .env, data/, backups/, build outputs
This commit is contained in:
271
docs/architecture.md
Normal file
271
docs/architecture.md
Normal file
@ -0,0 +1,271 @@
|
||||
# アーキテクチャ設計書 (Architecture Design Document)
|
||||
|
||||
> 本書は `docs/product-requirements.md` と `docs/functional-design.md` を技術的に実現するためのシステム構造・技術選定・インフラ要件を定義する。
|
||||
|
||||
## 技術スタック
|
||||
|
||||
### 言語・ランタイム
|
||||
|
||||
| 技術 | バージョン | 選定理由 |
|
||||
|------|-----------|----------|
|
||||
| Node.js | v24.11.0 | 開発環境(devcontainer)と同一。better-sqlite3の同期APIを直接扱える。LTS保証下で本番運用が安定 |
|
||||
| TypeScript | 5.x | 静的型付けによりコンパイル時バグ検出。Repository/Service/Entity間の型共有で保守性向上。IDE補完により開発効率向上 |
|
||||
| npm | 11.x | Node.js v24.11.0にバンドル。package-lock.jsonによる厳密な依存管理。workspaces対応 |
|
||||
|
||||
### フレームワーク・ライブラリ
|
||||
|
||||
| 技術 | バージョン | 目的 | 選定理由 |
|
||||
|------|-----------|------|----------|
|
||||
| Next.js | 15 | Webフレームワーク | App Router・Server Components・Route Handlers・Server Actionsを統合利用。Node.js Runtime選択可能でSQLite直接操作に適合 |
|
||||
| better-sqlite3 | 最新安定 | SQLiteドライバ | 同期APIで扱いやすく高速。トランザクション・プリペアドステートメント・pragma制御が直接可能 |
|
||||
| react-markdown | 最新安定 | Markdownレンダリング | GFM拡張と連携可能。プラグインでサニタイズパイプラインを構築できる |
|
||||
| remark-gfm | 最新安定 | GFM対応 | テーブル・チェックリスト・取り消し線等のGFM記法を有効化 |
|
||||
| rehype-sanitize | 最新安定 | HTMLサニタイズ | Markdown表示時のXSS対策。危険なHTML・URLスキームを除去 |
|
||||
| Tailwind CSS | 最新安定 | スタイリング | ユーティリティファーストでUI構築が高速。カスタムCSS削減 |
|
||||
| bcrypt | 最新安定 | パスワードハッシュ | ソルト付きハッシュで平文保存を回避。適切なコスト係数でブルートフォース耐性 |
|
||||
| FullCalendar系 または独自実装 | - | カレンダーUI | 月/週/日/リスト表示・ドラッグ操作・イベントフィルタ要件を満たす |
|
||||
|
||||
### 開発ツール
|
||||
|
||||
| 技術 | バージョン | 目的 | 選定理由 |
|
||||
|------|-----------|------|----------|
|
||||
| Vitest | 最新安定 | Unit Test | Viteベースで高速。TypeScriptネイティブ対応。better-sqlite3等のネイティブモジュールも扱える |
|
||||
| Playwright | 最新安定 | E2E Test | 実ブラウザ(Chromium/Firefox/WebKit)操作で主要ユーザーフローを検証。SSEのリアルタイム挙動も検証可能 |
|
||||
| ESLint | 最新安定 | リンタ | コード品質・一貫性維持。TypeScriptルールと連携 |
|
||||
| TypeScript(tsc) | 5.x | 型チェック | 型エラーをCIで検出 |
|
||||
|
||||
## アーキテクチャパターン
|
||||
|
||||
### レイヤードアーキテクチャ
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ UI層 (Next.js) │ ← Server Components / Client Components
|
||||
│ Route Handler / Server Action / SSE │ 入力受付・表示・認証・認可
|
||||
├─────────────────────────────────────────────┤
|
||||
│ Service層 │ ← 業務ロジック・権限チェック・トランザクション
|
||||
│ AuthService / ProjectService / ... │ 通知生成・アクティビティログ・SSE配信
|
||||
├─────────────────────────────────────────────┤
|
||||
│ Repository層 │ ← SQL保持・データアクセス・論理削除フィルタ
|
||||
│ UserRepository / ProjectRepository / ... │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ Data層 │ ← SQLite接続・SQL実行・Migration
|
||||
│ lib/db/sqlite.ts / migrator.ts / SQLite │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### レイヤ責務と依存規則
|
||||
|
||||
依存は一方向(UI → Service → Repository → Data)のみ許可する。逆方向依存・層飛ばしを禁止する。
|
||||
|
||||
#### UI層(Route Handler / Server Action / Server Components / SSEエンドポイント)
|
||||
- **責務**: 入力受付・バリデーション・認証・認可・結果表示
|
||||
- **許可操作**: Service層の呼び出し
|
||||
- **禁止操作**: Repository層・Data層への直接アクセス、SQLの直接記述
|
||||
|
||||
#### Service層
|
||||
- **責務**: 業務ロジック・権限チェック(`isMember`/ロール)・トランザクション境界・副作用(通知生成・アクティビティログ記録・SSE配信)
|
||||
- **許可操作**: Repository層の呼び出し・FileStorageServiceによるファイル操作・SseHubへの配信依頼
|
||||
- **禁止操作**: UI層への依存、SQLの直接記述、SQLiteライブラリの直接操作
|
||||
|
||||
#### Repository層
|
||||
- **責務**: SQLの保持・パラメータバインド実行・論理削除(`deleted_at IS NULL`)の確実な付与・プロジェクト分離の担保
|
||||
- **許可操作**: SQLラッパー(`lib/db/sqlite.ts`)経由のDBアクセス
|
||||
- **禁止操作**: 業務ロジックの実装、SQLiteライブラリの直接操作、UI層への依存
|
||||
|
||||
#### Data層
|
||||
- **責務**: SQLite接続の共通管理・SQL実行・トランザクション・Migration
|
||||
- **許可操作**: better-sqlite3へのアクセス・ファイルシステム(Migrationファイル・バックアップ)へのアクセス
|
||||
- **禁止操作**: 業務ロジックの実装
|
||||
|
||||
```typescript
|
||||
// 許容: UI → Service → Repository → Data
|
||||
routeHandler → projectService.createProject(...) → projectRepository.create(...) → db.execute(sql, params)
|
||||
|
||||
// 禁止: UI → Data (層飛ばし)
|
||||
routeHandler → db.execute("INSERT INTO projects ...") // ❌
|
||||
|
||||
// 禁止: Repository → SQLite直接 (ラッパー未使用)
|
||||
projectRepository → new Database(dbPath) // ❌
|
||||
```
|
||||
|
||||
### ランタイム方針
|
||||
|
||||
SQLiteを直接扱うため、Next.jsのEdge Runtimeは使用しない。API Route・Server Actions・DBアクセス処理・SSEエンドポイントはすべてNode.js Runtimeで実行する。各Route Handlerの先頭で `export const runtime = 'nodejs'` を明示する。
|
||||
|
||||
### Prisma不使用の方針
|
||||
|
||||
DBアクセスは独自SQLラッパー(`lib/db/sqlite.ts`)とRepositoryクラスで実装する。Prismaは導入しない。
|
||||
- 理由1: SQLを直接制御することでクエリ最適化・インデックス設計を明示できる
|
||||
- 理由2: better-sqlite3の同期APIと相性が良く、コード生成のオーバーヘッドがない
|
||||
- 理由3: MigrationもSQLファイルベースの独自実装でバージョン管理する
|
||||
|
||||
## データ永続化戦略
|
||||
|
||||
### 保存方式
|
||||
|
||||
| データ種別 | 保存先 | 形式 | 理由 |
|
||||
|-----------|----------|-------------|------|
|
||||
| アプリケーションデータ | SQLite(`./data/app.db`) | リレーショナル | トランザクション・外部キー・インデックス・論理削除を一貫管理 |
|
||||
| アップロードファイル | ローカルFS(`./data/uploads/<projectId>/`) | バイナリ | 外部ストレージ不要・自己完結。DBにメタデータ(`file_assets`)を保存 |
|
||||
| Migration履歴 | SQLite(`schema_migrations`) | 行レコード | 適用済みファイルを一意管理・再実行回避 |
|
||||
| バックアップ | ローカルFS(`./backups/`) | ZIP | DBファイル+uploadsディレクトリをZIP化 |
|
||||
|
||||
### SQLite接続設定
|
||||
|
||||
- `journal_mode = WAL`: 読み書きの並行性向上
|
||||
- `foreign_keys = ON`: 外部キー制約・カスケード削除を有効化
|
||||
- 接続はシングルトン(`getDb()`)で共有。dbPathは `process.env.SQLITE_PATH ?? "./data/app.db"`
|
||||
|
||||
### バックアップ戦略
|
||||
|
||||
- **作成タイミング**: 管理者がバックアップ画面から手動実行
|
||||
- **作成内容**: SQLite DBファイル + uploadsディレクトリをZIP化
|
||||
- **保存先**: `./backups/backup-<timestamp>.zip`
|
||||
- **世代管理**: 一覧表示・ダウンロード可能(世代数は運用で定義)
|
||||
- **リストア手順**: サーバ停止 → ZIP展開 → `./data/app.db` と `./data/uploads/` を差替 → サーバ再起動
|
||||
|
||||
## パフォーマンス要件
|
||||
|
||||
### 応答時間
|
||||
|
||||
| 操作 | 目標時間 | 測定環境 |
|
||||
|------|---------|---------|
|
||||
| チャットSSE配信遅延 | 送信から全クライアント受信まで3秒以内(95パーセンタイル) | 小規模同時接続(数十) |
|
||||
| 一覧画面表示 | 1000件データ時1秒以内(掲示板・チャット履歴・ファイル一覧・Markdownメモ) | ページネーション20件/頁 |
|
||||
| バックアップ作成 | DB+uploads合計100MB相当で30秒以内 | ローカルFS |
|
||||
| Migration実行 | 1ファイル1トランザクション・失敗時即座ロールバック | 初回スキーマ適用 |
|
||||
|
||||
### リソース使用量
|
||||
|
||||
| リソース | 上限 | 理由 |
|
||||
|---------|------|------|
|
||||
| メモリ | Next.jsサーバプロセス1GB程度 | 1プロジェクト数十人規模・小規模同時接続前提 |
|
||||
| CPU | 単一サーバで十分 | SQLite同期処理・SSE数十接続を想定 |
|
||||
| ディスク | DB+uploads合計数百MB〜数GBを想定 | バックアップは別途容量確保 |
|
||||
|
||||
### パフォーマンス最適化施策
|
||||
|
||||
- **ページネーション**: 全一覧APIで `?page=&pageSize=` を必須化し必要件数のみ取得
|
||||
- **インデックス**: `project_notes(project_id)`, `project_notes(updated_at)` 等の高頻度検索カラムにインデックス付与
|
||||
- **Server Components**: 可能な限りServer Componentsでデータ取得しクライアント送信量を削減
|
||||
- **WALモード**: 読み書き並行性向上
|
||||
- **SSE配信のスコープ限定**: プロジェクト単位でクライアント集合を管理し、無関係プロジェクトへの配信コストを排除
|
||||
|
||||
## セキュリティアーキテクチャ
|
||||
|
||||
### データ保護
|
||||
|
||||
- **パスワード保護**: bcryptでハッシュ化保存。平文保存禁止。ソルト付き・適切なコスト係数
|
||||
- **暗号化**: 通信はHTTPS前提。保存時のDBファイル暗号化は本スコープ外(ローカルFSのアクセス権限で保護)
|
||||
- **アクセス制御**: サーバプロセスのファイル権限により `./data/`, `./backups/` を保護
|
||||
- **機密情報管理**: 設定は `.env` で管理(`SQLITE_PATH` 等)。コード内にハードコード禁止。`.env` はリポジトリにコミットしない
|
||||
|
||||
### 認証・認可
|
||||
|
||||
- **認証**: 独自ログイン方式・セッションベース。未認証リクエストは保護画面/APIにアクセス不可(401/リダイレクト)
|
||||
- **認可(プロジェクト)**: Service層で `ProjectMemberRepository.isMember(projectId, userId)` を必ず実施。非参加者は403
|
||||
- **認可(管理者機能)**: バックアップ・Migration状態確認は `role='system_admin'` のみ許可
|
||||
- **ファイルアクセス**: ダウンロードAPIでもプロジェクト参加権限をチェック
|
||||
|
||||
### 入力バリデーション
|
||||
|
||||
- **バリデーション**: 全入力で必須チェック・長さ制限(タイトル1-200文字等)・形式チェックをService層で実施
|
||||
- **SQL対策**: 全SQLをパラメータバインドで実行。文字列結合によるSQL構築は禁止
|
||||
- **Markdownサニタイズ**: HTML直接入力無効化 + rehype-sanitize でサニタイズ + 危険URLスキーム(`javascript:`等)除外
|
||||
- **ファイルアップロード**: MIMEタイプチェック・ファイル名サニタイズ・保存名の一意化(`<uuid>.<ext>`)
|
||||
- **エラー表示**: スタックトレース・内部情報を本番では非表示。ユーザーには抽象メッセージのみ表示
|
||||
|
||||
### 監査
|
||||
|
||||
- 管理者操作・主要な変更操作をアクティビティログに記録(`activity_logs` テーブル)
|
||||
|
||||
## スケーラビリティ設計
|
||||
|
||||
### データ増大への対応
|
||||
|
||||
- **想定データ量**: 1プロジェクトあたり数十人・数千〜数万レコード(チャット・掲示板・アクティビティログが主要)
|
||||
- **性能劣化対策**:
|
||||
- ページネーションによる取得件数制限
|
||||
- インデックス最適化(検索頻度高いカラム)
|
||||
- 論理削除データの取得除外(`deleted_at IS NULL` を全取得クエリに付与)
|
||||
- **アーカイブ戦略**: 完了/アーカイブ済みプロジェクトは `status='archived'` で残置。大量データの物理削除は本スコープ外(運用で判断)
|
||||
|
||||
### 拡張性
|
||||
|
||||
- **プラグインシステム**: なし(本スコープ外)
|
||||
- **設定カスタマイズ**: `.env` による設定管理(`SQLITE_PATH`・ uploadsパス等)
|
||||
- **API拡張性**: Route Handlerベースでリソースごとにエンドポイントを分割。将来の公開REST API化はPost-MVP
|
||||
- **SSEイベント拡張**: `SseEvent` 型に新種別を追加するだけで新イベント配信が可能
|
||||
|
||||
## テスト戦略
|
||||
|
||||
### Unit Test
|
||||
- **フレームワーク**: Vitest
|
||||
- **対象**: SQLラッパー・Migration・全Repository・全Service・権限チェック・バリデーション・スケジュール重複判定・通知作成ロジック・アクティビティログ作成ロジック・マイルストーン進捗計算
|
||||
- **カバレッジ目標**: Repository/Service層 80%以上
|
||||
- **実行コマンド**: `npm test`
|
||||
|
||||
### 統合テスト
|
||||
- **方法**: Vitestで実際のSQLite(一時ファイル)を使用
|
||||
- **対象**: 認証フロー・プロジェクト作成→メンバー追加→権限分離・チャット送信→SSE配信
|
||||
|
||||
### E2E Test
|
||||
- **ツール**: Playwright
|
||||
- **シナリオ**: 認証・プロジェクト管理・掲示板・チャット(SSEリアルタイム)・ToDo(ドラッグ&ドロップ)・ファイル共有(Lightbox)・Markdownメモ・カレンダー・ミーティング(予定重複警告)・通知・アクティビティログ・バックアップ
|
||||
- **実行コマンド**: `npm run test:e2e`
|
||||
|
||||
## 技術的制約
|
||||
|
||||
### 環境要件
|
||||
- **OS**: devcontainer(開発)/ Linux想定(本番)。Windows・macOSでもNode.js Runtime動作可能
|
||||
- **最小メモリ**: 1GB
|
||||
- **必要ディスク**: DB+uploads+backups(数百MB〜数GB)
|
||||
- **必須外部依存**: なし(外部DB・外部ストレージ・外部IdPに非依存・自己完結)
|
||||
|
||||
### パフォーマンス制約
|
||||
- 1プロジェクトあたり数十人規模を想定(数百人規模はスコープ外)
|
||||
- チャットSSEは小規模同時接続(数十接続)を前提
|
||||
- 一覧取得は必ずページネーション(全件取得禁止)
|
||||
|
||||
### セキュリティ制約
|
||||
- 認証必須(`/api/auth/*`除く)
|
||||
- 全SQLパラメータバインド(文字列結合禁止)
|
||||
- Markdown表示時のHTML無効化・サニタイズ必須
|
||||
- パスワード平文保存禁止
|
||||
|
||||
### ランタイム制約
|
||||
- Edge Runtime使用禁止(SQLite直接操作のため全てNode.js Runtime)
|
||||
- Prisma使用禁止
|
||||
|
||||
## 依存管理
|
||||
|
||||
| ライブラリ | 目的 | バージョン管理方針 |
|
||||
|-----------|------|-------------------|
|
||||
| next | フレームワーク | 固定(破壊的変更リスク大) |
|
||||
| react / react-dom | UI | ^(マイナーアップ許容) |
|
||||
| better-sqlite3 | SQLiteドライバ | ^(ネイティブビルド要注意) |
|
||||
| react-markdown / remark-gfm / rehype-sanitize | Markdown | ^(マイナーアップ許容) |
|
||||
| bcrypt | パスワードハッシュ | ^ |
|
||||
| tailwindcss | スタイリング | ^ |
|
||||
| typescript | 型チェック | ~(パッチのみ自動・devDependencies) |
|
||||
| vitest | Unit Test | ^(devDependencies) |
|
||||
| @playwright/test | E2E Test | ^(devDependencies) |
|
||||
| eslint | リンタ | ^(devDependencies) |
|
||||
|
||||
**方針**:
|
||||
- 安定版は `^` でマイナーアップを許容
|
||||
- 破壊的変更リスクのあるもの(next等)は固定
|
||||
- devDependenciesは `~` でパッチのみ自動アップ許容
|
||||
- package-lock.jsonで厳密にロックしCIで再現性を担保
|
||||
|
||||
## チェックリスト
|
||||
|
||||
- [x] 全技術選定に理由が記載されている
|
||||
- [x] レイヤードアーキテクチャが明確に定義されている(依存規則含む)
|
||||
- [x] パフォーマンス要件が測定可能である
|
||||
- [x] セキュリティ考慮事項が文書化されている
|
||||
- [x] スケーラビリティが考慮されている
|
||||
- [x] バックアップ戦略が定義されている
|
||||
- [x] 依存管理方針が明確である
|
||||
- [x] テスト戦略が定義されている
|
||||
761
docs/development-guidelines.md
Normal file
761
docs/development-guidelines.md
Normal file
@ -0,0 +1,761 @@
|
||||
# 開発ガイドライン (Development Guidelines)
|
||||
|
||||
> 本書はシンプルグループウェアのチーム開発におけるコーディング規約と開発プロセスを定義する。技術スタックは `docs/architecture.md`、ディレクトリ構成は `docs/repository-structure.md` に基づく。
|
||||
|
||||
## コーディング規約
|
||||
|
||||
### 命名規約
|
||||
|
||||
#### 変数・関数
|
||||
|
||||
```typescript
|
||||
// ✅ 良い例: 役割が明確
|
||||
const projectMembers = await projectMemberRepository.findByProject(projectId);
|
||||
function formatDueDate(dueDate: string): string { }
|
||||
const hasPermission = await projectMemberRepository.isMember(projectId, userId);
|
||||
|
||||
// ❌ 悪い例: 曖昧
|
||||
const data = await repo.find(id);
|
||||
function calc(arr: any[]): number { }
|
||||
```
|
||||
|
||||
**原則**:
|
||||
- 変数: camelCase・名詞または名詞句
|
||||
- 関数: camelCase・動詞始まり(`find`, `create`, `update`, `delete`, `format`, `validate`)
|
||||
- 定数: UPPER_SNAKE_CASE(`MAX_PAGE_SIZE`, `DEFAULT_PAGE_SIZE`)
|
||||
- 真偽値: `is`, `has`, `should`, `can` 始まり(`isMember`, `hasPermission`)
|
||||
|
||||
#### クラス・インターフェース・型
|
||||
|
||||
```typescript
|
||||
// クラス: PascalCase + 役割接尾
|
||||
class UserRepository { }
|
||||
class ChatService { }
|
||||
class SqliteDatabase { }
|
||||
|
||||
// インターフェース: PascalCase(接尾辞Iは付けない)
|
||||
interface ProjectMember { }
|
||||
interface CreateMeetingInput { }
|
||||
|
||||
// 型エイリアス: PascalCase
|
||||
type ProjectStatus = 'active' | 'on_hold' | 'completed' | 'archived';
|
||||
type NotificationType = 'mention' | 'todo_assigned' | ...;
|
||||
```
|
||||
|
||||
#### ファイル名
|
||||
|
||||
- Repository/Serviceクラス: PascalCase + 接尾(`UserRepository.ts`, `ChatService.ts`)
|
||||
- 関数・ユーティリティ: camelCase・動詞始まり(`formatDate.ts`, `validateEmail.ts`)
|
||||
- 型定義: PascalCase(`TodoItem.ts`)
|
||||
- Reactコンポーネント: PascalCase(`KanbanBoard.tsx`)
|
||||
- Route Handler/画面: Next.js固定名(`route.ts`, `page.tsx`, `layout.tsx`)
|
||||
- Migration: `NNN_description.sql`(`001_initial.sql`)
|
||||
|
||||
### コードフォーマット
|
||||
|
||||
- **インデント**: 2スペース
|
||||
- **行長**: 最大100文字
|
||||
- **セミコロン**: 必須
|
||||
- **クォート**: シングルクォート
|
||||
- **ツール**: Prettier(`.prettierrc`)+ ESLint(`eslint.config.js` Flat Config)で自動整形
|
||||
|
||||
### TypeScript規約
|
||||
|
||||
#### 型定義
|
||||
|
||||
```typescript
|
||||
// ✅ 良い例: 明示的な型注釈
|
||||
function findByProject(projectId: number): ProjectMember[] { }
|
||||
|
||||
// ❌ 悪い例: 型推論への過度な依存(暗黙のany)
|
||||
function findByProject(projectId) { }
|
||||
```
|
||||
|
||||
- 公開APIの引数・戻り値には明示的な型注釈を付ける
|
||||
- `any` は原則禁止。やむを得ない場合は `unknown` + 型ガードを使用
|
||||
- オブジェクト型は `interface`、共用型・プリミティブ型は `type` エイリアスを使用
|
||||
- Entity型は `lib/types/` に集約し、レイヤ間で共有する
|
||||
|
||||
#### 関数設計
|
||||
|
||||
```typescript
|
||||
// ✅ 良い例: 単一責任・パラメータをオブジェクトに集約
|
||||
interface CreateTodoInput {
|
||||
title: string;
|
||||
description?: string;
|
||||
assigneeId?: number;
|
||||
dueDate?: string;
|
||||
priority?: TodoPriority;
|
||||
}
|
||||
function createTodo(input: CreateTodoInput): TodoItem { }
|
||||
|
||||
// ❌ 悪い例: 多すぎるパラメータ
|
||||
function createTodo(title, description, assigneeId, dueDate, priority, milestoneId): TodoItem { }
|
||||
```
|
||||
|
||||
- 1関数の責務は単一に(目安20行以内・50行推奨上限)
|
||||
- パラメータが4つ超の場合はオブジェクトに集約
|
||||
- 1ファイル300行以下推奨・500行超は分割
|
||||
|
||||
### コメント規約
|
||||
|
||||
#### ドキュメントコメント(TSDoc)
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* プロジェクトにメンバーを追加する
|
||||
*
|
||||
* @param actorId - 操作実行者のユーザーID(権限チェックに使用)
|
||||
* @param projectId - 対象プロジェクトID
|
||||
* @param userId - 追加するユーザーID
|
||||
* @param role - プロジェクト内ロール
|
||||
* @throws {ForbiddenError} 実行者に権限がない場合
|
||||
* @throws {NotFoundError} プロジェクトまたはユーザーが存在しない場合
|
||||
*/
|
||||
async function addMember(
|
||||
actorId: number,
|
||||
projectId: number,
|
||||
userId: number,
|
||||
role: ProjectMemberRole
|
||||
): Promise<void> { }
|
||||
```
|
||||
|
||||
#### インラインコメント
|
||||
|
||||
```typescript
|
||||
// ✅ 良い例: 理由を説明する
|
||||
// 論理削除済みデータを除外するため deleted_at IS NULL を付与
|
||||
const threads = db.query<BoardThread>(`
|
||||
SELECT * FROM board_threads
|
||||
WHERE project_id = @projectId AND deleted_at IS NULL
|
||||
`, { projectId });
|
||||
|
||||
// ❌ 悪い例: コードの再述
|
||||
// スレッドを取得する
|
||||
const threads = db.query(...);
|
||||
```
|
||||
|
||||
- コードから自明な内容は書かない
|
||||
- 「なぜ」その処理をするかを書く
|
||||
- TODO/FIXMEは課題番号と共に記載(`// TODO: キャッシュを実装する (Issue #123)`)
|
||||
- コメントアウトされたコードは残さない(削除する)
|
||||
|
||||
### エラーハンドリング
|
||||
|
||||
#### カスタムエラークラス
|
||||
|
||||
```typescript
|
||||
// 期待されるエラー: 適切なエラークラスを定義
|
||||
class ValidationError extends Error {
|
||||
constructor(message: string, public field: string, public value: unknown) {
|
||||
super(message);
|
||||
this.name = 'ValidationError';
|
||||
}
|
||||
}
|
||||
|
||||
class ForbiddenError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = 'ForbiddenError';
|
||||
}
|
||||
}
|
||||
|
||||
class NotFoundError extends Error {
|
||||
constructor(public resource: string, public id: number | string) {
|
||||
super(`${resource} not found: ${id}`);
|
||||
this.name = 'NotFoundError';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### エラー処理パターン
|
||||
|
||||
```typescript
|
||||
// ✅ 良い例: 期待されるエラーは適切に処理、予期せぬエラーは伝播
|
||||
async function getThread(threadId: number): Promise<BoardThread> {
|
||||
const thread = await boardRepository.findThreadById(threadId);
|
||||
if (!thread) {
|
||||
throw new NotFoundError('BoardThread', threadId);
|
||||
}
|
||||
return thread;
|
||||
}
|
||||
|
||||
// Route HandlerでのHTTPステータスへの変換
|
||||
try {
|
||||
const thread = await boardService.getThread(threadId);
|
||||
return Response.json(thread);
|
||||
} catch (error) {
|
||||
if (error instanceof ValidationError) return Response.json({ error: { message: error.message } }, { status: 400 });
|
||||
if (error instanceof ForbiddenError) return Response.json({ error: { message: error.message } }, { status: 403 });
|
||||
if (error instanceof NotFoundError) return Response.json({ error: { message: error.message } }, { status: 404 });
|
||||
console.error('Unexpected error:', error);
|
||||
return Response.json({ error: { message: '内部エラーが発生しました' } }, { status: 500 });
|
||||
}
|
||||
|
||||
// ❌ 悪い例: エラーを無視して null を返す
|
||||
async function getThread(threadId: number): Promise<BoardThread | null> {
|
||||
try {
|
||||
return await boardRepository.findThreadById(threadId);
|
||||
} catch (error) {
|
||||
return null; // エラー情報が失われる
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**原則**:
|
||||
- 期待されるエラー(バリデーション・権限・存在確認)は適切なエラークラスで表現
|
||||
- 予期せぬエラーは上位に伝播しログに記録
|
||||
- エラーを無視(空catch)しない
|
||||
- エラーメッセージは具体的で解決策を示す(`'タイトルは1-200文字で入力してください。現在: 250文字'`)
|
||||
|
||||
## プロジェクト固有規約
|
||||
|
||||
### Repository層の規約
|
||||
|
||||
#### SQLは必ずパラメータバインド
|
||||
|
||||
```typescript
|
||||
// ✅ 良い例: パラメータバインド
|
||||
const user = db.get<User>('SELECT * FROM users WHERE email = @email', { email });
|
||||
|
||||
// ❌ 悪い例: 文字列結合(SQLインジェクション脆弱性)
|
||||
const user = db.get<User>(`SELECT * FROM users WHERE email = '${email}'`);
|
||||
```
|
||||
|
||||
#### 論理削除テーブルの取得には必ず deleted_at IS NULL
|
||||
|
||||
```typescript
|
||||
// ✅ 良い例
|
||||
const notes = db.query<ProjectNote>(`
|
||||
SELECT * FROM project_notes
|
||||
WHERE project_id = @projectId AND deleted_at IS NULL
|
||||
ORDER BY is_pinned DESC, updated_at DESC
|
||||
LIMIT @limit OFFSET @offset
|
||||
`, { projectId, limit, offset });
|
||||
|
||||
// ❌ 悪い例: 削除済みデータが混入
|
||||
const notes = db.query<ProjectNote>(`SELECT * FROM project_notes WHERE project_id = @projectId`, { projectId });
|
||||
```
|
||||
|
||||
#### Repositoryは直接SQLiteライブラリを触らない
|
||||
|
||||
```typescript
|
||||
// ✅ 良い例: SQLラッパー経由
|
||||
import { getDb } from '@/lib/db/sqlite';
|
||||
const db = getDb();
|
||||
db.execute('INSERT INTO projects ...', params);
|
||||
|
||||
// ❌ 悪い例: better-sqlite3を直接操作
|
||||
import Database from 'better-sqlite3';
|
||||
const db = new Database('./data/app.db');
|
||||
```
|
||||
|
||||
#### ページネーション
|
||||
|
||||
一覧取得APIは必ずページネーション(`LIMIT`/`OFFSET`)し、全件取得しない。
|
||||
|
||||
```typescript
|
||||
function findThreads(projectId: number, page: number, pageSize: number = 20) {
|
||||
const offset = (page - 1) * pageSize;
|
||||
return db.query<BoardThread>(`
|
||||
SELECT * FROM board_threads
|
||||
WHERE project_id = @projectId AND deleted_at IS NULL
|
||||
ORDER BY is_pinned DESC, created_at DESC
|
||||
LIMIT @pageSize OFFSET @offset
|
||||
`, { projectId, pageSize, offset });
|
||||
}
|
||||
```
|
||||
|
||||
### Service層の規約
|
||||
|
||||
#### 権限チェックを必ず実施
|
||||
|
||||
```typescript
|
||||
// ✅ 良い例: 操作前に権限チェック
|
||||
async function addMember(actorId: number, projectId: number, userId: number, role: ProjectMemberRole) {
|
||||
const actorRole = await projectMemberRepository.getRole(projectId, actorId);
|
||||
if (!actorRole || actorRole !== 'admin') {
|
||||
throw new ForbiddenError('プロジェクト管理者のみメンバー追加が可能です');
|
||||
}
|
||||
// ...メンバー追加処理
|
||||
}
|
||||
```
|
||||
|
||||
#### トランザクション境界の明示
|
||||
|
||||
複数テーブルを更新する場合はトランザクション内で実行する。
|
||||
|
||||
```typescript
|
||||
async function createMeeting(actorId: number, projectId: number, input: MeetingInput) {
|
||||
return db.transaction(() => {
|
||||
const meeting = meetingRepository.create({ ...input, projectId, createdById: actorId });
|
||||
meetingRepository.addMembers(meeting.id, input.memberIds);
|
||||
activityLogService.log({ projectId, actorId, action: 'meeting_created', targetType: 'meeting', targetId: meeting.id });
|
||||
return meeting;
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
#### 副作用の分離
|
||||
|
||||
通知生成・アクティビティログ記録・SSE配信は専用Service(`NotificationService`, `ActivityLogService`, `SseHub`)に委譲し、業務ロジックと分離する。
|
||||
|
||||
### Next.js規約
|
||||
|
||||
#### Node.js Runtimeの明示
|
||||
|
||||
```typescript
|
||||
// app/api/.../route.ts の先頭
|
||||
export const runtime = 'nodejs'; // Edge Runtime使用禁止
|
||||
```
|
||||
|
||||
#### Server Componentsを優先
|
||||
|
||||
データ取得は可能な限りServer Componentsで行い、クライアント送信量を削減する。インタラクティブな要素(ドラッグ&ドロップ・SSE受信・フォーム)のみClient Componentsとする。
|
||||
|
||||
#### Markdownレンダリングの安全性
|
||||
|
||||
```typescript
|
||||
// ✅ 必ず rehype-sanitize を通す
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
import rehypeSanitize from 'rehype-sanitize';
|
||||
|
||||
<ReactMarkdown remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeSanitize]}>
|
||||
{bodyMd}
|
||||
</ReactMarkdown>
|
||||
```
|
||||
|
||||
HTML直接入力は無効化し、危険なURLスキーム(`javascript:`等)は除外する。
|
||||
|
||||
### セキュリティ規約
|
||||
|
||||
- 機密情報(パスワード・APIキー)はコードにハードコードしない。`.env` で管理
|
||||
- パスワードは bcrypt でハッシュ化保存
|
||||
- ファイルアップロードはMIMEタイプチェック・ファイル名サニタイズ・保存名の一意化
|
||||
- ファイルアクセスAPIでもプロジェクト参加権限をチェック
|
||||
- 管理者機能(バックアップ・Migration状態)は `role='system_admin'` のみ許可
|
||||
|
||||
## Gitワークフロー規則
|
||||
|
||||
### ブランチ戦略(Git Flow)
|
||||
|
||||
```
|
||||
main (本番環境)
|
||||
└── develop (開発統合)
|
||||
├── feature/task-management
|
||||
├── feature/user-auth
|
||||
├── fix/chat-sse-reconnect
|
||||
└── refactor/todo-repository
|
||||
```
|
||||
|
||||
**運用ルール**:
|
||||
- `main`: リリース済みの安定コードのみ。タグでバージョン管理
|
||||
- `develop`: 次回リリースの最新開発コード。CIで自動テスト実行
|
||||
- `feature/*`, `fix/*`: developから分岐しPR経由でdevelopへマージ
|
||||
- `release/*`: リリース準備(必要に応じて)
|
||||
- `hotfix/*`: 本番障害対応(mainから分岐しmain/develop両方へマージ)
|
||||
- 直接コミット禁止: 全ブランチでPRレビュー必須
|
||||
- マージ方針: feature→develop はsquash merge推奨、develop→main はmerge commit
|
||||
|
||||
### コミットメッセージ規約(Conventional Commits)
|
||||
|
||||
```
|
||||
<type>(<scope>): <subject>
|
||||
|
||||
<body>
|
||||
|
||||
<footer>
|
||||
```
|
||||
|
||||
**type**:
|
||||
- `feat`: 新機能
|
||||
- `fix`: バグ修正
|
||||
- `docs`: ドキュメント
|
||||
- `style`: フォーマット(コード挙動への影響なし)
|
||||
- `refactor`: リファクタリング
|
||||
- `perf`: パフォーマンス改善
|
||||
- `test`: テスト追加・修正
|
||||
- `build`: ビルドシステム
|
||||
- `ci`: CI/CD設定
|
||||
- `chore`: その他(依存更新等)
|
||||
|
||||
**例**:
|
||||
```
|
||||
feat(chat): SSEによるリアルタイムメッセージ配信を実装
|
||||
|
||||
プロジェクト別のSSEエンドポイントを追加し、メッセージ送信時に
|
||||
参加メンバーへリアルタイム配信する。
|
||||
|
||||
- SseHubクラスをlib/sse/hub.tsに追加
|
||||
- ChatService.sendMessageでブロードキャスト
|
||||
- chat.message.created/updated/deletedイベント定義
|
||||
|
||||
Closes #42
|
||||
```
|
||||
|
||||
### Pull Requestプロセス
|
||||
|
||||
**PR作成前チェック**:
|
||||
- [ ] 全テスト成功(`npm test`, `npm run test:e2e`)
|
||||
- [ ] Lintエラーなし(`npm run lint`)
|
||||
- [ ] 型チェック成功(`npm run typecheck`)
|
||||
- [ ] コンフリクト解消済み
|
||||
|
||||
**PRテンプレート**:
|
||||
```markdown
|
||||
## 変更種別
|
||||
- [ ] 新機能 (feat)
|
||||
- [ ] バグ修正 (fix)
|
||||
- [ ] リファクタリング (refactor)
|
||||
- [ ] ドキュメント (docs)
|
||||
- [ ] その他 (chore)
|
||||
|
||||
## 概要
|
||||
[変更内容の簡潔な説明]
|
||||
|
||||
## 変更理由
|
||||
[なぜこの変更が必要か]
|
||||
|
||||
## 変更内容
|
||||
- [変更1]
|
||||
- [変更2]
|
||||
|
||||
## テスト
|
||||
- [ ] Unit Test追加
|
||||
- [ ] E2E Test追加
|
||||
- [ ] 手動テスト実施
|
||||
|
||||
テスト結果: [説明]
|
||||
|
||||
## 関連Issue
|
||||
Closes #[番号]
|
||||
|
||||
## レビューポイント
|
||||
[特に確認してほしい点]
|
||||
```
|
||||
|
||||
**レビュープロセス**:
|
||||
1. セルフレビュー
|
||||
2. 自動テスト実行(CI)
|
||||
3. レビュアー割当
|
||||
4. レビュー指摘対応
|
||||
5. 承認後にマージ
|
||||
|
||||
**PRサイズ目安**:
|
||||
- 小PR(100行以下): 推奨
|
||||
- 中PR(100-300行): 許容
|
||||
- 大PR(300行超): 分割を検討
|
||||
|
||||
## テスト戦略
|
||||
|
||||
### テスト実装の必須条件
|
||||
|
||||
本プロジェクトでは、品質担保のため **Unit Test(Vitest)と E2E Test(Playwright)の実装を必須とする。** テストが未実装・未成功のPRはマージ不可。
|
||||
|
||||
#### Unit Test(Vitest)の実装【必須】
|
||||
|
||||
以下の対象について Unit Test の実装を必須とする。新規実装・修正時に対応する Unit Test を必ず作成すること。
|
||||
|
||||
- SQLラッパー
|
||||
- Migration実行
|
||||
- 全Repositoryクラス(User / Project / ProjectMember / Board / Chat / Todo / File / Calendar / Meeting / ProjectNote / Notification / ActivityLog)
|
||||
- 全Serviceクラス(Auth / Project / Chat / Meeting / Schedule / FileStorage / Backup)
|
||||
- 権限チェック・バリデーション・スケジュール重複判定・通知作成ロジック・アクティビティログ作成ロジック・マイルストーン進捗計算
|
||||
|
||||
**合格基準**:
|
||||
- [ ] `npm test` で全件成功すること
|
||||
- [ ] Repository/Service層のカバレッジ 80%以上を維持すること
|
||||
- [ ] 正常系・異常系(権限エラー・バリデーションエラー・存在確認)を網羅すること
|
||||
|
||||
#### E2E Test(Playwright)の実装【必須】
|
||||
|
||||
主要ユーザーフローについて Playwright による E2E Test の実装を必須とする。機能追加時は該当フローの E2E Test を必ず作成すること。
|
||||
|
||||
対象フロー:
|
||||
- 認証(ログイン・ログアウト・未ログインの保護)
|
||||
- プロジェクト管理(作成・編集・メンバー追加/削除・アーカイブ)
|
||||
- 掲示板(スレッド作成・編集・コメント・検索)
|
||||
- チャット(送信・SSEリアルタイム受信・編集・削除)
|
||||
- ToDo / Kanban(カラム作成・タスク作成・編集・移動・担当者/期限設定・完了)
|
||||
- ファイル共有(アップロード・一覧・Lightbox閲覧・PDFプレビュー・削除)
|
||||
- Markdownメモ(作成・編集・プレビュー・ピン留め・検索・削除)
|
||||
- カレンダー(ToDo期限・マイルストーン・ミーティング表示・イベント作成/編集)
|
||||
- ミーティング(作成・参加メンバー設定・予定重複警告・アジェンダ/議事録・関連付け)
|
||||
- 通知(ToDo担当者・メンション・ミーティング参加者への通知・既読化)
|
||||
- アクティビティログ(各操作の記録)
|
||||
- バックアップ(作成・一覧表示・ダウンロード)
|
||||
|
||||
**合格基準**:
|
||||
- [ ] `npm run test:e2e` で全件成功すること
|
||||
- [ ] 主要フローのカバレッジ 100%を維持すること
|
||||
|
||||
### テストピラミッド
|
||||
|
||||
```
|
||||
/\
|
||||
/E2E\ 少数(遅い・高コスト)
|
||||
/------\
|
||||
/ Integ. \ 中程度
|
||||
/----------\
|
||||
/ Unit \ 多数(高速・低コスト)
|
||||
/--------------\
|
||||
```
|
||||
|
||||
**対象比率**:
|
||||
- Unit Test: 70%
|
||||
- Integration Test: 20%
|
||||
- E2E Test: 10%
|
||||
|
||||
### Unit Test(Vitest)
|
||||
|
||||
**対象**: SQLラッパー・Migration・全Repository・全Service・権限チェック・バリデーション・スケジュール重複判定・通知作成ロジック・アクティビティログ作成ロジック・マイルストーン進捗計算
|
||||
|
||||
**カバレッジ目標**: Repository/Service層 80%以上
|
||||
|
||||
**構造(Given-When-Then)**:
|
||||
```typescript
|
||||
describe('ChatService', () => {
|
||||
describe('sendMessage', () => {
|
||||
it('有効なデータでメッセージを作成できる', async () => {
|
||||
// Given: セットアップ
|
||||
const chatService = new ChatService(mockChatRepo, mockSseHub, mockNotificationService);
|
||||
const input = { body: 'テストメッセージ' };
|
||||
|
||||
// When: 実行
|
||||
const result = await chatService.sendMessage(actorId, projectId, input.body);
|
||||
|
||||
// Then: 検証
|
||||
expect(result.id).toBeDefined();
|
||||
expect(result.body).toBe('テストメッセージ');
|
||||
expect(mockSseHub.broadcast).toHaveBeenCalledWith(projectId, expect.objectContaining({ type: 'chat.message.created' }));
|
||||
});
|
||||
|
||||
it('プロジェクト非参加者はメッセージ送信時にForbiddenErrorを投げる', async () => {
|
||||
// Given
|
||||
const chatService = new ChatService(...);
|
||||
mockProjectMemberRepository.isMember.mockReturnValue(false);
|
||||
|
||||
// When/Then
|
||||
await expect(chatService.sendMessage(nonMemberId, projectId, 'body')).rejects.toThrow(ForbiddenError);
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**テスト命名**: `[対象]_[条件]_[期待結果]`
|
||||
```typescript
|
||||
it('findById_existingId_returnsThread', () => { });
|
||||
it('findById_nonExistentId_returnsNull', () => { });
|
||||
it('create_emptyTitle_throwsValidationError', () => { });
|
||||
```
|
||||
|
||||
**モック原則**: 外部依存(DB・ファイルシステム・SSE)はモック化、業務ロジックは実体を使用。
|
||||
|
||||
### Integration Test(Vitest)
|
||||
|
||||
**対象**: 複数コンポーネントの連携。実際のSQLite(一時ファイル)を使用。
|
||||
|
||||
```typescript
|
||||
describe('プロジェクトメンバー権限', () => {
|
||||
it('非参加者はプロジェクトデータにアクセスできない', async () => {
|
||||
// 実DBでプロジェクト・ユーザー作成
|
||||
const project = await projectService.createProject(ownerId, { name: 'P1' });
|
||||
await expect(boardService.listThreads(nonMemberId, project.id)).rejects.toThrow(ForbiddenError);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### E2E Test(Playwright)
|
||||
|
||||
**対象**: 主要ユーザーフローの全体検証。`tests/e2e/*.spec.ts`。
|
||||
|
||||
```typescript
|
||||
test('チャットメッセージがSSEでリアルタイム配信される', async ({ browser }) => {
|
||||
const contextA = await browser.newContext();
|
||||
const contextB = await browser.newContext();
|
||||
const pageA = await contextA.newPage();
|
||||
const pageB = await contextB.newPage();
|
||||
|
||||
// 両ブラウザで同プロジェクトのチャット画面を開く
|
||||
await pageA.goto('/projects/1/chat');
|
||||
await pageB.goto('/projects/1/chat');
|
||||
|
||||
// Aがメッセージ送信
|
||||
await pageA.fill('input[name=message]', 'こんにちは');
|
||||
await pageA.click('button[type=submit]');
|
||||
|
||||
// Bにリアルタイム表示される
|
||||
await expect(pageB.locator('text=こんにちは')).toBeVisible();
|
||||
});
|
||||
```
|
||||
|
||||
**カバレッジ目標**: 主要フロー100%(認証・プロジェクト管理・掲示板・チャット・ToDo・ファイル・メモ・カレンダー・ミーティング・通知・アクティビティ・バックアップ)
|
||||
|
||||
### 実行コマンド
|
||||
|
||||
| コマンド | 説明 |
|
||||
|---------|------|
|
||||
| `npm test` | Unit Test実行(Vitest) |
|
||||
| `npm run test:e2e` | E2E Test実行(Playwright) |
|
||||
| `npm run lint` | Lint実行(ESLint) |
|
||||
| `npm run typecheck` | 型チェック実行(tsc --noEmit) |
|
||||
| `npm run build` | ビルド |
|
||||
|
||||
## コードレビュー基準
|
||||
|
||||
### レビューポイント
|
||||
|
||||
**機能性**:
|
||||
- [ ] 要件を満たしているか
|
||||
- [ ] エッジケースが考慮されているか
|
||||
- [ ] エラーハンドリングが適切か
|
||||
|
||||
**可読性**:
|
||||
- [ ] 命名が明確か
|
||||
- [ ] コメントが適切か
|
||||
- [ ] 複雑なロジックに説明があるか
|
||||
|
||||
**保守性**:
|
||||
- [ ] 重複コードがないか
|
||||
- [ ] 責務が分離されているか
|
||||
- [ ] 変更の影響範囲が限定的か
|
||||
|
||||
**パフォーマンス**:
|
||||
- [ ] 不要な計算がないか
|
||||
- [ ] N+1クエリになっていないか
|
||||
- [ ] 一覧取得がページネーションされているか
|
||||
|
||||
**セキュリティ**:
|
||||
- [ ] 入力バリデーションが適切か
|
||||
- [ ] SQLがパラメータバインドされているか
|
||||
- [ ] 権限チェックが実装されているか
|
||||
- [ ] 機密情報のハードコードがないか
|
||||
- [ ] Markdownがサニタイズされているか
|
||||
|
||||
### レビューコメントの書き方
|
||||
|
||||
**建設的フィードバック**:
|
||||
```markdown
|
||||
// ✅ 良い例
|
||||
この実装だとメンバー数増加時にN+1クエリになります。
|
||||
JOINで一括取得するのはいかがでしょうか?
|
||||
|
||||
// ❌ 悪い例
|
||||
この書き方は良くないです。
|
||||
```
|
||||
|
||||
**優先度の明示**:
|
||||
- `[必須]`: 修正必須(セキュリティ・バグ等)
|
||||
- `[推奨]`: 修正推奨
|
||||
- `[提案]`: 検討提案
|
||||
- `[質問]`: 意図の確認
|
||||
|
||||
## 開発環境セットアップ
|
||||
|
||||
### 必須ツール
|
||||
|
||||
| ツール | バージョン | インストール方法 |
|
||||
|--------|-----------|-----------------|
|
||||
| Node.js | v24.11.0 | 公式インストーラ/nvm |
|
||||
| npm | 11.x | Node.jsにバンドル |
|
||||
| devcontainer | - | VS Code拡張(開発環境統一) |
|
||||
|
||||
### セットアップ手順
|
||||
|
||||
```bash
|
||||
# 1. リポジトリクローン
|
||||
git clone [URL]
|
||||
cd [project-name]
|
||||
|
||||
# 2. 依存関係インストール
|
||||
npm install
|
||||
|
||||
# 3. 環境変数設定
|
||||
cp .env.example .env
|
||||
# .env を編集(SQLITE_PATH等)
|
||||
|
||||
# 4. DB初期化(Migration実行)
|
||||
npm run migrate
|
||||
|
||||
# 5. 開発サーバ起動
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### 品質自動化
|
||||
|
||||
**Pre-commit(Husky + lint-staged)**: コミット前にLint・フォーマット・型チェックを自動実行
|
||||
|
||||
```json
|
||||
// package.json
|
||||
{
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"format": "prettier --write .",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "vitest run",
|
||||
"test:e2e": "playwright test",
|
||||
"migrate": "tsx lib/db/run-migrations.ts",
|
||||
"dev": "next dev",
|
||||
"build": "next build"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{ts,tsx}": ["eslint --fix", "prettier --write"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**CI(GitHub Actions)**: PR作成時にLint・型チェック・Unit Test・ビルドを自動実行
|
||||
|
||||
```yaml
|
||||
# .github/workflows/ci.yml
|
||||
name: CI
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with: { node-version: '24' }
|
||||
- run: npm ci
|
||||
- run: npm run lint
|
||||
- run: npm run typecheck
|
||||
- run: npm run test
|
||||
- run: npm run build
|
||||
```
|
||||
|
||||
**効果**: 欠陥コードの混入防止・早期発見による修正コスト削減・CIによる品質担保。
|
||||
|
||||
## チェックリスト
|
||||
|
||||
### 実装完了前
|
||||
- [ ] 命名が明確で一貫している
|
||||
- [ ] 関数が単一責務
|
||||
- [ ] マジックナンバーがない
|
||||
- [ ] 型注釈が適切
|
||||
- [ ] エラーハンドリングが実装されている
|
||||
|
||||
### セキュリティ
|
||||
- [ ] 入力バリデーション実装
|
||||
- [ ] 機密情報のハードコードなし
|
||||
- [ ] SQLパラメータバインド
|
||||
- [ ] 権限チェック実装
|
||||
- [ ] Markdownサニタイズ
|
||||
|
||||
### パフォーマンス
|
||||
- [ ] 適切なデータ構造
|
||||
- [ ] N+1クエリ回避
|
||||
- [ ] 一覧のページネーション
|
||||
|
||||
### テスト【必須】
|
||||
- [ ] Unit Test(Vitest)作成
|
||||
- [ ] E2E Test(Playwright)作成
|
||||
- [ ] `npm test` 全件成功
|
||||
- [ ] `npm run test:e2e` 全件成功
|
||||
- [ ] エッジケース網羅
|
||||
|
||||
### ツール
|
||||
- [ ] Lintエラーなし
|
||||
- [ ] 型チェック成功
|
||||
- [ ] フォーマット統一
|
||||
1077
docs/functional-design.md
Normal file
1077
docs/functional-design.md
Normal file
File diff suppressed because it is too large
Load Diff
1606
docs/ideas/initial-requirements.md
Normal file
1606
docs/ideas/initial-requirements.md
Normal file
File diff suppressed because it is too large
Load Diff
870
docs/milestones.md
Normal file
870
docs/milestones.md
Normal file
@ -0,0 +1,870 @@
|
||||
# マイルストーン・タスク定義書 (Milestones & Tasks)
|
||||
|
||||
> 本書は `docs/product-requirements.md`・`docs/functional-design.md`・`docs/architecture.md`・`docs/repository-structure.md`・`docs/development-guidelines.md` に基づき、プロジェクト全体のマイルストーンと各マイルストーンのタスクを詳細に定義する。機能漏れを防ぐため、末尾に「機能カバレッジマトリクス」を設ける。
|
||||
|
||||
## マイルストーン全体構成
|
||||
|
||||
PRDの開発フェーズ(Phase 1〜5)を依存関係を考慮して15マイルストーンに展開する。
|
||||
|
||||
| MS | 名称 | 対応フェーズ | 主な成果物 | 前提 |
|
||||
|----|------|------------|-----------|------|
|
||||
| M1 | プロジェクト基盤セットアップ | Phase 1 | Next.js環境・設定ファイル・CI | - |
|
||||
| M2 | DB基盤(SQLラッパー・Migration) | Phase 1 | sqlite.ts・migrator.ts・初期スキーマ | M1 |
|
||||
| M3 | 認証・ユーザー管理 | Phase 1 | AuthService・UserRepository・ログイン画面 | M2 |
|
||||
| M4 | プロジェクト管理・メンバー管理 | Phase 1 | ProjectService・プロジェクト画面・レイアウト | M3 |
|
||||
| M5 | 通知・アクティビティログ基盤 | Phase 2 | NotificationService・ActivityLogService | M4 |
|
||||
| M6 | 掲示板 | Phase 2 | BoardService・掲示板画面 | M5 |
|
||||
| M7 | Markdownメモ | Phase 2 | NoteService・メモエディタ・Markdownプレビュー | M5 |
|
||||
| M8 | SSE基盤・チャット | Phase 3 | SseHub・ChatService・チャット画面 | M5 |
|
||||
| M9 | ToDo / Kanban | Phase 3 | TodoService・Kanbanボード | M8 |
|
||||
| M10 | ファイル共有・Lightbox | Phase 4 | FileStorageService・Lightbox | M4 |
|
||||
| M11 | カレンダー・マイルストーン | Phase 4 | ScheduleService・カレンダーUI・進捗計算 | M9 |
|
||||
| M12 | ミーティング管理・スケジュール重複 | Phase 5 | MeetingService・重複判定アルゴリズム | M11 |
|
||||
| M13 | 検索・ダッシュボード完成 | (横断) | 横断検索・個人/プロジェクトダッシュボード | M6-M12 |
|
||||
| M14 | バックアップ・管理者機能 | Phase 5 | BackupService・管理者画面 | M2 |
|
||||
| M15 | 全体テスト完成・品質担保 | (全体) | 全Unit/E2E/統合テスト成功 | M1-M14 |
|
||||
|
||||
### マイルストーン進行ルール
|
||||
|
||||
- 各マイルストーン完了時に `npm run lint`・`npm run typecheck` が成功すること
|
||||
- 各マイルストーンで実装したRepository/Service/画面には **Unit Test または E2E Test を必須で実装**する(`docs/development-guidelines.md` テスト実装の必須条件に準拠)
|
||||
- テスト未実装・未成功のマイルストーンは完了扱いとしない
|
||||
|
||||
---
|
||||
|
||||
## M1: プロジェクト基盤セットアップ
|
||||
|
||||
**目的**: Next.js 15 + TypeScript + Tailwind CSS の開発環境を構築し、全レイヤのディレクトリ構成と品質自動化ツールを整える。
|
||||
|
||||
**前提**: なし
|
||||
|
||||
### 実装タスク
|
||||
|
||||
**基盤・設定**:
|
||||
- [ ] Next.js 15 プロジェクト初期化(App Router・TypeScript)
|
||||
- [ ] Tailwind CSS セットアップ(`app/globals.css`・`tailwind.config`)
|
||||
- [ ] `tsconfig.json` 設定(`@/*` パスエイリアス・strict モード)
|
||||
- [ ] `next.config.mjs` 設定
|
||||
- [ ] `.env.example` 作成(`SQLITE_PATH`・uploadsパス等)
|
||||
- [ ] ディレクトリ構成作成: `app/`・`lib/`・`repositories/`・`services/`・`components/`・`tests/`・`data/`・`backups/`
|
||||
|
||||
**品質自動化ツール**:
|
||||
- [ ] ESLint セットアップ(`eslint.config.js` Flat Config)
|
||||
- [ ] Prettier セットアップ(`.prettierrc`・`.prettierignore`)
|
||||
- [ ] Vitest セットアップ(`vitest.config.ts`)
|
||||
- [ ] Playwright セットアップ(`playwright.config.ts`)
|
||||
- [ ] Husky + lint-staged セットアップ(pre-commit で Lint・フォーマット・型チェック)
|
||||
- [ ] CI 設定(`.github/workflows/ci.yml`): Lint・型チェック・Unit Test・ビルド
|
||||
|
||||
**package.json スクリプト**:
|
||||
- [ ] `lint`・`format`・`typecheck`・`test`・`test:e2e`・`migrate`・`dev`・`build` スクリプト定義
|
||||
|
||||
**依存関係**:
|
||||
- [ ] 本体依存: next・react・react-dom・better-sqlite3・bcrypt・react-markdown・remark-gfm・rehype-sanitize・tailwindcss
|
||||
- [ ] dev依存: typescript・vitest・@playwright/test・eslint・prettier・husky・lint-staged・tsx
|
||||
|
||||
### 完了条件
|
||||
- [ ] `npm run dev` で開発サーバが起動する
|
||||
- [ ] `npm run lint`・`npm run typecheck`・`npm run build` が成功する
|
||||
- [ ] ディレクトリ構成が `repository-structure.md` に準拠している
|
||||
|
||||
---
|
||||
|
||||
## M2: DB基盤(SQLラッパー・Migration)
|
||||
|
||||
**目的**: SQLiteへの共通アクセス基盤とSQLファイルベースのMigration機構を実装する。
|
||||
|
||||
**前提**: M1
|
||||
|
||||
### 実装タスク
|
||||
|
||||
**Data層**:
|
||||
- [ ] `lib/db/sqlite.ts`: `SqliteDatabase` クラス実装
|
||||
- `query<T>` / `get<T>` / `execute` / `transaction<T>` / `close`
|
||||
- コンストラクタで `journal_mode=WAL`・`foreign_keys=ON` 設定
|
||||
- `getDb()` シングルトン(dbPath = `process.env.SQLITE_PATH ?? "./data/app.db"`)
|
||||
- [ ] `lib/db/migrator.ts`: `Migrator` クラス実装
|
||||
- `schema_migrations` テーブル作成
|
||||
- ファイル名順実行・実行済み再実行回避・1ファイル1トランザクション・失敗時ロールバック
|
||||
- [ ] `lib/db/migrations/001_initial.sql`: 全16テーブル + インデックス作成
|
||||
- users・projects・project_members・board_threads・board_comments・chat_messages・todo_columns・todo_items・file_assets・project_notes・milestones・calendar_events・meetings・meeting_members・notifications・activity_logs
|
||||
- `idx_project_notes_project_id`・`idx_project_notes_updated_at` インデックス
|
||||
|
||||
**型定義**:
|
||||
- [ ] `lib/types/` に全Entity型定義(User・Project・ProjectMember・BoardThread・BoardComment・ChatMessage・TodoColumn・TodoItem・FileAsset・ProjectNote・Milestone・CalendarEvent・Meeting・MeetingMember・Notification・ActivityLog・SchemaMigration)
|
||||
- 列挙型: `UserRole`・`UserStatus`・`ProjectStatus`・`ProjectMemberRole`・`BoardCategory`・`TodoPriority`・`MilestoneStatus`・`CalendarEventType`・`MeetingMemberStatus`・`NotificationType`
|
||||
|
||||
**Migration実行・状態確認**:
|
||||
- [ ] `lib/db/run-migrations.ts`: Migration実行スクリプト(`npm run migrate`)
|
||||
- [ ] API: `GET /api/admin/migrations`(Migration状態確認・管理者のみ)
|
||||
|
||||
### テスト
|
||||
- [ ] **Unit Test**: `tests/unit/lib/db/sqlite.test.ts`(query/get/execute/transaction・WAL/外部キー設定)
|
||||
- [ ] **Unit Test**: `tests/unit/lib/db/migrator.test.ts`(ファイル名順実行・再実行回避・失敗時ロールバック)
|
||||
|
||||
### 完了条件
|
||||
- [ ] `npm run migrate` で初期スキーマが作成される
|
||||
- [ ] Migrationがファイル名順に実行され、実行済みは再実行されない
|
||||
- [ ] Migration失敗時にロールバックされる
|
||||
- [ ] Unit Test が成功する
|
||||
|
||||
---
|
||||
|
||||
## M3: 認証・ユーザー管理
|
||||
|
||||
**目的**: 独自ログイン方式による認証とユーザー管理(登録・ログイン・プロフィール・ロール・有効/無効)を実装する。
|
||||
|
||||
**前提**: M2
|
||||
|
||||
### 実装タスク
|
||||
|
||||
**Repository**:
|
||||
- [ ] `repositories/UserRepository.ts`: `findById`・`findByEmail`・`create`・`update`
|
||||
|
||||
**Service**:
|
||||
- [ ] `services/AuthService.ts`: `register`・`login`・`logout`・`getCurrentUser`・`updateProfile`
|
||||
- [ ] パスワードハッシュ化(bcrypt・平文保存禁止)
|
||||
- [ ] ロール管理(system_admin・project_admin・member・guest)
|
||||
- [ ] アカウント有効/無効(status='inactive' はログイン不可)
|
||||
|
||||
**認証ヘルパ**:
|
||||
- [ ] `lib/auth/session.ts`: セッション読み書き
|
||||
- [ ] `lib/auth/getCurrentUser.ts`: リクエストから現在ユーザー解決
|
||||
|
||||
**バリデータ**:
|
||||
- [ ] `lib/validators/userValidator.ts`: 必須・メール形式・パスワード強度・名前長
|
||||
|
||||
**API**:
|
||||
- [ ] `POST /api/auth/register`(ユーザー登録)
|
||||
- [ ] `POST /api/auth/login`(ログイン・Set-Cookie)
|
||||
- [ ] `POST /api/auth/logout`(ログアウト)
|
||||
- [ ] `GET /api/auth/me`(現在のユーザー)
|
||||
- [ ] `PATCH /api/users/me`(プロフィール編集: 表示名・メール・アイコン画像)
|
||||
- [ ] 全Route Handler に `export const runtime = 'nodejs'` 明示
|
||||
- [ ] 認証ミドルウェア: 未ログイン時は保護画面をログイン画面へリダイレクト(401)
|
||||
|
||||
**画面**:
|
||||
- [ ] `app/login/page.tsx`(ログイン画面)
|
||||
- [ ] `app/profile/page.tsx`(ユーザープロフィール・アイコン画像設定・表示名設定)
|
||||
- [ ] `app/layout.tsx`(ルートレイアウト)
|
||||
|
||||
### テスト
|
||||
- [ ] **Unit Test**: `tests/unit/repositories/UserRepository.test.ts`(CRUD・email一意・論理的確認)
|
||||
- [ ] **Unit Test**: `tests/unit/services/AuthService.test.ts`(登録・ログイン・ログアウト・プロフィール更新・無効アカウント拒否)
|
||||
- [ ] **E2E Test**: `tests/e2e/auth.spec.ts`(ログイン・ログアウト・未ログインの保護画面アクセス拒否)
|
||||
|
||||
### 完了条件
|
||||
- [ ] ユーザー登録・ログイン・ログアウトができる
|
||||
- [ ] パスワードがハッシュ化保存される
|
||||
- [ ] プロフィール・アイコン画像が編集できる
|
||||
- [ ] 無効アカウントはログイン不可
|
||||
- [ ] 未ログインで保護画面にアクセスできない
|
||||
- [ ] Unit Test・E2E Test が成功する
|
||||
|
||||
---
|
||||
|
||||
## M4: プロジェクト管理・メンバー管理
|
||||
|
||||
**目的**: プロジェクトの作成・編集・削除・アーカイブと、メンバー追加・削除・ロール設定を実装する。プロジェクトダッシュボードの骨組みも作る。
|
||||
|
||||
**前提**: M3
|
||||
|
||||
### 実装タスク
|
||||
|
||||
**Repository**:
|
||||
- [ ] `repositories/ProjectRepository.ts`: `findById`・`findByOwner`・`create`・`update`・`delete`
|
||||
- [ ] `repositories/ProjectMemberRepository.ts`: `findByProject`・`findByUser`・`add`・`remove`・`isMember`・`getRole`
|
||||
|
||||
**Service**:
|
||||
- [ ] `services/ProjectService.ts`: `createProject`・`updateProject`・`addMember`・`removeMember`・`archiveProject`・`getDashboard`
|
||||
- [ ] 権限チェック: `isMember`・`getRole`(非参加者は403・プロジェクト管理者権限チェック)
|
||||
- [ ] プロジェクトステータス管理(active・on_hold・completed・archived)
|
||||
- [ ] メンバー追加時に通知(M5のNotificationService連携)
|
||||
|
||||
**バリデータ**:
|
||||
- [ ] `lib/validators/projectValidator.ts`: プロジェクト名1-200文字・説明文
|
||||
|
||||
**API**:
|
||||
- [ ] `GET /api/projects`(自分の参加プロジェクト一覧)
|
||||
- [ ] `POST /api/projects`(プロジェクト作成)
|
||||
- [ ] `GET /api/projects/:projectId`(プロジェクト詳細/ダッシュボード)
|
||||
- [ ] `PATCH /api/projects/:projectId`(プロジェクト編集: 名前・説明・ステータス)
|
||||
- [ ] `DELETE /api/projects/:projectId`(プロジェクト削除)
|
||||
- [ ] `GET /api/projects/:projectId/members`(メンバー一覧)
|
||||
- [ ] `POST /api/projects/:projectId/members`(メンバー追加)
|
||||
- [ ] `DELETE /api/projects/:projectId/members/:userId`(メンバー削除)
|
||||
|
||||
**画面・コンポーネント**:
|
||||
- [ ] `app/dashboard/page.tsx`(個人ダッシュボード骨組み: 参加プロジェクト一覧)
|
||||
- [ ] `app/projects/[projectId]/page.tsx`(プロジェクト概要/ダッシュボード骨組み)
|
||||
- [ ] `app/projects/[projectId]/members/page.tsx`(メンバー管理)
|
||||
- [ ] `app/projects/[projectId]/settings/page.tsx`(プロジェクト設定)
|
||||
- [ ] `components/layout/`(Header・Sidebar・ProjectNav)
|
||||
- [ ] `components/project/`(ProjectCard・DashboardWidget)
|
||||
|
||||
### テスト
|
||||
- [ ] **Unit Test**: `tests/unit/repositories/ProjectRepository.test.ts`
|
||||
- [ ] **Unit Test**: `tests/unit/repositories/ProjectMemberRepository.test.ts`(CRUD・UNIQUE制約・isMember・getRole)
|
||||
- [ ] **Unit Test**: `tests/unit/services/ProjectService.test.ts`(作成・編集・アーカイブ・メンバー追加/削除・権限チェック・プロジェクト分離)
|
||||
- [ ] **Integration Test**: `tests/integration/project-member-permission.test.ts`(非参加者はプロジェクトデータにアクセス不可)
|
||||
- [ ] **E2E Test**: `tests/e2e/project-management.spec.ts`(作成・編集・メンバー追加/削除・アーカイブ)
|
||||
|
||||
### 完了条件
|
||||
- [ ] プロジェクト作成・編集・削除・アーカイブができる
|
||||
- [ ] メンバー追加・削除・ロール設定ができる
|
||||
- [ ] 非参加者はプロジェクト情報にアクセスできない(403)
|
||||
- [ ] Unit・Integration・E2E Test が成功する
|
||||
|
||||
---
|
||||
|
||||
## M5: 通知・アクティビティログ基盤
|
||||
|
||||
**目的**: 通知生成とアクティビティログ記録の基盤Serviceを実装し、後続機能(掲示板・チャット・ToDo等)から利用可能にする。
|
||||
|
||||
**前提**: M4
|
||||
|
||||
### 実装タスク
|
||||
|
||||
**Repository**:
|
||||
- [ ] `repositories/NotificationRepository.ts`: 通知作成・未読一覧(ページネーション)・既読化
|
||||
- [ ] `repositories/ActivityLogRepository.ts`: ログ作成・プロジェクト別一覧(ページネーション)
|
||||
|
||||
**Service**:
|
||||
- [ ] `services/NotificationService.ts`: `notifyOnEvent`・`resolveTargets`
|
||||
- 対象イベント: mention・todo_assigned・todo_due_soon・meeting_invited・board_commented・project_added・file_shared・note_updated
|
||||
- 対象ユーザー解決ロジック(メンション先・担当者・ミーティング参加者・掲示板投稿者・プロジェクトメンバー等)
|
||||
- [ ] `services/ActivityLogService.ts`: `logActivity`
|
||||
- 記録対象: todo_created・todo_updated・todo_completed・file_uploaded・board_posted・comment_added・note_created・note_updated・meeting_created・member_added・milestone_updated
|
||||
- [ ] 管理者操作もアクティビティログに記録
|
||||
|
||||
**API**:
|
||||
- [ ] `GET /api/notifications`(未読通知一覧)
|
||||
- [ ] `POST /api/notifications/:id/read`(既読化)
|
||||
- [ ] `GET /api/projects/:projectId/activity`(アクティビティログ一覧)
|
||||
|
||||
**画面・コンポーネント**:
|
||||
- [ ] `app/notifications/page.tsx`(通知一覧画面)※共通画面
|
||||
- [ ] `components/notifications/NotificationList.tsx`・`NotificationBadge.tsx`(ヘッダの未読バッジ)
|
||||
- [ ] `app/projects/[projectId]/activity/page.tsx`(プロジェクト別アクティビティログ画面)
|
||||
|
||||
### テスト
|
||||
- [ ] **Unit Test**: `tests/unit/repositories/NotificationRepository.test.ts`
|
||||
- [ ] **Unit Test**: `tests/unit/repositories/ActivityLogRepository.test.ts`
|
||||
- [ ] **Unit Test**: `tests/unit/services/NotificationService.test.ts`(正しいユーザーへ通知作成・resolveTargets)
|
||||
- [ ] **Unit Test**: `tests/unit/services/ActivityLogService.test.ts`(ログ記録・プロジェクト分離)
|
||||
|
||||
### 完了条件
|
||||
- [ ] 各イベント種別で通知が正しいユーザーに作成される
|
||||
- [ ] 変更操作がアクティビティログに記録される
|
||||
- [ ] 通知の既読化ができる
|
||||
- [ ] Unit Test が成功する
|
||||
|
||||
---
|
||||
|
||||
## M6: 掲示板
|
||||
|
||||
**目的**: プロジェクト単位の非リアルタイム情報共有(スレッド・コメント・カテゴリ・ピン留め・重要マーク・既読・検索)を実装する。
|
||||
|
||||
**前提**: M5
|
||||
|
||||
### 実装タスク
|
||||
|
||||
**Repository**:
|
||||
- [ ] `repositories/BoardRepository.ts`: スレッドCRUD・コメントCRUD・検索・ページネーション(`deleted_at IS NULL` 必須)
|
||||
|
||||
**Service**:
|
||||
- [ ] `services/BoardService.ts`: スレッド作成/編集/削除・コメント作成/編集/削除
|
||||
- [ ] 権限チェック(プロジェクト参加者のみ)
|
||||
- [ ] カテゴリ分類(notice・spec・minutes・question・decision・trouble・memo)
|
||||
- [ ] ピン留め・重要マーク
|
||||
- [ ] 既読管理
|
||||
- [ ] コメント追加時に通知(`board_commented` → 投稿者)・アクティビティログ記録(`board_posted`・`comment_added`)
|
||||
|
||||
**API**:
|
||||
- [ ] `GET /api/projects/:projectId/board/threads`(一覧・ページネーション・検索)
|
||||
- [ ] `POST /api/projects/:projectId/board/threads`(作成)
|
||||
- [ ] `GET /api/projects/:projectId/board/threads/:threadId`(詳細)
|
||||
- [ ] `PATCH /api/projects/:projectId/board/threads/:threadId`(編集)
|
||||
- [ ] `DELETE /api/projects/:projectId/board/threads/:threadId`(削除)
|
||||
- [ ] `POST /api/projects/:projectId/board/threads/:threadId/comments`(コメント作成)
|
||||
- [ ] `PATCH /api/projects/:projectId/board/comments/:commentId`(コメント編集)
|
||||
- [ ] `DELETE /api/projects/:projectId/board/comments/:commentId`(コメント削除)
|
||||
|
||||
**画面・コンポーネント**:
|
||||
- [ ] `app/projects/[projectId]/board/page.tsx`(掲示板一覧)
|
||||
- [ ] スレッド詳細・作成/編集フォーム
|
||||
- [ ] `components/board/`(ThreadList・ThreadForm・CommentList)
|
||||
- [ ] Markdown本文表示(react-markdown + rehype-sanitize)
|
||||
|
||||
### テスト
|
||||
- [ ] **Unit Test**: `tests/unit/repositories/BoardRepository.test.ts`(CRUD・論理削除非取得・プロジェクト分離・検索)
|
||||
- [ ] **Unit Test**: `tests/unit/services/BoardService.test.ts`(権限チェック・カテゴリ・ピン留め・通知・アクティビティログ)
|
||||
- [ ] **E2E Test**: `tests/e2e/board.spec.ts`(スレッド作成・編集・コメント・検索)
|
||||
|
||||
### 完了条件
|
||||
- [ ] スレッド・コメントのCRUDができる
|
||||
- [ ] カテゴリ・ピン留め・重要マーク・既読・検索ができる
|
||||
- [ ] 論理削除済みデータが通常取得に含まれない
|
||||
- [ ] Unit・E2E Test が成功する
|
||||
|
||||
---
|
||||
|
||||
## M7: Markdownメモ
|
||||
|
||||
**目的**: プロジェクトごとのMarkdownメモ(作成・編集・プレビュー・タグ・ピン留め・検索・添付・関連付け)を実装する。
|
||||
|
||||
**前提**: M5
|
||||
|
||||
### 実装タスク
|
||||
|
||||
**Repository**:
|
||||
- [ ] `repositories/ProjectNoteRepository.ts`: メモCRUD・検索・ピン留め(`deleted_at IS NULL`・インデックス活用)
|
||||
|
||||
**Service**:
|
||||
- [ ] `services/NoteService.ts`: メモ作成/編集/削除
|
||||
- [ ] 権限チェック
|
||||
- [ ] タイトル・タグ・ピン留め
|
||||
- [ ] 作成者・最終更新者・更新日時管理
|
||||
- [ ] ファイル添付・関連ToDo・関連ミーティング設定
|
||||
- [ ] 更新時に通知(`note_updated`)・アクティビティログ(`note_created`・`note_updated`)
|
||||
|
||||
**Markdownレンダリング(セキュリティ)**:
|
||||
- [ ] react-markdown + remark-gfm + rehype-sanitize でプレビュー
|
||||
- [ ] HTML直接入力無効化・危険URLスキーム(`javascript:`等)除外
|
||||
- [ ] 対応記法: 見出し・箇条書き・番号リスト・チェックリスト・コードブロック・テーブル・リンク・画像・引用
|
||||
|
||||
**API**:
|
||||
- [ ] `GET /api/projects/:projectId/notes`(一覧・検索・ページネーション)
|
||||
- [ ] `POST /api/projects/:projectId/notes`(作成)
|
||||
- [ ] `GET /api/projects/:projectId/notes/:noteId`(詳細)
|
||||
- [ ] `PATCH /api/projects/:projectId/notes/:noteId`(編集)
|
||||
- [ ] `DELETE /api/projects/:projectId/notes/:noteId`(削除)
|
||||
|
||||
**画面・コンポーネント**:
|
||||
- [ ] `app/projects/[projectId]/notes/page.tsx`(メモ一覧)
|
||||
- [ ] メモエディタ・プレビュー画面
|
||||
- [ ] `components/notes/`(NoteEditor・MarkdownPreview)
|
||||
|
||||
### テスト
|
||||
- [ ] **Unit Test**: `tests/unit/repositories/ProjectNoteRepository.test.ts`(CRUD・検索・ピン留め・論理削除・プロジェクト分離)
|
||||
- [ ] **Unit Test**: `tests/unit/services/NoteService.test.ts`(権限・タグ・ピン留め・関連付け・通知・アクティビティログ)
|
||||
- [ ] **E2E Test**: `tests/e2e/markdown-notes.spec.ts`(作成・編集・プレビュー・ピン留め・検索・削除)
|
||||
|
||||
### 完了条件
|
||||
- [ ] MarkdownメモのCRUD・プレビューができる
|
||||
- [ ] タグ・ピン留め・検索ができる
|
||||
- [ ] MarkdownがサニタイズされHTML直接入力が無効化される
|
||||
- [ ] Unit・E2E Test が成功する
|
||||
|
||||
---
|
||||
|
||||
## M8: SSE基盤・チャット
|
||||
|
||||
**目的**: SSE配信基盤(SseHub)とプロジェクト別リアルタイムチャット(送信・編集・削除・メンション・リアクション・既読/未読・検索)を実装する。
|
||||
|
||||
**前提**: M5
|
||||
|
||||
### 実装タスク
|
||||
|
||||
**SSE基盤**:
|
||||
- [ ] `lib/sse/hub.ts`: `SseHub` クラス(`addClient`・`removeClient`・`broadcast`)
|
||||
- プロジェクト単位のクライアント集合管理
|
||||
- 当該プロジェクトのみ配信(他プロジェクトへ漏れさせない)
|
||||
- [ ] SSEエンドポイント: `GET /api/projects/:projectId/chat/stream`
|
||||
- [ ] クライアント側の自動再接続対応
|
||||
- [ ] SSEイベント種別: `chat.message.created`・`chat.message.updated`・`chat.message.deleted`・`todo.updated`・`file.uploaded`・`meeting.created`・`note.updated`・`notification.created`
|
||||
|
||||
**Repository**:
|
||||
- [ ] `repositories/ChatRepository.ts`: メッセージCRUD・ページネーション・検索(`deleted_at IS NULL`)
|
||||
|
||||
**Service**:
|
||||
- [ ] `services/ChatService.ts`: `sendMessage`・`editMessage`・`deleteMessage`・`getHistory`
|
||||
- [ ] 権限チェック(プロジェクト参加者のみ)
|
||||
- [ ] メンション検出 → 通知(`mention`)
|
||||
- [ ] SSE配信(`chat.message.created/updated/deleted`)
|
||||
- [ ] リアクション・既読/未読・添付ファイル
|
||||
|
||||
**API**:
|
||||
- [ ] `GET /api/projects/:projectId/chat/messages`(履歴・ページネーション・検索)
|
||||
- [ ] `POST /api/projects/:projectId/chat/messages`(送信)
|
||||
- [ ] `PATCH /api/projects/:projectId/chat/messages/:messageId`(編集)
|
||||
- [ ] `DELETE /api/projects/:projectId/chat/messages/:messageId`(削除)
|
||||
|
||||
**画面・コンポーネント**:
|
||||
- [ ] `app/projects/[projectId]/chat/page.tsx`(チャット画面)
|
||||
- [ ] `components/chat/`(ChatWindow・MessageInput・MessageList)
|
||||
|
||||
### テスト
|
||||
- [ ] **Unit Test**: `tests/unit/lib/sse/hub.test.ts`(クライアント管理・プロジェクト別配信・配信スコープ)
|
||||
- [ ] **Unit Test**: `tests/unit/repositories/ChatRepository.test.ts`(CRUD・検索・論理削除・プロジェクト分離)
|
||||
- [ ] **Unit Test**: `tests/unit/services/ChatService.test.ts`(送信・編集・削除・メンション通知・SSE配信呼出・権限)
|
||||
- [ ] **Integration Test**: `tests/integration/chat-sse-broadcast.test.ts`(送信→SSE配信)
|
||||
- [ ] **E2E Test**: `tests/e2e/chat-sse.spec.ts`(送信・別コンテキストでSSEリアルタイム受信・編集・削除)
|
||||
|
||||
### 完了条件
|
||||
- [ ] メッセージ送信・編集・削除ができる
|
||||
- [ ] SSEで別クライアントにリアルタイム配信される
|
||||
- [ ] 接続切断時に自動再接続される
|
||||
- [ ] メンション・リアクション・既読/未読・検索ができる
|
||||
- [ ] Unit・Integration・E2E Test が成功する
|
||||
|
||||
---
|
||||
|
||||
## M9: ToDo / Kanban
|
||||
|
||||
**目的**: プロジェクトごとのタスクをKanban形式で管理する(カラム・タスク・ドラッグ&ドロップ・担当者・期限・優先度・ラベル・チェックリスト・完了・マイルストーン紐づけ・カレンダー表示)。
|
||||
|
||||
**前提**: M8
|
||||
|
||||
### 実装タスク
|
||||
|
||||
**Repository**:
|
||||
- [ ] `repositories/TodoRepository.ts`: カラムCRUD・タスクCRUD・並び替え(orderIndex再計算)・ページネーション(`deleted_at IS NULL`)
|
||||
|
||||
**Service**:
|
||||
- [ ] `services/TodoService.ts`: カラム作成/編集/削除/並び替え・タスク作成/編集/削除/移動
|
||||
- [ ] 権限チェック
|
||||
- [ ] 担当者・期限・優先度(low/normal/high)・ラベル設定
|
||||
- [ ] チェックリスト・コメント・添付ファイル
|
||||
- [ ] 完了状態管理(`completedAt`)
|
||||
- [ ] マイルストーン紐づけ
|
||||
- [ ] 担当者割り当て時に通知(`todo_assigned`)・アクティビティログ(`todo_created`・`todo_updated`・`todo_completed`)
|
||||
- [ ] SSE配信(`todo.updated`)
|
||||
- [ ] 標準カラム初期生成: Backlog・To Do・In Progress・Review・Done
|
||||
|
||||
**API**:
|
||||
- [ ] `GET /api/projects/:projectId/todos/columns`(カラム一覧)
|
||||
- [ ] `POST /api/projects/:projectId/todos/columns`(カラム作成)
|
||||
- [ ] `PATCH /api/projects/:projectId/todos/columns/:columnId`(カラム編集/並び替え)
|
||||
- [ ] `DELETE /api/projects/:projectId/todos/columns/:columnId`(カラム削除)
|
||||
- [ ] `GET /api/projects/:projectId/todos/items`(タスク一覧)
|
||||
- [ ] `POST /api/projects/:projectId/todos/items`(タスク作成)
|
||||
- [ ] `PATCH /api/projects/:projectId/todos/items/:itemId`(タスク編集/移動)
|
||||
- [ ] `DELETE /api/projects/:projectId/todos/items/:itemId`(タスク削除)
|
||||
|
||||
**画面・コンポーネント**:
|
||||
- [ ] `app/projects/[projectId]/todos/page.tsx`(Kanbanボード)
|
||||
- [ ] `components/todo/`(KanbanBoard・KanbanColumn・TodoCard)ドラッグ&ドロップ対応
|
||||
|
||||
### テスト
|
||||
- [ ] **Unit Test**: `tests/unit/repositories/TodoRepository.test.ts`(CRUD・並び替え・論理削除・プロジェクト分離)
|
||||
- [ ] **Unit Test**: `tests/unit/services/TodoService.test.ts`(作成・編集・移動・完了・担当者通知・アクティビティログ・権限)
|
||||
- [ ] **E2E Test**: `tests/e2e/todo-kanban.spec.ts`(カラム作成・タスク作成・編集・別カラム移動・担当者/期限設定・完了)
|
||||
|
||||
### 完了条件
|
||||
- [ ] Kanbanボードが表示される(標準カラム5つ)
|
||||
- [ ] カラム・タスクのCRUD・ドラッグ&ドロップ移動ができる
|
||||
- [ ] 担当者・期限・優先度・ラベル・チェックリスト・コメントが設定できる
|
||||
- [ ] 完了タスクがDoneカラムに表示される
|
||||
- [ ] Unit・E2E Test が成功する
|
||||
|
||||
---
|
||||
|
||||
## M10: ファイル共有・Lightbox
|
||||
|
||||
**目的**: プロジェクト内ファイルのアップロード・一覧・フォルダ管理・Lightbox閲覧・PDFプレビュー・紐づけを実装する。
|
||||
|
||||
**前提**: M4
|
||||
|
||||
### 実装タスク
|
||||
|
||||
**Repository**:
|
||||
- [ ] `repositories/FileRepository.ts`: ファイルメタCRUD・フォルダ管理(`deleted_at IS NULL`)
|
||||
|
||||
**Service**:
|
||||
- [ ] `services/FileStorageService.ts`: `upload`・`getDownloadStream`・`delete`
|
||||
- ローカルFS保存: `data/uploads/<projectId>/<uuid>.<ext>`
|
||||
- MIMEタイプチェック・ファイル名サニタイズ・保存名一意化
|
||||
- ファイルアクセス権限チェック(プロジェクト参加者のみ)
|
||||
- アクティビティログ(`file_uploaded`)・通知(`file_shared`)・SSE配信(`file.uploaded`)
|
||||
|
||||
**ファイル紐づけ**:
|
||||
- [ ] ファイルとToDo・掲示板投稿・ミーティング・Markdownメモの紐づけ
|
||||
- [ ] ファイルコメント
|
||||
|
||||
**API**:
|
||||
- [ ] `GET /api/projects/:projectId/files`(一覧・ページネーション)
|
||||
- [ ] `POST /api/projects/:projectId/files`(アップロード・multipart)
|
||||
- [ ] `GET /api/files/:fileId/download`(ダウンロード・権限チェック)
|
||||
- [ ] `DELETE /api/files/:fileId`(削除)
|
||||
|
||||
**画面・コンポーネント**:
|
||||
- [ ] `app/projects/[projectId]/files/page.tsx`(ファイル一覧)
|
||||
- [ ] `components/files/`(FileList・Uploader・Lightbox)
|
||||
- 画像Lightbox表示・PDFプレビュー
|
||||
|
||||
### テスト
|
||||
- [ ] **Unit Test**: `tests/unit/repositories/FileRepository.test.ts`
|
||||
- [ ] **Unit Test**: `tests/unit/services/FileStorageService.test.ts`(アップロード・MIMEチェック・保存名一意化・権限・削除・アクティビティログ)
|
||||
- [ ] **E2E Test**: `tests/e2e/file-sharing.spec.ts`(アップロード・一覧・Lightbox閲覧・PDFプレビュー・削除)
|
||||
|
||||
### 完了条件
|
||||
- [ ] ファイルアップロード・一覧・ダウンロード・削除ができる
|
||||
- [ ] 画像をLightboxで閲覧できる・PDFをプレビューできる
|
||||
- [ ] MIMEチェック・権限チェックが機能する
|
||||
- [ ] ファイル紐づけ・コメントができる
|
||||
- [ ] Unit・E2E Test が成功する
|
||||
|
||||
---
|
||||
|
||||
## M11: カレンダー・マイルストーン
|
||||
|
||||
**目的**: カレンダー(月/週/日/リスト表示・各種イベント表示・フィルター)とマイルストーン管理(CRUD・進捗率自動計算)を実装する。
|
||||
|
||||
**前提**: M9
|
||||
|
||||
### 実装タスク
|
||||
|
||||
**Repository**:
|
||||
- [ ] `repositories/CalendarRepository.ts`: イベントCRUD・期間検索(`deleted_at IS NULL`)
|
||||
- [ ] `repositories/MilestoneRepository.ts`: マイルストーンCRUD・関連ToDo取得(`deleted_at IS NULL`)
|
||||
|
||||
**Service**:
|
||||
- [ ] `services/ScheduleService.ts`: `getCalendarEvents`(期間・フィルター)
|
||||
- 表示対象: マイルストーン・デッドライン・ToDo開始日・ToDo期限・ミーティング・任意イベント
|
||||
- メンバー別フィルター・種別フィルター
|
||||
- [ ] マイルストーン管理Service: 作成/編集/削除・期限・説明文・関連ToDo紐づけ
|
||||
- [ ] **進捗率自動計算アルゴリズム**: 関連ToDoの完了率から0-100を算出
|
||||
- [ ] 完了状態管理・カレンダー表示
|
||||
- [ ] アクティビティログ(`milestone_updated`)
|
||||
|
||||
**API**:
|
||||
- [ ] `GET /api/projects/:projectId/calendar/events`(イベント一覧・期間・フィルタ)
|
||||
- [ ] `POST /api/projects/:projectId/calendar/events`(イベント作成)
|
||||
- [ ] `PATCH /api/projects/:projectId/calendar/events/:eventId`(編集)
|
||||
- [ ] `DELETE /api/projects/:projectId/calendar/events/:eventId`(削除)
|
||||
- [ ] `GET /api/projects/:projectId/milestones`(マイルストーン一覧)
|
||||
- [ ] `POST /api/projects/:projectId/milestones`(作成)
|
||||
- [ ] `PATCH /api/projects/:projectId/milestones/:id`(編集)
|
||||
- [ ] `GET /api/projects/:projectId/milestones/:id/progress`(進捗率取得)
|
||||
|
||||
**画面・コンポーネント**:
|
||||
- [ ] `app/projects/[projectId]/calendar/page.tsx`(カレンダー: 月/週/日/リスト表示)
|
||||
- [ ] `app/projects/[projectId]/milestones/page.tsx`(マイルストーン一覧・進捗バー)
|
||||
- [ ] `components/calendar/`(CalendarView・EventBadge)
|
||||
|
||||
### テスト
|
||||
- [ ] **Unit Test**: `tests/unit/repositories/CalendarRepository.test.ts`
|
||||
- [ ] **Unit Test**: `tests/unit/repositories/MilestoneRepository.test.ts`
|
||||
- [ ] **Unit Test**: `tests/unit/services/ScheduleService.test.ts`(期間検索・フィルタ・種別別取得)
|
||||
- [ ] **Unit Test**: 進捗率計算アルゴリズム(`calcMilestoneProgress`・ToDo0件時0%・完了率計算)
|
||||
- [ ] **E2E Test**: `tests/e2e/calendar.spec.ts`(ToDo期限・マイルストーン・ミーティング表示・イベント作成/編集)
|
||||
|
||||
### 完了条件
|
||||
- [ ] 月/週/日/リスト表示ができる
|
||||
- [ ] マイルストーン・デッドライン・ToDo期限・ミーティングが表示される
|
||||
- [ ] イベントCRUD・フィルターができる
|
||||
- [ ] マイルストーン進捗率が自動計算される
|
||||
- [ ] Unit・E2E Test が成功する
|
||||
|
||||
---
|
||||
|
||||
## M12: ミーティング管理・スケジュール重複チェック
|
||||
|
||||
**目的**: ミーティングCRUD・参加メンバー設定・アジェンダ/議事録・関連付け・スケジュール重複判定を実装する。
|
||||
|
||||
**前提**: M11
|
||||
|
||||
### 実装タスク
|
||||
|
||||
**Repository**:
|
||||
- [ ] `repositories/MeetingRepository.ts`: ミーティングCRUD・meeting_members管理(`deleted_at IS NULL`)
|
||||
|
||||
**Service**:
|
||||
- [ ] `services/MeetingService.ts`: `createMeeting`・`updateMeeting`・`deleteMeeting`・`checkScheduleConflicts`・`updateMinutes`
|
||||
- [ ] 権限チェック
|
||||
- [ ] タイトル・説明・開始/終了日時・参加メンバー・場所・ミーティングURL設定
|
||||
- [ ] アジェンダ・議事録(Markdown)
|
||||
- [ ] 関連ToDo・関連ファイル・関連掲示板投稿・関連Markdownメモ設定
|
||||
- [ ] カレンダー表示連携
|
||||
- [ ] 参加者招待通知(`meeting_invited`)・アクティビティログ(`meeting_created`)・SSE配信(`meeting.created`)
|
||||
|
||||
**スケジュール重複判定アルゴリズム**:
|
||||
- [ ] `checkScheduleConflicts`: 選択メンバーの予定重複を検出
|
||||
- 判定対象1: 他のミーティング(meeting_members経由・時間重複)
|
||||
- 判定対象2: カレンダーイベント(時間重複)
|
||||
- 判定対象3: 期限の近い重要タスク(priority='high'・dueDate ±3日以内)
|
||||
- 時間重複判定: `NOT (existing.end <= new.start OR existing.start >= new.end)`
|
||||
- 重複があれば警告返却(作成自体はブロックしない)
|
||||
|
||||
**API**:
|
||||
- [ ] `GET /api/projects/:projectId/meetings`(一覧)
|
||||
- [ ] `POST /api/projects/:projectId/meetings`(作成・conflicts返却)
|
||||
- [ ] `PATCH /api/projects/:projectId/meetings/:id`(編集)
|
||||
- [ ] `POST /api/projects/:projectId/meetings/check`(予定重複チェックのみ)
|
||||
|
||||
**画面・コンポーネント**:
|
||||
- [ ] `app/projects/[projectId]/meetings/page.tsx`(ミーティング一覧)
|
||||
- [ ] ミーティング作成フォーム・アジェンダ/議事録編集
|
||||
- [ ] `components/meetings/`(MeetingForm・ConflictWarning)
|
||||
|
||||
### テスト
|
||||
- [ ] **Unit Test**: `tests/unit/repositories/MeetingRepository.test.ts`(CRUD・meeting_members・UNIQUE制約・論理削除・プロジェクト分離)
|
||||
- [ ] **Unit Test**: `tests/unit/services/MeetingService.test.ts`(作成・編集・議事録更新・参加者通知・アクティビティログ・権限)
|
||||
- [ ] **Unit Test**: スケジュール重複判定アルゴリズム(他ミーティング重複・カレンダーイベント重複・重要タスク検出・時間重複ロジック・excludeMeetingId)
|
||||
- [ ] **E2E Test**: `tests/e2e/meetings.spec.ts`(作成・参加メンバー設定・予定重複警告・アジェンダ/議事録・関連付け)
|
||||
|
||||
### 完了条件
|
||||
- [ ] ミーティングCRUD・参加メンバー設定ができる
|
||||
- [ ] アジェンダ・議事録が入力できる
|
||||
- [ ] 関連付け(ToDo/ファイル/掲示板/メモ)ができる
|
||||
- [ ] 参加メンバーの予定重複が画面上で警告される
|
||||
- [ ] Unit・E2E Test が成功する
|
||||
|
||||
---
|
||||
|
||||
## M13: 検索・ダッシュボード完成
|
||||
|
||||
**目的**: プロジェクト内横断検索と、個人/プロジェクトダッシュボードの全項目表示を完成させる。
|
||||
|
||||
**前提**: M6-M12(各データソース完成後)
|
||||
|
||||
### 実装タスク
|
||||
|
||||
**横断検索**:
|
||||
- [ ] 検索対象: 掲示板・チャット・ToDo・ファイル名・カレンダーイベント・ミーティング・議事録・マイルストーン・Markdownメモ
|
||||
- [ ] 検索条件: キーワード・投稿者・担当者・日付・種別・プロジェクト・タグ
|
||||
- [ ] API: `GET /api/projects/:projectId/search`
|
||||
- [ ] 画面: 検索結果一覧
|
||||
|
||||
**個人ダッシュボード完成**:
|
||||
- [ ] 自分の参加プロジェクト
|
||||
- [ ] 自分の未完了ToDo
|
||||
- [ ] 今日の予定
|
||||
- [ ] 近日中のミーティング
|
||||
- [ ] 未読通知
|
||||
- [ ] 期限切れタスク
|
||||
- [ ] 最近のアクティビティ
|
||||
- [ ] `app/dashboard/page.tsx` 完成版
|
||||
|
||||
**プロジェクトダッシュボード完成**:
|
||||
- [ ] プロジェクト概要
|
||||
- [ ] 進行中ToDo
|
||||
- [ ] 期限が近いToDo(7日以内)
|
||||
- [ ] 最新チャット(直近5件)
|
||||
- [ ] 最新掲示板(ピン留め優先・直近5件)
|
||||
- [ ] 最新Markdownメモ(ピン留め優先・直近5件)
|
||||
- [ ] 最近のファイル(直近5件)
|
||||
- [ ] 次回ミーティング(直近1件)
|
||||
- [ ] マイルストーン進捗(進捗バー付き)
|
||||
- [ ] 最近のアクティビティ(直近10件)
|
||||
- [ ] `app/projects/[projectId]/page.tsx` 完成版
|
||||
|
||||
### テスト
|
||||
- [ ] **Unit Test**: 検索ロジック(各リソース横断検索・フィルタ絞り込み)
|
||||
- [ ] **Unit Test**: ダッシュボード集計ロジック(未完了ToDo・期限近いToDo・今日の予定等)
|
||||
- [ ] **E2E Test**: ダッシュボード表示確認(個人・プロジェクト各項目の表示)
|
||||
|
||||
### 完了条件
|
||||
- [ ] 横断検索で全リソースが検索できる
|
||||
- [ ] 検索フィルターが機能する
|
||||
- [ ] 個人ダッシュボードの全項目が表示される
|
||||
- [ ] プロジェクトダッシュボードの全項目が表示される
|
||||
- [ ] Unit・E2E Test が成功する
|
||||
|
||||
---
|
||||
|
||||
## M14: バックアップ・管理者機能
|
||||
|
||||
**目的**: 管理者によるバックアップ作成(DB+uploads ZIP化)・一覧・ダウンロードとMigration状態確認画面を実装する。
|
||||
|
||||
**前提**: M2
|
||||
|
||||
### 実装タスク
|
||||
|
||||
**Service**:
|
||||
- [ ] `services/BackupService.ts`: `createBackup`・`listBackups`・`downloadBackup`
|
||||
- SQLite DBファイル + uploadsディレクトリをZIP化
|
||||
- 保存先: `backups/backup-<timestamp>.zip`
|
||||
- 管理者権限チェック(`role='system_admin'` のみ)
|
||||
- 管理者操作をアクティビティログに記録
|
||||
|
||||
**API**:
|
||||
- [ ] `GET /api/admin/backups`(バックアップ一覧・管理者のみ)
|
||||
- [ ] `POST /api/admin/backups`(バックアップ作成・管理者のみ)
|
||||
- [ ] `GET /api/admin/backups/:filename`(ダウンロード・管理者のみ)
|
||||
- [ ] `GET /api/admin/migrations`(Migration状態確認・管理者のみ)※M2でAPI実装済なら画面連携
|
||||
|
||||
**画面**:
|
||||
- [ ] `app/admin/backups/page.tsx`(管理者バックアップ画面: 作成・一覧・ダウンロード)
|
||||
- [ ] Migration状態確認画面(管理者)
|
||||
|
||||
### テスト
|
||||
- [ ] **Unit Test**: `tests/unit/services/BackupService.test.ts`(バックアップ作成・ZIP化・一覧・ダウンロード・権限チェック)
|
||||
- [ ] **E2E Test**: `tests/e2e/backup.spec.ts`(作成・一覧表示・ダウンロード)
|
||||
|
||||
### 完了条件
|
||||
- [ ] 管理者がバックアップを作成できる
|
||||
- [ ] バックアップ一覧が表示される
|
||||
- [ ] バックアップファイルをダウンロードできる
|
||||
- [ ] 非管理者はアクセスできない(403)
|
||||
- [ ] Migration状態が確認できる
|
||||
- [ ] Unit・E2E Test が成功する
|
||||
|
||||
---
|
||||
|
||||
## M15: 全体テスト完成・品質担保
|
||||
|
||||
**目的**: 全マイルストールのテストを統合し、カバレッジ目標と成功条件/受け入れ要件を全項目クリアする。
|
||||
|
||||
**前提**: M1-M14
|
||||
|
||||
### 実装タスク
|
||||
|
||||
**Unit Test 完成**:
|
||||
- [ ] SQLラッパー・Migration・全13Repository・全12Service のUnit Test 完成
|
||||
- [ ] 権限チェック・バリデーション・スケジュール重複判定・通知作成ロジック・アクティビティログ作成ロジック・マイルストーン進捗計算 のUnit Test 完成
|
||||
- [ ] Repository/Service層カバレッジ 80%以上
|
||||
- [ ] `npm test` 全件成功
|
||||
|
||||
**統合テスト完成**:
|
||||
- [ ] `tests/integration/auth-flow.test.ts`(登録→ログイン→保護画面アクセス)
|
||||
- [ ] `tests/integration/project-member-permission.test.ts`(プロジェクト作成→メンバー追加→権限分離)
|
||||
- [ ] `tests/integration/chat-sse-broadcast.test.ts`(チャット送信→SSE配信)
|
||||
|
||||
**E2E Test 完成**:
|
||||
- [ ] 全12シナリオ完成: auth・project-management・board・chat-sse・todo-kanban・file-sharing・markdown-notes・calendar・meetings・notifications・activity-log・backup
|
||||
- [ ] 主要フローカバレッジ 100%
|
||||
- [ ] `npm run test:e2e` 全件成功
|
||||
|
||||
**品質ゲート**:
|
||||
- [ ] `npm run lint` エラーなし
|
||||
- [ ] `npm run typecheck` 成功
|
||||
- [ ] `npm run build` 成功
|
||||
|
||||
**受け入れ要件確認**:
|
||||
- [ ] PRD「成功条件/受け入れ要件」の全項目を確認(ユーザーログイン〜バックアップ作成・Unit Test・E2E Test 全成功まで)
|
||||
|
||||
### 完了条件
|
||||
- [ ] `npm test` でUnit Testが全件成功する
|
||||
- [ ] `npm run test:e2e` でPlaywright E2E Testが全件成功する
|
||||
- [ ] 統合テストが全件成功する
|
||||
- [ ] Lint・型チェック・ビルドが成功する
|
||||
- [ ] PRDの受け入れ要件を全項目クリアする
|
||||
|
||||
---
|
||||
|
||||
## 機能カバレッジマトリクス
|
||||
|
||||
PRDの機能要件(16機能)+DB基盤+テストがどのマイルストーンで実装されるかを示す。機能漏れがないことを保証する。
|
||||
|
||||
| 機能 | PRD優先度 | 実装MS | 完了確認MS | 備考 |
|
||||
|------|----------|--------|-----------|------|
|
||||
| DB基盤(SQLラッパー・Migration・Repository基盤) | P0 | M2 | M2 | 全16テーブル+schema_migrations |
|
||||
| ユーザー管理(登録・ログイン・プロフィール・ロール・有効/無効) | P0 | M3 | M3 | bcrypt・独自ログイン |
|
||||
| プロジェクト管理(作成・編集・削除・アーカイブ・ステータス) | P0 | M4 | M4 | |
|
||||
| プロジェクトメンバー管理(追加・削除・ロール) | P0 | M4 | M4 | |
|
||||
| 通知(アプリ内・未読一覧・既読化・8イベント) | P0 | M5 | M5 | 基盤Service・各機能から連携 |
|
||||
| アクティビティログ(11操作記録・時系列表示) | P1 | M5 | M5 | 基盤Service・各機能から連携 |
|
||||
| 掲示板(スレッド・コメント・カテゴリ・ピン留め・重要・既読・検索) | P0 | M6 | M6 | |
|
||||
| Markdownメモ(CRUD・プレビュー・タグ・ピン留め・検索・添付・関連付け) | P0 | M7 | M7 | サニタイズ必須 |
|
||||
| SSE基盤(SseHub・プロジェクト別配信・自動再接続・8イベント) | P0 | M8 | M8 | |
|
||||
| チャット(送信・編集・削除・メンション・リアクション・既読/未読・検索) | P0 | M8 | M8 | SSEリアルタイム |
|
||||
| ToDo / Kanban(カラム・タスク・D&D・担当・期限・優先度・ラベル・チェックリスト・完了・マイルストーン紐づけ) | P0 | M9 | M9 | |
|
||||
| ファイル共有(アップロード・一覧・フォルダ・Lightbox・PDF・コメント・紐づけ・MIMEチェック) | P0 | M10 | M10 | ローカルFS保存 |
|
||||
| カレンダー(月/週/日/リスト・イベントCRUD・フィルタ) | P0 | M11 | M11 | |
|
||||
| マイルストーン管理(CRUD・期限・関連ToDo・進捗率自動計算・完了) | P1 | M11 | M11 | |
|
||||
| ミーティング管理(CRUD・メンバー・アジェンダ/議事録・関連付け・カレンダー連携) | P0 | M12 | M12 | |
|
||||
| スケジュール重複チェック(他ミーティング・カレンダーイベント・重要タスク) | P0 | M12 | M12 | 警告表示(ブロックしない) |
|
||||
| 検索(横断検索・7フィルタ条件) | P1 | M13 | M13 | 9リソース横断 |
|
||||
| 個人ダッシュボード(7項目) | P0 | M4(骨組み) | M13 | 全項目完成はM13 |
|
||||
| プロジェクトダッシュボード(9項目) | P0 | M4(骨組み) | M13 | 全項目完成はM13 |
|
||||
| バックアップ(DB+uploads ZIP・一覧・ダウンロード・Migration状態確認) | P1 | M14 | M14 | 管理者のみ |
|
||||
|
||||
### Repository カバレッジ(13クラス)
|
||||
|
||||
| Repository | 実装MS | Unit Test MS |
|
||||
|-----------|--------|-------------|
|
||||
| UserRepository | M3 | M3 |
|
||||
| ProjectRepository | M4 | M4 |
|
||||
| ProjectMemberRepository | M4 | M4 |
|
||||
| NotificationRepository | M5 | M5 |
|
||||
| ActivityLogRepository | M5 | M5 |
|
||||
| BoardRepository | M6 | M6 |
|
||||
| ProjectNoteRepository | M7 | M7 |
|
||||
| ChatRepository | M8 | M8 |
|
||||
| TodoRepository | M9 | M9 |
|
||||
| FileRepository | M10 | M10 |
|
||||
| CalendarRepository | M11 | M11 |
|
||||
| MilestoneRepository | M11 | M11 |
|
||||
| MeetingRepository | M12 | M12 |
|
||||
|
||||
### Service カバレッジ(12クラス)
|
||||
|
||||
| Service | 実装MS | Unit Test MS |
|
||||
|---------|--------|-------------|
|
||||
| AuthService | M3 | M3 |
|
||||
| ProjectService | M4 | M4 |
|
||||
| NotificationService | M5 | M5 |
|
||||
| ActivityLogService | M5 | M5 |
|
||||
| BoardService | M6 | M6 |
|
||||
| NoteService | M7 | M7 |
|
||||
| ChatService | M8 | M8 |
|
||||
| TodoService | M9 | M9 |
|
||||
| FileStorageService | M10 | M10 |
|
||||
| ScheduleService | M11 | M11 |
|
||||
| (マイルストーン進捗計算) | M11 | M11 |
|
||||
| MeetingService | M12 | M12 |
|
||||
| (スケジュール重複判定) | M12 | M12 |
|
||||
| BackupService | M14 | M14 |
|
||||
|
||||
### E2E Test カバレッジ(12シナリオ)
|
||||
|
||||
| E2Eシナリオ | 実装MS |
|
||||
|------------|--------|
|
||||
| auth.spec.ts | M3 |
|
||||
| project-management.spec.ts | M4 |
|
||||
| board.spec.ts | M6 |
|
||||
| markdown-notes.spec.ts | M7 |
|
||||
| chat-sse.spec.ts | M8 |
|
||||
| todo-kanban.spec.ts | M9 |
|
||||
| file-sharing.spec.ts | M10 |
|
||||
| calendar.spec.ts | M11 |
|
||||
| meetings.spec.ts | M12 |
|
||||
| notifications.spec.ts | M5(通知一覧)/ 各MS(イベント発生時) |
|
||||
| activity-log.spec.ts | M5(一覧)/ 各MS(記録時) |
|
||||
| backup.spec.ts | M14 |
|
||||
|
||||
### 統合テスト カバレッジ(3シナリオ)
|
||||
|
||||
| 統合テスト | 実装MS |
|
||||
|----------|--------|
|
||||
| auth-flow.test.ts | M3 |
|
||||
| project-member-permission.test.ts | M4 |
|
||||
| chat-sse-broadcast.test.ts | M8 |
|
||||
|
||||
---
|
||||
|
||||
## フェーズ対応表
|
||||
|
||||
PRDの開発順序(Phase 1〜5)とマイルストーンの対応。
|
||||
|
||||
| フェーズ | 内容 | 対象マイルストーン |
|
||||
|---------|------|------------------|
|
||||
| Phase 1: 基盤 | Next.js・Tailwind・SQLite・SQLラッパー・Migration・Repository基盤・認証・ユーザー管理・プロジェクト管理・メンバー管理 | M1・M2・M3・M4 |
|
||||
| Phase 2: プロジェクト内基本機能 | 通知・アクティビティログ・プロジェクトダッシュボード(骨組み)・掲示板・Markdownメモ | M5・M6・M7 |
|
||||
| Phase 3: リアルタイム・タスク管理 | SSE基盤・チャット・メンション・既読/未読・ToDo/Kanban | M8・M9 |
|
||||
| Phase 4: ファイル・カレンダー | ファイル共有・Lightbox・カレンダー・マイルストーン・デッドライン表示 | M10・M11 |
|
||||
| Phase 5: ミーティング・バックアップ | ミーティング作成・メンバー設定・スケジュール重複チェック・議事録・ToDo連携・メモ連携・バックアップ | M12・M14 |
|
||||
| (横断) | 検索・ダッシュボード完成 | M13 |
|
||||
| (全体) | 全体テスト完成・品質担保 | M15 |
|
||||
|
||||
---
|
||||
|
||||
## テスト要件サマリー
|
||||
|
||||
`docs/development-guidelines.md` の「テスト実装の必須条件」に準拠し、各マイルストーンでテスト実装を必須とする。
|
||||
|
||||
### Unit Test(Vitest)【必須】
|
||||
- **対象**: SQLラッパー・Migration・全13Repository・全12Service・権限チェック・バリデーション・スケジュール重複判定・通知作成ロジック・アクティビティログ作成ロジック・マイルストーン進捗計算
|
||||
- **合格基準**: `npm test` 全件成功・Repository/Service層カバレッジ80%以上・正常系/異常系網羅
|
||||
- **最終確認**: M15
|
||||
|
||||
### 統合テスト(Vitest)【必須】
|
||||
- **対象**: 認証フロー・プロジェクトメンバー権限・チャットSSE配信
|
||||
- **最終確認**: M15
|
||||
|
||||
### E2E Test(Playwright)【必須】
|
||||
- **対象**: 認証・プロジェクト管理・掲示板・チャット(SSE)・ToDo(Kanban)・ファイル共有(Lightbox)・Markdownメモ・カレンダー・ミーティング(予定重複警告)・通知・アクティビティログ・バックアップ(全12シナリオ)
|
||||
- **合格基準**: `npm run test:e2e` 全件成功・主要フロー100%
|
||||
- **最終確認**: M15
|
||||
524
docs/product-requirements.md
Normal file
524
docs/product-requirements.md
Normal file
@ -0,0 +1,524 @@
|
||||
# Product Requirements Document
|
||||
|
||||
## プロダクト概要
|
||||
|
||||
### 名前
|
||||
**シンプルグループウェア** - プロジェクト単位で情報共有・タスク管理を行えるチームコラボレーションツール
|
||||
|
||||
### プロダクトコンセプト
|
||||
- **プロジェクト中心の情報管理**: すべての主要機能(掲示板・チャット・ToDo・ファイル・メモ・カレンダー・ミーティング)がプロジェクトに紐づき、プロジェクトごとに独立して利用できる
|
||||
- **軽量で扱いやすい技術構成**: Next.js 15 + TypeScript + SQLite(better-sqlite3) で構築し、Prisma を使わず独自SQLラッパーとRepositoryクラスでDBアクセスを実装する。小規模チーム(プロジェクトあたり数十人)で運用できるシンプルさを追求する
|
||||
- **リアルタイム性と一元管理の両立**: SSEによるリアルタイムチャットを備えつつ、カレンダーでマイルストーン・デッドライン・ToDo・ミーティングを一画面に集約し、チームの進捗を可視化する
|
||||
|
||||
### プロダクトビジョン
|
||||
プロジェクトごとに独立した情報共有空間を提供し、チームが掲示板・チャット・タスク・ファイル・メモ・カレンダー・ミーティングを一つのアプリで完結できるグループウェアを実現する。
|
||||
軽量なSQLiteベースの構成により、小規模チームでも簡単に導入・運用できる。
|
||||
リアルタイムチャットとカレンダーによる一元管理で、情報散逸を防ぎ、チームの生産性を高める。
|
||||
|
||||
### 目的
|
||||
- ユーザーを管理できる
|
||||
- プロジェクトを作成・管理できる
|
||||
- プロジェクトごとにメンバーを管理できる
|
||||
- プロジェクトごとに掲示板を使える
|
||||
- プロジェクトごとにSSEチャットを使える
|
||||
- プロジェクトごとにKanban形式のToDoを使える
|
||||
- プロジェクトごとにファイル共有を使える
|
||||
- ファイルをLightboxで閲覧できる
|
||||
- プロジェクトごとにMarkdownメモを作成・編集・閲覧できる
|
||||
- プロジェクトごとにカレンダーを使える
|
||||
- カレンダーでマイルストーン、デッドライン、ToDo、ミーティングを表示できる
|
||||
- プロジェクトごとにミーティングを管理できる
|
||||
- ミーティング作成時に参加メンバーの予定重複を確認できる
|
||||
- アプリ内通知を使える
|
||||
- アクティビティログを記録できる
|
||||
- SQLiteのDBスキーマをSQL Migrationで更新できる
|
||||
- 管理者がバックアップを作成できる
|
||||
|
||||
## ターゲットユーザー
|
||||
|
||||
### 主要ペルソナ: 佐藤 健太(32歳、プロジェクトマネージャー)
|
||||
- 中小規模の開発チーム(5〜30名)で複数プロジェクトを並行管理している
|
||||
- プロジェクトごとにメンバー構成が変わり、情報共有手段を都度切り替えるのに負担を感じている
|
||||
- チャット・タスク管理・ファイル共有・ミーティング調整が別々のツールに分散しており、情報を行き来させるのに時間がかかっている
|
||||
- 各メンバーの予定やタスク期限を一画面で把握し、ミーティングの重複を自動検知したい
|
||||
- 軽量なツールを自社サーバー(またはローカル)で手軽に運用したい
|
||||
|
||||
### サブペルソナ: 山田 花子(27歳、フロントエンドエンジニア / プロジェクトメンバー)
|
||||
- 複数プロジェクトに所属し、それぞれのToDo期限やミーティング予定を見逃さずに把握したい
|
||||
- Markdownでメモや議事録を書くことに慣れており、プレビュー付きの編集環境を求めている
|
||||
- チャットでリアルタイムに相談しつつ、掲示板で非同期的に仕様や決定事項を残したい
|
||||
|
||||
## 成功指標(KPI)
|
||||
|
||||
### 主要KPI
|
||||
- **主要ユーザーフローの動作確認**: 認証・プロジェクト作成・掲示板・SSEチャット・Kanban ToDo・ファイル共有・Markdownメモ・カレンダー・ミーティング・通知・アクティビティログ・バックアップのすべてが正常に動作する(リリース時)
|
||||
- **Unit Test カバレッジ**: SQLラッパー・Migration・全Repository・全ServiceクラスのUnit Testが実装され、`npm test` で全件成功する(リリース時)
|
||||
- **E2E Test 合格率**: Playwrightによる主要ユーザーフローのE2E Testが実装され、`npm run test:e2e` で全件成功する(リリース時)
|
||||
|
||||
### 副次KPI
|
||||
- **リアルタイム性**: チャットメッセージ送信から他クライアントのSSE受信まで1秒以内(小規模同時接続前提)
|
||||
- **一覧表示の応答性**: チャット履歴・掲示板・ファイル一覧・Markdownメモ一覧はページネーションされ、1ページあたりの取得が1秒以内
|
||||
- **バックアップの可用性**: 管理者が1操作でSQLite DBファイルとuploadsディレクトリをZIP化したバックアップを作成・ダウンロードできる
|
||||
|
||||
## 機能要件
|
||||
|
||||
### コア機能(MVP)
|
||||
|
||||
#### 1. ユーザー管理
|
||||
|
||||
**ユーザーストーリー**:
|
||||
システム管理者として、ユーザーの登録・ロール割り当て・有効/無効管理を行いたい。それはシステムへのアクセスを適切に制御するためである。
|
||||
またユーザーとして、パスワードでログインし、自分のプロフィール・アイコン・表示名を編集したい。それは自分のアイデンティティをチーム内で正しく表現するためである。
|
||||
|
||||
**受け入れ基準**:
|
||||
- [ ] ユーザー登録ができる(名前・メールアドレス・パスワード)
|
||||
- [ ] パスワードログインができる
|
||||
- [ ] ログアウトができる
|
||||
- [ ] プロフィール編集(表示名・メールアドレス)ができる
|
||||
- [ ] アイコン画像を設定できる
|
||||
- [ ] アカウントを有効/無効にできる(無効アカウントはログイン不可)
|
||||
- [ ] ロール(System Admin / Project Admin / Member / Guest)を管理できる
|
||||
- [ ] 認証必須の画面で未ログイン時はログイン画面へリダイレクトされる
|
||||
- [ ] ログインしていないユーザーは保護された画面にアクセスできない
|
||||
|
||||
**優先度**: P0(必須)
|
||||
|
||||
---
|
||||
|
||||
#### 2. プロジェクト管理
|
||||
|
||||
**ユーザーストーリー**:
|
||||
プロジェクト管理者として、プロジェクトを作成し、メンバーを追加・削除し、プロジェクト内ロールを設定したい。それはプロジェクトごとに適切な権限でチームを運用するためである。
|
||||
またプロジェクト管理者として、プロジェクトのステータス(Active/On Hold/Completed/Archived)を管理し、不要になったプロジェクトをアーカイブ・削除したい。それはプロジェクトのライフサイクルを整理するためである。
|
||||
|
||||
**受け入れ基準**:
|
||||
- [ ] プロジェクトを作成できる(名前・説明文)
|
||||
- [ ] プロジェクト名・説明文を編集できる
|
||||
- [ ] プロジェクトのステータス(Active/On Hold/Completed/Archived)を変更できる
|
||||
- [ ] プロジェクトにメンバーを追加できる
|
||||
- [ ] プロジェクトからメンバーを削除できる
|
||||
- [ ] プロジェクト内ロールを設定できる
|
||||
- [ ] プロジェクトをアーカイブできる
|
||||
- [ ] プロジェクトを削除できる
|
||||
- [ ] プロジェクト参加者以外はプロジェクト情報にアクセスできない
|
||||
- [ ] プロジェクトダッシュボードに以下が表示される:
|
||||
- 最新チャット
|
||||
- 最新掲示板投稿
|
||||
- 最新Markdownメモ
|
||||
- 未完了ToDo
|
||||
- 期限が近いToDo
|
||||
- 次回ミーティング
|
||||
- 直近のマイルストーン
|
||||
- 最近アップロードされたファイル
|
||||
- 最近のアクティビティ
|
||||
|
||||
**優先度**: P0(必須)
|
||||
|
||||
---
|
||||
|
||||
#### 3. 掲示板
|
||||
|
||||
**ユーザーストーリー**:
|
||||
プロジェクトメンバーとして、プロジェクト単位で非リアルタイムの情報共有(お知らせ・仕様・議事録・質問・決定事項・トラブル・メモ)をスレッド形式で行いたい。それは重要な情報を後から振り返れる形で残すためである。
|
||||
|
||||
**受け入れ基準**:
|
||||
- [ ] スレッドを作成・編集・削除できる(Markdown本文)
|
||||
- [ ] スレッドにコメントを作成・編集・削除できる
|
||||
- [ ] スレッドに添付ファイルを付けられる
|
||||
- [ ] スレッドをピン留めできる
|
||||
- [ ] スレッドに重要マークを付けられる
|
||||
- [ ] カテゴリ(お知らせ/仕様/議事録/質問/決定事項/トラブル/メモ)で分類できる
|
||||
- [ ] 既読管理ができる
|
||||
- [ ] スレッドを検索できる
|
||||
- [ ] 論理削除されたスレッド・コメントは通常取得に含まれない
|
||||
|
||||
**優先度**: P0(必須)
|
||||
|
||||
---
|
||||
|
||||
#### 4. チャット(SSE)
|
||||
|
||||
**ユーザーストーリー**:
|
||||
プロジェクトメンバーとして、プロジェクト内でリアルタイムに短い会話をしたい。それは素早い相談ややり取りを円滑に行うためである。
|
||||
|
||||
**受け入れ基準**:
|
||||
- [ ] プロジェクト別のチャットが使える
|
||||
- [ ] メッセージを送信できる
|
||||
- [ ] SSEにより新規メッセージがリアルタイムに他クライアントへ配信される(別ブラウザ/別コンテキストで確認)
|
||||
- [ ] 接続切断時に自動再接続される
|
||||
- [ ] SSEイベントはプロジェクト単位で配信される
|
||||
- [ ] メッセージを編集・削除できる
|
||||
- [ ] メッセージに添付ファイルを付けられる
|
||||
- [ ] メンションができる
|
||||
- [ ] リアクションができる
|
||||
- [ ] 既読/未読が管理できる
|
||||
- [ ] チャット履歴を検索できる(ページネーション付き)
|
||||
- [ ] SSEイベント種別: `chat.message.created` / `chat.message.updated` / `chat.message.deleted` / `todo.updated` / `file.uploaded` / `meeting.created` / `note.updated` / `notification.created` が配信される
|
||||
|
||||
**優先度**: P0(必須)
|
||||
|
||||
---
|
||||
|
||||
#### 5. ToDo / Kanban
|
||||
|
||||
**ユーザーストーリー**:
|
||||
プロジェクトメンバーとして、プロジェクトごとのタスクをKanbanボード形式で管理したい。それはタスクの状態と担当を視覚的に把握するためである。
|
||||
|
||||
**受け入れ基準**:
|
||||
- [ ] Kanbanボードが表示される(標準カラム: Backlog/To Do/In Progress/Review/Done)
|
||||
- [ ] カラムを作成・編集・削除・並び替えできる
|
||||
- [ ] タスクを作成・編集・削除できる
|
||||
- [ ] タスクをドラッグ&ドロップで別カラムへ移動できる
|
||||
- [ ] タスクに担当者・期限・優先度・ラベルを設定できる
|
||||
- [ ] タスクにチェックリスト・コメント・添付ファイルを付けられる
|
||||
- [ ] タスクの完了状態を管理できる
|
||||
- [ ] 完了したToDoがDoneカラムに表示される
|
||||
- [ ] タスクをカレンダーに表示できる
|
||||
- [ ] タスクをマイルストーンと紐づけられる
|
||||
|
||||
**優先度**: P0(必須)
|
||||
|
||||
---
|
||||
|
||||
#### 6. ファイル共有
|
||||
|
||||
**ユーザーストーリー**:
|
||||
プロジェクトメンバーとして、プロジェクト内でファイルをアップロード・閲覧・共有したい。それは資料や画像をチーム内で簡単に扱うためである。
|
||||
|
||||
**受け入れ基準**:
|
||||
- [ ] ファイルをアップロードできる(ローカルファイルシステムに保存)
|
||||
- [ ] ファイル一覧が表示される(ページネーション付き)
|
||||
- [ ] フォルダ管理ができる
|
||||
- [ ] ファイル名変更・削除・ダウンロードができる
|
||||
- [ ] 画像ファイルをLightboxで閲覧できる
|
||||
- [ ] PDFファイルをプレビューできる
|
||||
- [ ] ファイルにコメントを付けられる
|
||||
- [ ] ファイルをToDo・掲示板投稿・ミーティング・Markdownメモと紐づけられる
|
||||
- [ ] ファイルアクセスにも権限チェックが行われる
|
||||
- [ ] アップロードファイルのMIMEチェックが行われる
|
||||
|
||||
**優先度**: P0(必須)
|
||||
|
||||
---
|
||||
|
||||
#### 7. Markdownメモ
|
||||
|
||||
**ユーザーストーリー**:
|
||||
プロジェクトメンバーとして、プロジェクトごとにMarkdown形式のメモを作成・編集・閲覧したい。それは仕様メモやノウハウを構造化して蓄積するためである。
|
||||
|
||||
**受け入れ基準**:
|
||||
- [ ] Markdownメモを作成・編集・削除できる
|
||||
- [ ] Markdownプレビューが表示される
|
||||
- [ ] タイトル・タグを設定できる
|
||||
- [ ] メモをピン留めできる
|
||||
- [ ] メモを検索できる
|
||||
- [ ] 作成者・最終更新者・更新日時が表示される
|
||||
- [ ] ファイル添付ができる
|
||||
- [ ] 関連ToDo・関連ミーティングを設定できる
|
||||
- [ ] 対応記法: 見出し・箇条書き・番号リスト・チェックリスト・コードブロック・テーブル・リンク・画像・引用
|
||||
- [ ] HTML直接入力は無効化され、表示時にサニタイズされる
|
||||
- [ ] 危険なURLスキームは除外される
|
||||
|
||||
**優先度**: P0(必須)
|
||||
|
||||
---
|
||||
|
||||
#### 8. カレンダー
|
||||
|
||||
**ユーザーストーリー**:
|
||||
プロジェクトメンバーとして、プロジェクト内の予定・マイルストーン・ToDo期限・ミーティングをカレンダー上で確認したい。それはチームのスケジュールを一画面で把握するためである。
|
||||
|
||||
**受け入れ基準**:
|
||||
- [ ] 月表示・週表示・日表示・リスト表示ができる
|
||||
- [ ] マイルストーン・デッドライン・ToDo開始日・ToDo期限・ミーティング・任意イベントが表示される
|
||||
- [ ] カレンダーイベントを作成・編集・削除できる
|
||||
- [ ] イベント種別(Meeting/Deadline/Milestone/Todo/Reminder/Custom)を設定できる
|
||||
- [ ] メンバー別フィルターができる
|
||||
- [ ] 種別フィルターができる
|
||||
|
||||
**優先度**: P0(必須)
|
||||
|
||||
---
|
||||
|
||||
#### 9. マイルストーン管理
|
||||
|
||||
**ユーザーストーリー**:
|
||||
プロジェクト管理者として、プロジェクトの重要な節目(マイルストーン)を管理したい。それは進捗の目標を明確にし、完了率を可視化するためである。
|
||||
|
||||
**受け入れ基準**:
|
||||
- [ ] マイルストーンを作成・編集・削除できる
|
||||
- [ ] 期限・説明文を設定できる
|
||||
- [ ] 関連ToDoを紐づけられる
|
||||
- [ ] 関連ToDoの完了率から進捗率が自動計算される
|
||||
- [ ] 完了状態を管理できる
|
||||
- [ ] カレンダーに表示される
|
||||
|
||||
**優先度**: P1(重要)
|
||||
|
||||
---
|
||||
|
||||
#### 10. ミーティング管理
|
||||
|
||||
**ユーザーストーリー**:
|
||||
プロジェクト管理者として、プロジェクトメンバーとのミーティングを設定し、参加者の予定重複を確認したい。それはスケジュールの競合を事前に防ぐためである。
|
||||
|
||||
**受け入れ基準**:
|
||||
- [ ] ミーティングを作成・編集・削除できる
|
||||
- [ ] タイトル・説明・開始日時・終了日時・参加メンバー・場所・ミーティングURLを設定できる
|
||||
- [ ] アジェンダ・議事録をMarkdownで作成できる
|
||||
- [ ] 関連ToDo・関連ファイル・関連掲示板投稿・関連Markdownメモを設定できる
|
||||
- [ ] カレンダーに表示される
|
||||
- [ ] ミーティング作成時に参加メンバーの予定重複をチェックし、同じ時間帯に他のミーティング・カレンダーイベント・期限の近い重要タスクがある場合は警告する
|
||||
- [ ] 参加メンバーの予定重複が画面上で警告される
|
||||
|
||||
**優先度**: P0(必須)
|
||||
|
||||
---
|
||||
|
||||
#### 11. 通知
|
||||
|
||||
**ユーザーストーリー**:
|
||||
ユーザーとして、自分に関係する重要な更新(メンション・ToDo割り当て・期限前・ミーティング招待・コメント・プロジェクト追加・ファイル共有・メモ更新)を見逃さないようにしたい。それは必要な対応を迅速に行うためである。
|
||||
|
||||
**受け入れ基準**:
|
||||
- [ ] アプリ内通知が表示される
|
||||
- [ ] 未読通知一覧が表示される
|
||||
- [ ] 通知を既読化できる
|
||||
- [ ] 以下のイベントで通知が作成される:
|
||||
- 自分がメンションされた
|
||||
- 自分にToDoが割り当てられた
|
||||
- ToDoの期限が近い
|
||||
- ミーティングに招待された
|
||||
- 掲示板にコメントが付いた
|
||||
- プロジェクトに追加された
|
||||
- ファイルが共有された
|
||||
- Markdownメモが更新された
|
||||
- [ ] 通知が正しいユーザーに作成される
|
||||
|
||||
**優先度**: P0(必須)
|
||||
|
||||
---
|
||||
|
||||
#### 12. アクティビティログ
|
||||
|
||||
**ユーザーストーリー**:
|
||||
プロジェクトメンバーとして、プロジェクト内の変更履歴を時系列で確認したい。それは誰がいつ何を変更したかを追跡するためである。
|
||||
|
||||
**受け入れ基準**:
|
||||
- [ ] 以下の操作がアクティビティログに記録される:
|
||||
- ToDo作成・更新・完了
|
||||
- ファイルアップロード
|
||||
- 掲示板投稿
|
||||
- コメント追加
|
||||
- Markdownメモ作成・更新
|
||||
- ミーティング作成
|
||||
- メンバー追加
|
||||
- マイルストーン更新
|
||||
- [ ] アクティビティログがプロジェクト単位で時系列表示される
|
||||
- [ ] 管理者操作もアクティビティログに記録される
|
||||
|
||||
**優先度**: P1(重要)
|
||||
|
||||
---
|
||||
|
||||
#### 13. 検索
|
||||
|
||||
**ユーザーストーリー**:
|
||||
プロジェクトメンバーとして、プロジェクト内の情報(掲示板・チャット・ToDo・ファイル・カレンダーイベント・ミーティング・議事録・マイルストーン・Markdownメモ)を横断検索したい。それは目的の情報にすばやくたどり着くためである。
|
||||
|
||||
**受け入れ基準**:
|
||||
- [ ] 掲示板・チャット・ToDo・ファイル名・カレンダーイベント・ミーティング・議事録・マイルストーン・Markdownメモを検索できる
|
||||
- [ ] 検索条件(キーワード・投稿者・担当者・日付・種別・プロジェクト・タグ)で絞り込みできる
|
||||
|
||||
**優先度**: P1(重要)
|
||||
|
||||
---
|
||||
|
||||
#### 14. ダッシュボード
|
||||
|
||||
**ユーザーストーリー**:
|
||||
ユーザーとして、ログイン後に自分に関係する情報を一画面で確認したい。それは今日やるべきことと近日の予定を把握するためである。
|
||||
|
||||
**受け入れ基準**:
|
||||
- [ ] 個人ダッシュボードに以下が表示される:
|
||||
- 自分の参加プロジェクト
|
||||
- 自分の未完了ToDo
|
||||
- 今日の予定
|
||||
- 近日中のミーティング
|
||||
- 未読通知
|
||||
- 期限切れタスク
|
||||
- 最近のアクティビティ
|
||||
- [ ] プロジェクトダッシュボードに以下が表示される:
|
||||
- プロジェクト概要
|
||||
- 進行中ToDo
|
||||
- 期限が近いToDo
|
||||
- 最新チャット
|
||||
- 最新掲示板
|
||||
- 最新Markdownメモ
|
||||
- 最近のファイル
|
||||
- 次回ミーティング
|
||||
- マイルストーン進捗
|
||||
|
||||
**優先度**: P0(必須)
|
||||
|
||||
---
|
||||
|
||||
#### 15. バックアップ
|
||||
|
||||
**ユーザーストーリー**:
|
||||
システム管理者として、SQLite DBファイルとアップロードファイルをバックアップしたい。それはデータ喪失に備えるためである。
|
||||
|
||||
**受け入れ基準**:
|
||||
- [ ] 管理者用バックアップ画面が使える
|
||||
- [ ] SQLite DBファイルのバックアップを作成できる
|
||||
- [ ] uploadsディレクトリのバックアップを作成できる
|
||||
- [ ] DBとuploadsをZIP化できる
|
||||
- [ ] バックアップファイル一覧が表示される
|
||||
- [ ] バックアップファイルをダウンロードできる
|
||||
|
||||
**優先度**: P1(重要)
|
||||
|
||||
---
|
||||
|
||||
#### 16. DB基盤(SQLラッパー・Migration・Repository)
|
||||
|
||||
**ユーザーストーリー**:
|
||||
開発者として、SQLiteへのアクセスを共通SQLラッパーで行い、SQLファイルベースのMigrationでスキーマを管理したい。それはDBアクセスを一貫させ、スキーマ変更を追跡可能にするためである。
|
||||
|
||||
**受け入れ基準**:
|
||||
- [ ] 共通SQLラッパー(SELECT複数行/SELECT単一行/INSERT・UPDATE・DELETE/トランザクション/初期設定/接続管理/エラー処理)が実装される
|
||||
- [ ] 各Repositoryは直接SQLiteライブラリを触らず、共通SQLラッパーを通してSQLを実行する
|
||||
- [ ] Migrationファイルがファイル名順に実行される
|
||||
- [ ] 実行済みMigrationは再実行されない
|
||||
- [ ] 実行済み履歴は `schema_migrations` テーブルに保存される
|
||||
- [ ] 1ファイルごとにトランザクションが張られ、失敗時はロールバックされる
|
||||
- [ ] 管理者がMigration状態を確認できる
|
||||
- [ ] SQLはパラメータバインドで実行される(SQLインジェクション対策)
|
||||
|
||||
**優先度**: P0(必須)
|
||||
|
||||
---
|
||||
|
||||
### 画面構成
|
||||
|
||||
#### 共通画面
|
||||
- ログイン画面
|
||||
- ダッシュボード
|
||||
- 通知一覧
|
||||
- ユーザープロフィール
|
||||
- 管理者設定
|
||||
- バックアップ管理
|
||||
|
||||
#### プロジェクト内画面
|
||||
- プロジェクト概要
|
||||
- 掲示板
|
||||
- チャット
|
||||
- ToDo / Kanban
|
||||
- ファイル
|
||||
- Markdownメモ
|
||||
- カレンダー
|
||||
- マイルストーン
|
||||
- ミーティング
|
||||
- メンバー
|
||||
- アクティビティログ
|
||||
- 設定
|
||||
|
||||
### 今後の機能(Post-MVP)
|
||||
|
||||
#### 外部連携・拡張
|
||||
- 外部カレンダー(Google Calendar等)との同期
|
||||
- メール通知・Webhook通知
|
||||
- モバイル専用UIの最適化
|
||||
|
||||
**優先度**: P2(今後検討)
|
||||
|
||||
## 非機能要件
|
||||
|
||||
### パフォーマンス
|
||||
- 1プロジェクトあたり数十人規模を想定する
|
||||
- チャットSSEは小規模同時接続を前提とする
|
||||
- ファイル一覧・チャット履歴・掲示板・Markdownメモはページネーションを行う
|
||||
- 一覧取得では必要な件数だけ取得する
|
||||
|
||||
### ユーザビリティ
|
||||
- ログイン後、ユーザーはダッシュボードで自分に関係する情報を一画面で確認できる
|
||||
- プロジェクト内の主要機能はサイドメニューから1クリックで遷移できる
|
||||
- Kanbanタスクはドラッグ&ドロップで直感的に操作できる
|
||||
|
||||
### 信頼性
|
||||
- DB更新は1ファイルごとにトランザクションを張り、失敗時はロールバックする
|
||||
- 管理者がSQLite DBファイルとuploadsディレクトリのバックアップを作成できる
|
||||
- SQLite DBファイル・uploadsディレクトリは永続化される
|
||||
|
||||
### セキュリティ
|
||||
- 認証必須(未ログインは保護された画面にアクセス不可)
|
||||
- プロジェクト参加者以外はプロジェクト情報にアクセス不可
|
||||
- ファイルアクセスにも権限チェックを行う
|
||||
- SQLはパラメータバインドで実行する
|
||||
- Markdown表示時はHTMLを無効化しサニタイズする
|
||||
- 危険なURLスキームを除外する
|
||||
- アップロードファイルのMIMEチェックを行う
|
||||
- 管理者操作をアクティビティログに記録する
|
||||
|
||||
### スケーラビリティ
|
||||
- Next.jsのEdge Runtimeは使用せず、API Route・Server Actions・DBアクセスはすべてNode.js Runtimeで実行する(SQLite直接扱いのため)
|
||||
- SQLiteはWALモード・外部キー制約ONで運用する
|
||||
|
||||
### 運用・保守
|
||||
- `.env` で設定管理できる
|
||||
- SQLite DBファイルを永続化する
|
||||
- uploadsディレクトリを永続化する
|
||||
- 管理者がDB Migration状態を確認できる
|
||||
- 管理者がバックアップを作成できる
|
||||
|
||||
## テスト要件
|
||||
|
||||
### Unit Test(Vitest)
|
||||
以下を対象とする:
|
||||
- SQLラッパー
|
||||
- Migration実行
|
||||
- 全Repository(User/Project/ProjectMember/Board/Chat/Todo/File/Calendar/Meeting/ProjectNote/Notification/ActivityLog)
|
||||
- 全Service(Auth/Project/Chat/Meeting/Schedule/FileStorage/Backup)
|
||||
- 権限チェック・バリデーション・スケジュール重複判定・通知作成ロジック・アクティビティログ作成ロジック
|
||||
|
||||
確認内容:
|
||||
- 正常にデータを作成・取得・更新・削除できる
|
||||
- 論理削除されたデータが通常取得に含まれない
|
||||
- プロジェクト単位でデータが分離される
|
||||
- 権限がないユーザーは操作できない
|
||||
- 必須項目不足時にエラーになる
|
||||
- Migrationがファイル名順に実行され、実行済みは再実行されない
|
||||
- 予定重複を検出できる
|
||||
- 通知が正しいユーザーに作成される
|
||||
- アクティビティログが正しく記録される
|
||||
|
||||
`npm test` でUnit Testが実行できること。
|
||||
|
||||
### E2E Test(Playwright)
|
||||
主要ユーザーフローを実際のブラウザ操作で検証する:
|
||||
- 認証(ログイン・ログアウト・未ログインの保護)
|
||||
- プロジェクト管理(作成・編集・メンバー追加/削除・アーカイブ)
|
||||
- 掲示板(スレッド作成・編集・コメント・検索)
|
||||
- チャット(送信・SSEリアルタイム受信・編集・削除)
|
||||
- ToDo/Kanban(カラム作成・タスク作成・編集・移動・担当者/期限設定・完了)
|
||||
- ファイル共有(アップロード・一覧・Lightbox閲覧・PDFプレビュー・削除)
|
||||
- Markdownメモ(作成・編集・プレビュー・ピン留め・検索・削除)
|
||||
- カレンダー(ToDo期限・マイルストーン・ミーティング表示・イベント作成/編集)
|
||||
- ミーティング(作成・参加メンバー設定・予定重複警告・アジェンダ/議事録・関連付け)
|
||||
- 通知(ToDo担当者・メンション・ミーティング参加者への通知・既読化)
|
||||
- アクティビティログ(ToDo作成・ファイルアップロード・メモ更新・ミーティング作成の記録)
|
||||
- バックアップ(作成・一覧表示・ダウンロード)
|
||||
|
||||
`npm run test:e2e` でPlaywright E2E Testが実行できること。
|
||||
Unit TestとE2E Testがすべて成功すること。
|
||||
|
||||
## スコープ外
|
||||
|
||||
明示的にスコープ外とする項目:
|
||||
- Prisma等のORMは使用しない(独自SQLラッパー + Repositoryクラスで実装)
|
||||
- Next.js Edge Runtimeは使用しない(Node.js Runtimeのみ)
|
||||
- 外部カレンダー(Google Calendar等)との同期(Post-MVP)
|
||||
- メール通知・Webhook通知(Post-MVP)
|
||||
- モバイル専用UIの最適化(Post-MVP)
|
||||
- 外部認証プロバイダ(OAuth/SSO)は使用しない(独自ログイン方式)
|
||||
- クラウドストレージへのファイル保存は行わない(ローカルファイルシステムのみ)
|
||||
506
docs/repository-structure.md
Normal file
506
docs/repository-structure.md
Normal file
@ -0,0 +1,506 @@
|
||||
# リポジトリ構成定義書 (Repository Structure Document)
|
||||
|
||||
> 本書は `docs/architecture.md` で定義したレイヤードアーキテクチャを具体的なディレクトリ構成に落とし込んだものである。Next.js 15 App Router の規約に従い、`app/`・`lib/`・`repositories/`・`services/`・`components/` をルート直下に配置する。
|
||||
|
||||
## プロジェクト構成
|
||||
|
||||
```
|
||||
repo/
|
||||
├── app/ # UI層: Next.js App Router
|
||||
│ ├── api/ # Route Handlers (REST/SSEエンドポイント)
|
||||
│ ├── login/ # ログイン画面
|
||||
│ ├── dashboard/ # 個人ダッシュボード
|
||||
│ ├── projects/[projectId]/ # プロジェクト内画面群
|
||||
│ ├── profile/ # ユーザープロフィール
|
||||
│ ├── admin/ # 管理者画面(バックアップ等)
|
||||
│ ├── layout.tsx # ルートレイアウト
|
||||
│ └── globals.css # Tailwind エントリ
|
||||
├── lib/ # Data層 + 共通基盤
|
||||
│ ├── db/ # SQLite接続・Migration
|
||||
│ ├── sse/ # SSE配信基盤
|
||||
│ ├── auth/ # 認証・セッションヘルパ
|
||||
│ ├── types/ # Entity型定義
|
||||
│ └── validators/ # 入力バリデーション
|
||||
├── repositories/ # Repository層
|
||||
├── services/ # Service層
|
||||
├── components/ # Reactコンポーネント
|
||||
│ ├── layout/
|
||||
│ ├── project/
|
||||
│ ├── board/
|
||||
│ ├── chat/
|
||||
│ ├── todo/
|
||||
│ ├── files/
|
||||
│ ├── calendar/
|
||||
│ ├── meetings/
|
||||
│ ├── notes/
|
||||
│ └── notifications/
|
||||
├── tests/ # テストコード
|
||||
│ ├── unit/
|
||||
│ ├── integration/
|
||||
│ └── e2e/
|
||||
├── data/ # 永続化データ(git管理外)
|
||||
│ ├── app.db
|
||||
│ └── uploads/
|
||||
├── backups/ # バックアップZIP(git管理外)
|
||||
├── docs/ # プロジェクトドキュメント
|
||||
├── .steering/ # ワーク単位のステアリングファイル
|
||||
├── .opencode/ # opencode設定
|
||||
├── public/ # 静的アセット
|
||||
└── 設定ファイル群(package.json, tsconfig.json, next.config 等)
|
||||
```
|
||||
|
||||
## ディレクトリ詳細
|
||||
|
||||
### app/ (UI層)
|
||||
|
||||
**役割**: Next.js App Router。画面表示・入力受付・認証・認可・Route Handler/SSEエンドポイント。
|
||||
|
||||
**配置ファイル**:
|
||||
- `page.tsx`: 画面コンポーネント(Server Components 中心)
|
||||
- `route.ts`: Route Handler(REST API)
|
||||
- `layout.tsx`: レイアウト
|
||||
- `loading.tsx` / `error.tsx`: ローディング・エラー状態
|
||||
|
||||
**命名規則**:
|
||||
- ディレクトリはNext.js規約(`[projectId]`等の動的セグメント含む)
|
||||
- 画面ディレクトリは kebab-case(`projects/[projectId]/board/`)
|
||||
|
||||
**依存**:
|
||||
- 依存可能: `services/`, `components/`, `lib/`
|
||||
- 依存禁止: `repositories/`, `lib/db/` への直接アクセス(Service経由のみ)
|
||||
|
||||
**構成例**:
|
||||
```
|
||||
app/
|
||||
├── api/
|
||||
│ ├── auth/
|
||||
│ │ ├── login/route.ts
|
||||
│ │ ├── logout/route.ts
|
||||
│ │ └── me/route.ts
|
||||
│ ├── projects/
|
||||
│ │ ├── route.ts # 一覧・作成
|
||||
│ │ └── [projectId]/
|
||||
│ │ ├── route.ts # 詳細・編集・削除
|
||||
│ │ ├── members/route.ts
|
||||
│ │ ├── board/
|
||||
│ │ ├── chat/
|
||||
│ │ │ ├── messages/route.ts
|
||||
│ │ │ └── stream/route.ts # SSEエンドポイント
|
||||
│ │ ├── todos/
|
||||
│ │ ├── files/
|
||||
│ │ ├── notes/
|
||||
│ │ ├── calendar/
|
||||
│ │ ├── milestones/
|
||||
│ │ └── meetings/
|
||||
│ ├── files/[fileId]/download/route.ts
|
||||
│ ├── notifications/route.ts
|
||||
│ └── admin/
|
||||
│ ├── backups/route.ts
|
||||
│ └── migrations/route.ts
|
||||
├── login/page.tsx
|
||||
├── dashboard/page.tsx
|
||||
├── projects/[projectId]/
|
||||
│ ├── page.tsx # プロジェクト概要/ダッシュボード
|
||||
│ ├── board/page.tsx
|
||||
│ ├── chat/page.tsx
|
||||
│ ├── todos/page.tsx
|
||||
│ ├── files/page.tsx
|
||||
│ ├── notes/page.tsx
|
||||
│ ├── calendar/page.tsx
|
||||
│ ├── milestones/page.tsx
|
||||
│ ├── meetings/page.tsx
|
||||
│ ├── members/page.tsx
|
||||
│ ├── activity/page.tsx
|
||||
│ └── settings/page.tsx
|
||||
├── profile/page.tsx
|
||||
└── admin/backups/page.tsx
|
||||
```
|
||||
|
||||
**各 Route Handler の先頭に `export const runtime = 'nodejs'` を明示する**(Edge Runtime使用禁止)。
|
||||
|
||||
### lib/ (Data層 + 共通基盤)
|
||||
|
||||
#### lib/db/
|
||||
|
||||
**役割**: SQLite接続の共通管理・SQL実行・Migration。
|
||||
|
||||
**配置ファイル**:
|
||||
- `sqlite.ts`: `SqliteDatabase` クラス・`getDb()` シングルトン
|
||||
- `migrator.ts`: `Migrator` クラス
|
||||
- `migrations/*.sql`: Migrationファイル(ファイル名順実行)
|
||||
|
||||
**命名規則**: Migrationファイルは `001_initial.sql` 形式(3桁連番 + 説明)
|
||||
|
||||
**依存**: better-sqlite3。Repository層からのみ利用される。
|
||||
|
||||
#### lib/sse/
|
||||
|
||||
**役割**: プロジェクト単位のSSEクライアント管理・イベント配信。
|
||||
|
||||
**配置ファイル**:
|
||||
- `hub.ts`: `SseHub` クラス(addClient/removeClient/broadcast)
|
||||
|
||||
**依存**: なし(Service層から呼び出される)。
|
||||
|
||||
#### lib/auth/
|
||||
|
||||
**役割**: セッション管理・認証ヘルパ・現在ユーザー取得。
|
||||
|
||||
**配置ファイル**:
|
||||
- `session.ts`: セッション読み書き
|
||||
- `getCurrentUser.ts`: リクエストから現在ユーザー解決
|
||||
|
||||
#### lib/types/
|
||||
|
||||
**役割**: Entity型定義・共有型。`functional-design.md` のデータモデルに対応。
|
||||
|
||||
**配置ファイル**: `User.ts`, `Project.ts`, `BoardThread.ts`, `ChatMessage.ts`, `TodoItem.ts`, `FileAsset.ts`, `ProjectNote.ts`, `Milestone.ts`, `CalendarEvent.ts`, `Meeting.ts`, `Notification.ts`, `ActivityLog.ts` 等
|
||||
|
||||
**命名規則**: PascalCase(Entity名)
|
||||
|
||||
#### lib/validators/
|
||||
|
||||
**役割**: 入力バリデーション(必須・長さ・形式)。Service層から呼び出される。
|
||||
|
||||
**配置ファイル**: `projectValidator.ts`, `todoValidator.ts`, `meetingValidator.ts` 等
|
||||
|
||||
**命名規則**: camelCase + `Validator` 接尾
|
||||
|
||||
### repositories/ (Repository層)
|
||||
|
||||
**役割**: SQLの保持・パラメータバインド実行・論理削除フィルタ(`deleted_at IS NULL`)・プロジェクト分離の担保。直接SQLiteライブラリを触らず `lib/db/sqlite.ts` 経由。
|
||||
|
||||
**配置ファイル**: テーブルごとに1クラス。
|
||||
|
||||
```
|
||||
repositories/
|
||||
├── UserRepository.ts
|
||||
├── ProjectRepository.ts
|
||||
├── ProjectMemberRepository.ts
|
||||
├── BoardRepository.ts
|
||||
├── ChatRepository.ts
|
||||
├── TodoRepository.ts
|
||||
├── FileRepository.ts
|
||||
├── CalendarRepository.ts
|
||||
├── MeetingRepository.ts
|
||||
├── ProjectNoteRepository.ts
|
||||
├── NotificationRepository.ts
|
||||
├── ActivityLogRepository.ts
|
||||
└── MilestoneRepository.ts
|
||||
```
|
||||
|
||||
**命名規則**: PascalCase + `Repository` 接尾
|
||||
|
||||
**依存**:
|
||||
- 依存可能: `lib/db/sqlite.ts`, `lib/types/`
|
||||
- 依存禁止: `services/`, `app/`, `lib/sse/`(業務ロジック・配信を持たない)
|
||||
|
||||
### services/ (Service層)
|
||||
|
||||
**役割**: 業務ロジック・権限チェック・トランザクション境界・副作用(通知生成・アクティビティログ記録・SSE配信)。
|
||||
|
||||
**配置ファイル**:
|
||||
```
|
||||
services/
|
||||
├── AuthService.ts
|
||||
├── ProjectService.ts
|
||||
├── ChatService.ts
|
||||
├── MeetingService.ts
|
||||
├── ScheduleService.ts
|
||||
├── FileStorageService.ts
|
||||
├── BackupService.ts
|
||||
├── TodoService.ts
|
||||
├── BoardService.ts
|
||||
├── NoteService.ts
|
||||
├── NotificationService.ts
|
||||
└── ActivityLogService.ts
|
||||
```
|
||||
|
||||
**命名規則**: PascalCase + `Service` 接尾
|
||||
|
||||
**依存**:
|
||||
- 依存可能: `repositories/`, `lib/sse/`, `lib/validators/`, `lib/types/`, `lib/db/`(トランザクションのため)
|
||||
- 依存禁止: `app/`(UI層への依存)
|
||||
|
||||
### components/ (Reactコンポーネント)
|
||||
|
||||
**役割**: 再利用可能なUIコンポーネント。機能領域ごとに分割。
|
||||
|
||||
**配置ファイル**: 機能ディレクトリ配下にコンポーネント。
|
||||
```
|
||||
components/
|
||||
├── layout/ # Header, Sidebar, ProjectNav
|
||||
├── project/ # ProjectCard, DashboardWidget
|
||||
├── board/ # ThreadList, ThreadForm, CommentList
|
||||
├── chat/ # ChatWindow, MessageInput, MessageList
|
||||
├── todo/ # KanbanBoard, KanbanColumn, TodoCard
|
||||
├── files/ # FileList, Uploader, Lightbox
|
||||
├── calendar/ # CalendarView, EventBadge
|
||||
├── meetings/ # MeetingForm, ConflictWarning
|
||||
├── notes/ # NoteEditor, MarkdownPreview
|
||||
└── notifications/ # NotificationList, NotificationBadge
|
||||
```
|
||||
|
||||
**命名規則**: コンポーネントファイルは PascalCase(`KanbanBoard.tsx`)
|
||||
|
||||
**依存**: `app/` から利用される。`services/` 型・`lib/types/` を参照可能。直接 `repositories/` は触らない。
|
||||
|
||||
### tests/ (テストディレクトリ)
|
||||
|
||||
#### tests/unit/
|
||||
|
||||
**役割**: Unit Test(Vitest)。本番コードと同じ構造をミラーする。
|
||||
|
||||
**構成**:
|
||||
```
|
||||
tests/unit/
|
||||
├── lib/db/sqlite.test.ts
|
||||
├── lib/db/migrator.test.ts
|
||||
├── lib/sse/hub.test.ts
|
||||
├── repositories/UserRepository.test.ts
|
||||
├── repositories/ProjectRepository.test.ts
|
||||
├── ...
|
||||
└── services/ChatService.test.ts
|
||||
```
|
||||
|
||||
**命名規則**: `[対象ファイル].test.ts`(対象と同名 + `.test`)
|
||||
|
||||
#### tests/integration/
|
||||
|
||||
**役割**: 統合テスト。実際のSQLite(一時ファイル)を使用。
|
||||
|
||||
**構成**:
|
||||
```
|
||||
tests/integration/
|
||||
├── auth-flow.test.ts
|
||||
├── project-member-permission.test.ts
|
||||
└── chat-sse-broadcast.test.ts
|
||||
```
|
||||
|
||||
**命名規則**: `[シナリオ].test.ts`(kebab-case)
|
||||
|
||||
#### tests/e2e/
|
||||
|
||||
**役割**: E2E Test(Playwright)。ユーザーシナリオごとに分割。
|
||||
|
||||
**構成**:
|
||||
```
|
||||
tests/e2e/
|
||||
├── auth.spec.ts
|
||||
├── project-management.spec.ts
|
||||
├── board.spec.ts
|
||||
├── chat-sse.spec.ts
|
||||
├── todo-kanban.spec.ts
|
||||
├── file-sharing.spec.ts
|
||||
├── markdown-notes.spec.ts
|
||||
├── calendar.spec.ts
|
||||
├── meetings.spec.ts
|
||||
├── notifications.spec.ts
|
||||
├── activity-log.spec.ts
|
||||
└── backup.spec.ts
|
||||
```
|
||||
|
||||
**命名規則**: `[領域].spec.ts`
|
||||
|
||||
### data/ ・ backups/ (永続化データ)
|
||||
|
||||
**役割**: SQLite DBファイル・アップロードファイル・バックアップZIPの永続化先。git管理外。
|
||||
|
||||
```
|
||||
data/
|
||||
├── app.db # SQLite DBファイル
|
||||
└── uploads/<projectId>/<uuid>.<ext>
|
||||
backups/
|
||||
└── backup-<timestamp>.zip
|
||||
```
|
||||
|
||||
### docs/ (ドキュメント)
|
||||
|
||||
**配置ファイル**:
|
||||
- `product-requirements.md`: PRD
|
||||
- `functional-design.md`: 機能設計書
|
||||
- `architecture.md`: アーキテクチャ設計書
|
||||
- `repository-structure.md`: 本書
|
||||
- `development-guidelines.md`: 開発ガイドライン
|
||||
- `glossary.md`: 用語集
|
||||
- `ideas/`: ブレインストーミング成果物
|
||||
|
||||
### .steering/ (ステアリングファイル)
|
||||
|
||||
**役割**: ワーク単位の要件・設計・タスクリスト。
|
||||
|
||||
**構成**:
|
||||
```
|
||||
.steering/[YYYYMMDD]-[task-name]/
|
||||
├── requirements.md
|
||||
├── design.md
|
||||
└── tasklist.md
|
||||
```
|
||||
|
||||
**命名規則**: `20250115-add-user-profile` 形式
|
||||
|
||||
### .opencode/ (opencode設定)
|
||||
|
||||
**役割**: opencode設定・カスタマイズ。
|
||||
|
||||
**構成**: `command/`, `skills/`, `agent/`
|
||||
|
||||
## ファイル配置ルール
|
||||
|
||||
### ソースファイル
|
||||
|
||||
| ファイル種別 | 配置先 | 命名規則 | 例 |
|
||||
|------------|--------|---------|-----|
|
||||
| Route Handler | `app/api/.../route.ts` | `route.ts`(固定) | `app/api/projects/route.ts` |
|
||||
| 画面 | `app/.../page.tsx` | `page.tsx`(固定) | `app/dashboard/page.tsx` |
|
||||
| Repository | `repositories/` | PascalCase + `Repository` | `UserRepository.ts` |
|
||||
| Service | `services/` | PascalCase + `Service` | `ChatService.ts` |
|
||||
| SQLラッパ | `lib/db/` | camelCase | `sqlite.ts` |
|
||||
| Migration | `lib/db/migrations/` | `NNN_description.sql` | `001_initial.sql` |
|
||||
| Entity型 | `lib/types/` | PascalCase | `TodoItem.ts` |
|
||||
| バリデータ | `lib/validators/` | camelCase + `Validator` | `todoValidator.ts` |
|
||||
| Reactコンポーネント | `components/<area>/` | PascalCase | `KanbanBoard.tsx` |
|
||||
| ユーティリティ関数 | `lib/` 配下の適切な領域 | camelCase + 動詞始まり | `formatDate.ts` |
|
||||
|
||||
### テストファイル
|
||||
|
||||
| テスト種別 | 配置先 | 命名規則 | 例 |
|
||||
|-----------|--------|---------|-----|
|
||||
| Unit test | `tests/unit/` | `[対象].test.ts` | `ChatService.test.ts` |
|
||||
| Integration test | `tests/integration/` | `[シナリオ].test.ts` | `chat-sse-broadcast.test.ts` |
|
||||
| E2E test | `tests/e2e/` | `[領域].spec.ts` | `todo-kanban.spec.ts` |
|
||||
|
||||
### 設定ファイル
|
||||
|
||||
| ファイル種別 | 配置先 | 命名規則 |
|
||||
|------------|--------|---------|
|
||||
| ツール設定 | プロジェクトルート | `[tool].config.{js,ts,mjs}`(`next.config.mjs`, `vitest.config.ts`, `playwright.config.ts`) |
|
||||
| 環境変数 | プロジェクトルート | `.env`, `.env.example` |
|
||||
| TypeScript設定 | プロジェクトルート | `tsconfig.json` |
|
||||
|
||||
## 命名規則
|
||||
|
||||
### ディレクトリ名
|
||||
- **レイヤディレクトリ**: 複数形・kebab-case(`repositories/`, `services/`, `components/`)
|
||||
- **機能ディレクトリ**: 単数形・kebab-case(`board/`, `chat/`, `meetings/`)※画面はNext.js規約に従う
|
||||
- **汎用ディレクトリ名禁止**: `utils/`, `misc/`, `common/` は役割が曖昧になるため避ける
|
||||
|
||||
### ファイル名
|
||||
- **クラスファイル**: PascalCase + 役割接尾(`UserRepository.ts`, `ChatService.ts`)
|
||||
- **関数ファイル**: camelCase + 動詞始まり(`formatDate.ts`, `validateEmail.ts`)
|
||||
- **型定義**: PascalCase(`TodoItem.ts`)
|
||||
- **Route Handler/画面**: Next.js固定名(`route.ts`, `page.tsx`, `layout.tsx`)
|
||||
|
||||
## 依存規則
|
||||
|
||||
### レイヤ間の依存
|
||||
|
||||
```
|
||||
app/ (UI層)
|
||||
↓ (OK)
|
||||
services/ (Service層)
|
||||
↓ (OK)
|
||||
repositories/ (Repository層)
|
||||
↓ (OK)
|
||||
lib/db/ (Data層)
|
||||
```
|
||||
|
||||
**禁止依存**:
|
||||
- `lib/db/` → `repositories/`/`services/`/`app/`(下位から上位へ ❌)
|
||||
- `repositories/` → `services/`/`app/`(❌)
|
||||
- `services/` → `app/`(❌)
|
||||
- `app/` → `repositories/`/`lib/db/` の直接アクセス(層飛ばし ❌、Service経由のみ)
|
||||
- `repositories/` → better-sqlite3 直接(❌、`lib/db/sqlite.ts` 経由のみ)
|
||||
|
||||
```typescript
|
||||
// ✅ 許容: UI → Service → Repository → Data
|
||||
import { projectService } from '@/services/ProjectService';
|
||||
// ProjectService内:
|
||||
import { projectRepository } from '@/repositories/ProjectRepository';
|
||||
// ProjectRepository内:
|
||||
import { getDb } from '@/lib/db/sqlite';
|
||||
|
||||
// ❌ 禁止: Route HandlerがRepositoryを直接呼ぶ
|
||||
import { projectRepository } from '@/repositories/ProjectRepository'; // app/api/... から ❌
|
||||
```
|
||||
|
||||
### モジュール間の依存
|
||||
|
||||
**循環依存禁止**: Service間で循環依存が生じる場合は、共有型を `lib/types/` に抽出するか、共通機能を別Service(例: `NotificationService`, `ActivityLogService`)に切り出す。
|
||||
|
||||
```typescript
|
||||
// ❌ 循環依存
|
||||
// services/TaskService.ts
|
||||
import { UserService } from './UserService';
|
||||
// services/UserService.ts
|
||||
import { TaskService } from './TaskService';
|
||||
|
||||
// ✅ 解決: 共通副作用を別Serviceに切り出し
|
||||
// services/NotificationService.ts ← 両方から利用
|
||||
// services/ActivityLogService.ts ← 両方から利用
|
||||
```
|
||||
|
||||
### パスエイリアス
|
||||
|
||||
`tsconfig.json` で `@/*` をプロジェクトルートにマッピングし、相対パスの深い `../../` を避ける。
|
||||
|
||||
```json
|
||||
{ "compilerOptions": { "paths": { "@/*": ["./*"] } } }
|
||||
```
|
||||
|
||||
## スケーリング戦略
|
||||
|
||||
### 機能追加時の配置方針
|
||||
|
||||
1. **小機能**: 既存ディレクトリに追加(例: 新しいRepository → `repositories/` に1ファイル)
|
||||
2. **中機能**: レイヤ内にサブディレクトリ作成(例: `services/meeting/` 配下に複数Service)
|
||||
3. **大機能**: 独立モジュール化を検討
|
||||
|
||||
### ファイルサイズ管理
|
||||
|
||||
- 1ファイル **300行以下** 推奨
|
||||
- 300-500行: リファクタリング検討
|
||||
- 500行超: 分割推奨(責務ごとに分割。例: `TaskService.ts` → `TaskService.ts` + `TaskValidationService.ts` + `TaskNotificationService.ts`)
|
||||
|
||||
### モジュール分離のタイミング
|
||||
|
||||
以下の兆候があれば機能単位のモジュール化を検討:
|
||||
- 1ディレクトリに10ファイル超
|
||||
- 関連機能がグループ化されている
|
||||
- 独立してテスト可能
|
||||
- 他機能への依存が少ない
|
||||
|
||||
## 除外設定
|
||||
|
||||
### .gitignore
|
||||
|
||||
除外対象:
|
||||
- `node_modules/`
|
||||
- `.next/`
|
||||
- `dist/`
|
||||
- `coverage/`
|
||||
- `data/`(DB・uploads・一時データ)
|
||||
- `backups/`
|
||||
- `.env`
|
||||
- `.steering/`(タスク管理の一時ファイル)
|
||||
- `*.log`
|
||||
- `test-results/`, `playwright-report/`
|
||||
- `.DS_Store`
|
||||
|
||||
### ツール除外
|
||||
|
||||
`.prettierignore`, `.eslintignore`:
|
||||
- `dist/`, `node_modules/`, `.next/`, `coverage/`, `data/`, `backups/`
|
||||
|
||||
## チェックリスト
|
||||
|
||||
- [x] 各ディレクトリの役割が明確に定義されている
|
||||
- [x] レイヤ構造がディレクトリに反映されている
|
||||
- [x] 命名規則が一貫している
|
||||
- [x] テストコードの配置方針が決まっている
|
||||
- [x] 依存規則が明確である
|
||||
- [x] 循環依存を避ける方針がある
|
||||
- [x] スケーリング戦略が考慮されている
|
||||
- [x] 共有コードの配置ルールが定義されている(`lib/types/`, `lib/validators/`)
|
||||
- [x] 設定ファイルの管理方法が決まっている
|
||||
- [x] ドキュメントの配置が明確である
|
||||
Reference in New Issue
Block a user