diff --git a/.vscode/mcp.json b/.vscode/mcp.json new file mode 100644 index 00000000..2a08a564 --- /dev/null +++ b/.vscode/mcp.json @@ -0,0 +1,9 @@ +{ + "servers": { + "my-mcp-server-dd44760e": { + "url": "https://api.githubcopilot.com/mcp/", + "type": "http" + } + }, + "inputs": [] +} \ No newline at end of file diff --git a/architecture.md b/architecture.md new file mode 100644 index 00000000..8adfeb14 --- /dev/null +++ b/architecture.md @@ -0,0 +1,523 @@ +# ポモドーロタイマーWebアプリケーション アーキテクチャ仕様書 + +## 1. 概要 + +本文書は、FlaskとHTML/CSS/JavaScriptを使用したポモドーロタイマーWebアプリケーションのアーキテクチャ設計について記載します。 + +### 1.1 目的 +- 25分の作業時間と5分の休憩時間を管理するポモドーロタイマー機能の提供 +- 日別の作業統計とセッション履歴の記録・表示 +- レスポンシブでモダンなUIの提供 +- 高いテスタビリティと保守性を持つアーキテクチャの実現 + +### 1.2 技術スタック +- **バックエンド**: Flask (Python 3.9+) +- **フロントエンド**: HTML5, CSS3, JavaScript (ES6+) +- **リアルタイム通信**: Flask-SocketIO (WebSocket) +- **データベース**: SQLite (開発用) / PostgreSQL (本番用) +- **セッション管理**: Flask-Session +- **テストフレームワーク**: pytest + +## 2. アーキテクチャ概要 + +### 2.1 アーキテクチャパターン +- **レイヤードアーキテクチャ**: プレゼンテーション層、ビジネスロジック層、データアクセス層の分離 +- **依存性注入**: テスタビリティと疎結合を実現 +- **リポジトリパターン**: データアクセス層の抽象化 +- **MVC パターン**: Model-View-Controller の分離 + +### 2.2 アーキテクチャ図 +``` +┌─────────────────────────────────────────────┐ +│ Frontend Layer │ +│ ┌─────────────┐ ┌─────────────────────────┐ │ +│ │ HTML │ │ JavaScript │ │ +│ │ CSS │ │ ┌─────────────────────┐ │ │ +│ │ │ │ │ Timer Controller │ │ │ +│ └─────────────┘ │ │ UI Controller │ │ │ +│ │ │ WebSocket Client │ │ │ +│ │ └─────────────────────┘ │ │ +│ └─────────────────────────┘ │ +└─────────────────────────────────────────────┘ + │ HTTP/WebSocket +┌─────────────────────────────────────────────┐ +│ Backend Layer │ +│ ┌─────────────────────────────────────────┐ │ +│ │ Flask Application │ │ +│ │ ┌─────────────┐ ┌─────────────────────┐ │ │ +│ │ │ Routes │ │ WebSocket │ │ │ +│ │ │ (API/Web) │ │ Handlers │ │ │ +│ │ └─────────────┘ └─────────────────────┘ │ │ +│ └─────────────────────────────────────────┘ │ +│ ┌─────────────────────────────────────────┐ │ +│ │ Service Layer │ │ +│ │ ┌─────────────┐ ┌─────────────────────┐ │ │ +│ │ │TimerService │ │ StatsService │ │ │ +│ │ │ │ │ │ │ │ +│ │ └─────────────┘ └─────────────────────┘ │ │ +│ └─────────────────────────────────────────┘ │ +│ ┌─────────────────────────────────────────┐ │ +│ │ Repository Layer │ │ +│ │ ┌─────────────┐ ┌─────────────────────┐ │ │ +│ │ │Session Repo │ │ Stats Repo │ │ │ +│ │ │ │ │ │ │ │ +│ │ └─────────────┘ └─────────────────────┘ │ │ +│ └─────────────────────────────────────────┘ │ +└─────────────────────────────────────────────┘ + │ +┌─────────────────────────────────────────────┐ +│ Data Layer │ +│ ┌─────────────────────────────────────────┐ │ +│ │ Database │ │ +│ │ ┌─────────────┐ ┌─────────────────────┐ │ │ +│ │ │pomodoro_ │ │ daily_stats │ │ │ +│ │ │sessions │ │ │ │ │ +│ │ └─────────────┘ └─────────────────────┘ │ │ +│ └─────────────────────────────────────────┘ │ +└─────────────────────────────────────────────┘ +``` + +## 3. プロジェクト構造 + +``` +pomodoro_app/ +├── app.py # Flask アプリケーションのエントリーポイント +├── config/ +│ ├── __init__.py +│ ├── base.py # 基本設定 +│ ├── development.py # 開発環境設定 +│ ├── testing.py # テスト環境設定 +│ └── production.py # 本番環境設定 +├── models/ +│ ├── __init__.py +│ ├── timer.py # タイマー関連のドメインモデル +│ └── session.py # セッション記録モデル +├── services/ +│ ├── __init__.py +│ ├── timer_service.py # タイマーのビジネスロジック +│ └── stats_service.py # 統計情報の処理 +├── repositories/ +│ ├── __init__.py +│ ├── session_repository.py # セッションデータアクセス +│ └── stats_repository.py # 統計データアクセス +├── routes/ +│ ├── __init__.py +│ ├── main.py # メインページのルート +│ └── api.py # REST API エンドポイント +├── websocket/ +│ ├── __init__.py +│ └── handlers.py # WebSocket イベントハンドラー +├── static/ +│ ├── css/ +│ │ ├── style.css # メインスタイルシート +│ │ └── components.css # コンポーネント別スタイル +│ ├── js/ +│ │ ├── timer.js # タイマー機能 +│ │ ├── ui.js # UI制御 +│ │ ├── websocket.js # WebSocket通信 +│ │ └── utils.js # ユーティリティ関数 +│ └── images/ +│ └── icons/ # アイコン類 +├── templates/ +│ ├── base.html # ベーステンプレート +│ └── index.html # メインページ +├── database/ +│ ├── __init__.py +│ ├── models.py # SQLAlchemy モデル定義 +│ └── migrations/ # データベースマイグレーション +├── utils/ +│ ├── __init__.py +│ ├── factories.py # テスト用ファクトリー +│ └── mocks.py # モッククラス +├── tests/ +│ ├── __init__.py +│ ├── conftest.py # pytest設定とフィクスチャ +│ ├── unit/ +│ │ ├── __init__.py +│ │ ├── test_timer_service.py # タイマーサービスのテスト +│ │ ├── test_models.py # モデルのテスト +│ │ └── test_stats_service.py # 統計サービスのテスト +│ ├── integration/ +│ │ ├── __init__.py +│ │ ├── test_api_endpoints.py # API統合テスト +│ │ └── test_websocket.py # WebSocket統合テスト +│ └── fixtures/ +│ └── test_data.py # テストデータ +├── requirements/ +│ ├── base.txt # 基本依存関係 +│ ├── development.txt # 開発用依存関係 +│ └── testing.txt # テスト用依存関係 +├── pytest.ini # pytest設定 +├── architecture.md # 本文書 +└── README.md # プロジェクト説明 +``` + +## 4. 主要コンポーネント設計 + +### 4.1 ドメインモデル (`models/timer.py`) + +```python +from dataclasses import dataclass +from enum import Enum +from datetime import datetime, timedelta +from typing import Optional + +class TimerState(Enum): + IDLE = "idle" + WORK = "work" + SHORT_BREAK = "short_break" + LONG_BREAK = "long_break" + PAUSED = "paused" + +class SessionType(Enum): + WORK = "work" + SHORT_BREAK = "short_break" + LONG_BREAK = "long_break" + +@dataclass +class PomodoroSession: + id: Optional[int] = None + duration_minutes: int = 25 + start_time: Optional[datetime] = None + end_time: Optional[datetime] = None + session_type: SessionType = SessionType.WORK + state: TimerState = TimerState.IDLE + completed: bool = False + paused_duration: timedelta = timedelta(0) +``` + +### 4.2 サービス層 (`services/timer_service.py`) + +```python +from abc import ABC, abstractmethod +from datetime import datetime, timedelta +from typing import Optional, Callable +from models.timer import PomodoroSession, TimerState, SessionType +from repositories.session_repository import SessionRepositoryInterface + +class TimeProvider(ABC): + @abstractmethod + def now(self) -> datetime: pass + + @abstractmethod + def sleep(self, seconds: float): pass + +class TimerService: + def __init__(self, + session_repository: SessionRepositoryInterface, + time_provider: TimeProvider, + event_emitter: Optional[Callable] = None): + self.session_repository = session_repository + self.time_provider = time_provider + self.event_emitter = event_emitter + self.current_session: Optional[PomodoroSession] = None + + def start_session(self, session_type: SessionType, duration_minutes: int) -> bool: + """新しいセッションを開始""" + + def pause_session(self) -> bool: + """現在のセッションを一時停止""" + + def resume_session(self) -> bool: + """一時停止中のセッションを再開""" + + def complete_session(self) -> bool: + """現在のセッションを完了""" + + def reset_session(self) -> bool: + """現在のセッションをリセット""" + + def get_remaining_time(self) -> Optional[timedelta]: + """残り時間を取得""" + + def get_current_session(self) -> Optional[PomodoroSession]: + """現在のセッションを取得""" +``` + +### 4.3 リポジトリ層 (`repositories/session_repository.py`) + +```python +from abc import ABC, abstractmethod +from typing import List, Optional +from datetime import date, datetime +from models.timer import PomodoroSession + +class SessionRepositoryInterface(ABC): + @abstractmethod + def save(self, session: PomodoroSession) -> int: pass + + @abstractmethod + def get_by_id(self, session_id: int) -> Optional[PomodoroSession]: pass + + @abstractmethod + def get_by_date_range(self, start_date: date, end_date: date) -> List[PomodoroSession]: pass + + @abstractmethod + def get_completed_sessions_by_date(self, target_date: date) -> List[PomodoroSession]: pass + + @abstractmethod + def update(self, session: PomodoroSession) -> bool: pass + + @abstractmethod + def delete(self, session_id: int) -> bool: pass + +class SQLiteSessionRepository(SessionRepositoryInterface): + """SQLite実装のセッションリポジトリ""" + +class InMemorySessionRepository(SessionRepositoryInterface): + """テスト用インメモリリポジトリ""" +``` + +### 4.4 API レイヤー (`routes/api.py`) + +```python +from flask import Blueprint, request, jsonify +from services.timer_service import TimerService +from models.timer import SessionType + +api_bp = Blueprint('api', __name__) + +@api_bp.route('/timer/start', methods=['POST']) +def start_timer(): + """タイマー開始 API""" + +@api_bp.route('/timer/pause', methods=['POST']) +def pause_timer(): + """タイマー一時停止 API""" + +@api_bp.route('/timer/resume', methods=['POST']) +def resume_timer(): + """タイマー再開 API""" + +@api_bp.route('/timer/reset', methods=['POST']) +def reset_timer(): + """タイマーリセット API""" + +@api_bp.route('/timer/status', methods=['GET']) +def get_timer_status(): + """タイマー状態取得 API""" + +@api_bp.route('/stats/today', methods=['GET']) +def get_today_stats(): + """今日の統計取得 API""" + +@api_bp.route('/stats/history', methods=['GET']) +def get_history(): + """履歴取得 API""" +``` + +## 5. データベース設計 + +### 5.1 テーブル構造 + +```sql +-- ポモドーロセッションテーブル +CREATE TABLE pomodoro_sessions ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + duration_minutes INTEGER NOT NULL DEFAULT 25, + start_time DATETIME NOT NULL, + end_time DATETIME, + session_type VARCHAR(20) NOT NULL CHECK (session_type IN ('work', 'short_break', 'long_break')), + state VARCHAR(20) NOT NULL DEFAULT 'idle' CHECK (state IN ('idle', 'work', 'short_break', 'long_break', 'paused')), + completed BOOLEAN DEFAULT FALSE, + paused_duration INTEGER DEFAULT 0, -- 秒単位 + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP +); + +-- 日別統計テーブル +CREATE TABLE daily_stats ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + date DATE NOT NULL UNIQUE, + completed_work_sessions INTEGER DEFAULT 0, + completed_break_sessions INTEGER DEFAULT 0, + total_focus_time INTEGER DEFAULT 0, -- 分単位 + total_break_time INTEGER DEFAULT 0, -- 分単位 + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP +); + +-- インデックス +CREATE INDEX idx_pomodoro_sessions_date ON pomodoro_sessions(date(start_time)); +CREATE INDEX idx_pomodoro_sessions_type ON pomodoro_sessions(session_type); +CREATE INDEX idx_pomodoro_sessions_completed ON pomodoro_sessions(completed); +CREATE INDEX idx_daily_stats_date ON daily_stats(date); +``` + +## 6. WebSocket通信設計 + +### 6.1 イベント定義 + +**クライアント → サーバー** +```javascript +// タイマー操作要求 +socket.emit('timer_start', { sessionType: 'work', duration: 25 }); +socket.emit('timer_pause'); +socket.emit('timer_resume'); +socket.emit('timer_reset'); + +// 状態同期要求 +socket.emit('sync_request'); +``` + +**サーバー → クライアント** +```javascript +// タイマー状態更新 +socket.emit('timer_tick', { + remainingTime: 1485, // 秒 + totalTime: 1500, + state: 'work', + sessionId: 123 +}); + +// セッション状態変更 +socket.emit('session_started', { session: sessionData }); +socket.emit('session_paused', { session: sessionData }); +socket.emit('session_completed', { session: sessionData }); +socket.emit('session_reset'); + +// 統計更新 +socket.emit('stats_updated', { todayStats: statsData }); + +// エラー通知 +socket.emit('error', { message: 'エラーメッセージ' }); +``` + +## 7. フロントエンド設計 + +### 7.1 主要コンポーネント + +**TimerController (`static/js/timer.js`)** +```javascript +class TimerController { + constructor() { + this.socket = io(); + this.state = { + isRunning: false, + isPaused: false, + remainingTime: 1500, // 25分 + totalTime: 1500, + sessionType: 'work' + }; + + this.initializeWebSocket(); + this.bindEvents(); + } + + start(sessionType = 'work', duration = 25) {} + pause() {} + resume() {} + reset() {} + updateDisplay() {} +} +``` + +**UIController (`static/js/ui.js`)** +```javascript +class UIController { + constructor(timerController) { + this.timer = timerController; + this.elements = { + display: document.querySelector('.timer-display'), + progressRing: document.querySelector('.progress-ring-circle'), + startBtn: document.getElementById('startBtn'), + resetBtn: document.getElementById('resetBtn'), + statusText: document.querySelector('.status') + }; + + this.bindUIEvents(); + } + + updateTimerDisplay(remainingTime, totalTime) {} + updateProgressRing(progress) {} + updateStatus(state) {} + updateStats(stats) {} +} +``` + +## 8. テスト戦略 + +### 8.1 テストレベル + +1. **単体テスト (Unit Tests)** + - モデルクラス + - サービス層ロジック + - リポジトリ層 + - ユーティリティ関数 + +2. **統合テスト (Integration Tests)** + - API エンドポイント + - WebSocket 通信 + - データベース操作 + +3. **エンドツーエンドテスト (E2E Tests)** + - 完全なユーザーシナリオ + +### 8.2 テスト設計原則 + +- **依存性注入**: モックとスタブの活用 +- **時間の抽象化**: TimeProvider で時間制御をテスト可能に +- **データの分離**: テスト用データベースとフィクスチャ +- **並行テスト**: テスト間の独立性確保 + +### 8.3 テストカバレッジ目標 + +- **単体テスト**: 90%以上 +- **統合テスト**: 主要フロー100% +- **全体**: 80%以上 + +## 9. セキュリティ考慮事項 + +### 9.1 実装予定のセキュリティ対策 + +- **CSRF防護**: Flask-WTF によるCSRFトークン +- **XSS対策**: テンプレートエスケープとContent Security Policy +- **SQLインジェクション対策**: SQLAlchemy ORM使用 +- **セッション管理**: Flask-Session による安全なセッション管理 +- **入力検証**: フォームバリデーションとサニタイゼーション + +## 10. パフォーマンス考慮事項 + +### 10.1 最適化戦略 + +- **データベース**: 適切なインデックス設計 +- **WebSocket**: イベントの最適化と適切な切断処理 +- **フロントエンド**: CSS/JavaScript の最小化と圧縮 +- **キャッシュ**: 静的ファイルのブラウザキャッシュ活用 + +## 11. 拡張性と保守性 + +### 11.1 設計原則 + +- **単一責任の原則**: 各クラスは一つの責任のみ持つ +- **開放閉鎖の原則**: 拡張に対して開放、修正に対して閉鎖 +- **依存性逆転の原則**: 抽象に依存し、具象に依存しない +- **インターフェース分離**: 不要な依存を避ける + +### 11.2 将来の拡張ポイント + +- **ユーザー認証**: マルチユーザー対応 +- **カスタム設定**: 作業時間・休憩時間の調整 +- **通知機能**: ブラウザ通知、メール通知 +- **統計の詳細化**: 週次・月次レポート +- **チーム機能**: グループでのポモドーロ管理 + +## 12. 開発・運用 + +### 12.1 環境構成 + +- **開発環境**: Flask Development Server + SQLite +- **テスト環境**: pytest + In-Memory Database +- **本番環境**: Gunicorn + PostgreSQL + Nginx + +### 12.2 デプロイメント + +- **コンテナ化**: Docker対応 +- **CI/CD**: GitHub Actions +- **監視**: ログ監視とヘルスチェック + +--- + +**作成日**: 2025年8月8日 +**バージョン**: 1.0 +**作成者**: Development Team diff --git a/deliverManager.py b/deliverManager.py index 6f07105d..6bc767ca 100644 --- a/deliverManager.py +++ b/deliverManager.py @@ -4,7 +4,6 @@ from dataclasses import dataclass, field from enum import Enum - class EventArgs: """イベント引数の基底クラス""" pass diff --git a/features.md b/features.md new file mode 100644 index 00000000..36221c21 --- /dev/null +++ b/features.md @@ -0,0 +1,271 @@ +# ポモドーロタイマーアプリケーション 実装機能一覧 + +## 概要 + +本文書は、ポモドーロタイマーWebアプリケーションで実装が必要な機能の詳細一覧です。各機能にはチェックボックスを設置し、実装進捗を管理できるようにしています。 + +## 1. 基本タイマー機能 + +### 1.1 タイマー制御機能 +- [ ] **タイマー開始**: 25分の作業セッション開始 +- [ ] **タイマー一時停止**: 進行中のタイマーを一時停止 +- [ ] **タイマー再開**: 一時停止中のタイマーを再開 +- [ ] **タイマーリセット**: タイマーを初期状態(25:00)に戻す +- [ ] **タイマー完了**: 時間終了時の自動処理 + +### 1.2 セッション管理機能 +- [ ] **作業セッション**: 25分の集中作業時間管理 +- [ ] **短い休憩**: 5分の短い休憩時間管理 +- [ ] **長い休憩**: 15-30分の長い休憩時間管理(4セッション後) +- [ ] **セッション自動切り替え**: 作業→休憩の自動遷移 +- [ ] **セッション状態管理**: 現在のセッション種別と状態の保持 + +## 2. ユーザーインターフェース機能 + +### 2.1 タイマー表示機能 +- [ ] **デジタル時計表示**: 「25:00」形式での残り時間表示 +- [ ] **円形プログレスバー**: 進捗を視覚的に表示する円形UI +- [ ] **プログレス更新**: 1秒ごとのリアルタイム更新 +- [ ] **状態表示**: 「作業中」「休憩中」「一時停止中」などの状態表示 + +### 2.2 操作ボタン機能 +- [ ] **開始ボタン**: セッション開始用のプライマリボタン +- [ ] **一時停止/再開ボタン**: 動的に表示が変わるボタン +- [ ] **リセットボタン**: セカンダリスタイルのリセットボタン +- [ ] **ボタン状態管理**: タイマー状態に応じたボタンの有効/無効制御 + +### 2.3 統計表示機能 +- [ ] **今日の完了セッション数**: 「4 完了」の表示 +- [ ] **今日の合計集中時間**: 「1時間40分 集中時間」の表示 +- [ ] **統計リアルタイム更新**: セッション完了時の自動更新 + +## 3. データ永続化機能 + +### 3.1 セッション記録機能 +- [ ] **セッション開始記録**: 開始時刻、種別、予定時間の記録 +- [ ] **セッション完了記録**: 終了時刻、実際の時間、完了状態の記録 +- [ ] **セッション履歴保存**: データベースへの永続化 +- [ ] **一時停止時間記録**: 一時停止の累積時間記録 + +### 3.2 統計データ管理機能 +- [ ] **日別統計計算**: 完了セッション数、合計時間の集計 +- [ ] **統計データ更新**: セッション完了時の統計自動更新 +- [ ] **履歴データ取得**: 過去の統計データ取得API + +## 4. リアルタイム通信機能 + +### 4.1 WebSocket機能 +- [ ] **クライアント接続管理**: WebSocket接続の確立と維持 +- [ ] **タイマー同期**: 複数タブ間でのタイマー状態同期 +- [ ] **リアルタイム更新**: 1秒ごとのタイマー状態ブロードキャスト +- [ ] **接続エラー処理**: 接続断時の再接続処理 + +### 4.2 イベント処理機能 +- [ ] **タイマーイベント**: 開始、一時停止、再開、完了、リセット +- [ ] **統計更新イベント**: セッション完了時の統計更新通知 +- [ ] **エラーイベント**: エラー発生時の通知 + +## 5. REST API機能 + +### 5.1 タイマー操作API +- [ ] `POST /api/timer/start`: タイマー開始API +- [ ] `POST /api/timer/pause`: タイマー一時停止API +- [ ] `POST /api/timer/resume`: タイマー再開API +- [ ] `POST /api/timer/reset`: タイマーリセットAPI +- [ ] `GET /api/timer/status`: 現在のタイマー状態取得API + +### 5.2 統計情報API +- [ ] `GET /api/stats/today`: 今日の統計情報取得API +- [ ] `GET /api/stats/history`: 履歴データ取得API +- [ ] `GET /api/sessions/recent`: 最近のセッション一覧API + +## 6. 設定管理機能 + +### 6.1 タイマー設定 +- [ ] **作業時間設定**: デフォルト25分の変更可能機能 +- [ ] **短い休憩時間設定**: デフォルト5分の変更可能機能 +- [ ] **長い休憩時間設定**: デフォルト15分の変更可能機能 +- [ ] **長い休憩間隔設定**: 何セッション後に長い休憩にするかの設定 + +### 6.2 通知設定 +- [ ] **ブラウザ通知**: セッション完了時のデスクトップ通知 +- [ ] **音声通知**: セッション完了時のアラート音 +- [ ] **バイブレーション**: モバイル端末でのバイブレーション通知 + +## 7. レスポンシブUI機能 + +### 7.1 画面サイズ対応 +- [ ] **デスクトップ表示**: 1200px以上での最適化表示 +- [ ] **タブレット表示**: 768px-1199pxでの適応表示 +- [ ] **モバイル表示**: 767px以下での縦型表示最適化 + +### 7.2 インタラクション機能 +- [ ] **タッチ操作対応**: モバイル端末でのタッチ操作 +- [ ] **キーボード操作**: スペースキーでの開始/一時停止、Rキーでのリセット +- [ ] **ホバーエフェクト**: ボタンのホバー時視覚フィードバック + +## 8. エラーハンドリング機能 + +### 8.1 フロントエンドエラー処理 +- [ ] **WebSocket接続エラー**: 接続失敗時の再試行処理 +- [ ] **API通信エラー**: HTTP通信エラー時のフォールバック +- [ ] **タイマー同期エラー**: サーバーとの時刻同期失敗時の処理 + +### 8.2 バックエンドエラー処理 +- [ ] **データベースエラー**: DB接続失敗時のエラーレスポンス +- [ ] **バリデーションエラー**: 不正なリクエスト時のエラーメッセージ +- [ ] **セッション管理エラー**: 同時実行制御エラー処理 + +## 9. パフォーマンス最適化機能 + +### 9.1 フロントエンド最適化 +- [ ] **静的ファイル圧縮**: CSS/JSの最小化 +- [ ] **ブラウザキャッシュ**: 静的リソースのキャッシュ制御 +- [ ] **遅延ロード**: 必要な時のみリソース読み込み + +### 9.2 バックエンド最適化 +- [ ] **データベース最適化**: インデックス設定と適切なクエリ +- [ ] **WebSocket最適化**: 不要な通信の削減 +- [ ] **メモリ管理**: セッション情報の適切なメモリ管理 + +## 10. セキュリティ機能 + +### 10.1 基本セキュリティ +- [ ] **CSRF防護**: CSRFトークンによる不正リクエスト防止 +- [ ] **XSS対策**: 入力値のサニタイゼーションとエスケープ +- [ ] **SQLインジェクション対策**: ORMによる安全なDB操作 + +### 10.2 入力検証機能 +- [ ] **API入力検証**: リクエストパラメータのバリデーション +- [ ] **時間値検証**: 設定可能時間の範囲チェック +- [ ] **WebSocketメッセージ検証**: WebSocketデータの検証 + +## 11. テスト機能 + +### 11.1 自動テスト機能 +- [ ] **単体テスト**: 各モジュールの機能テスト +- [ ] **統合テスト**: API・WebSocketの統合テスト +- [ ] **E2Eテスト**: ブラウザでの完全動作テスト +- [ ] **テストカバレッジ**: 80%以上のカバレッジ確保 + +## 12. 運用・監視機能 + +### 12.1 ログ機能 +- [ ] **アクセスログ**: HTTPリクエストのログ記録 +- [ ] **エラーログ**: 例外・エラーの詳細ログ +- [ ] **パフォーマンスログ**: レスポンス時間等の性能ログ + +### 12.2 ヘルスチェック機能 +- [ ] **アプリケーションヘルスチェック**: アプリ生存監視 +- [ ] **データベースヘルスチェック**: DB接続状態監視 + +## 実装優先順位 + +### Phase 1: 基本機能 (MVP) +**目標**: 最小限の動作するポモドーロタイマー + +**必須機能**: +- [ ] タイマー制御機能(開始、一時停止、リセット) +- [ ] デジタル時計表示 +- [ ] 基本的なUI(ボタン、状態表示) +- [ ] セッション記録の基本機能 +- [ ] 基本的なREST API + +**完了基準**: +- ブラウザでタイマーが動作する +- 時間が正確にカウントダウンされる +- ボタン操作が正常に動作する + +--- + +### Phase 2: 視覚的改善 +**目標**: UIモックに近い見た目の実現 + +**追加機能**: +- [ ] 円形プログレスバー +- [ ] 今日の統計表示 +- [ ] レスポンシブデザイン +- [ ] UIアニメーション +- [ ] 統計データの永続化 + +**完了基準**: +- UIがモックアップと同等の品質 +- モバイル端末でも適切に表示される +- 統計情報が正しく表示される + +--- + +### Phase 3: リアルタイム機能 +**目標**: 複数タブ同期とリアルタイム体験 + +**追加機能**: +- [ ] WebSocket実装 +- [ ] 複数タブ同期 +- [ ] リアルタイム統計更新 +- [ ] 接続エラー処理 + +**完了基準**: +- 複数タブで同期が取れる +- リアルタイムでデータが更新される +- 接続が途切れても復旧する + +--- + +### Phase 4: 拡張機能 +**目標**: ユーザビリティとカスタマイズ性の向上 + +**追加機能**: +- [ ] 設定管理機能 +- [ ] 通知機能 +- [ ] 履歴表示機能 +- [ ] キーボードショートカット + +**完了基準**: +- ユーザーが設定をカスタマイズできる +- 適切なタイミングで通知される +- 過去のデータを確認できる + +--- + +### Phase 5: 品質向上 +**目標**: プロダクション品質の達成 + +**追加機能**: +- [ ] 包括的テスト +- [ ] パフォーマンス最適化 +- [ ] セキュリティ強化 +- [ ] 運用機能 + +**完了基準**: +- テストカバレッジ80%以上 +- セキュリティ要件を満たす +- 本番環境にデプロイ可能 + +## 進捗管理 + +### 全体進捗 +- **総機能数**: 66機能 +- **完了済み**: 0機能 (0%) +- **進行中**: 0機能 (0%) +- **未着手**: 66機能 (100%) + +### フェーズ別進捗 +- **Phase 1 (MVP)**: 0/10機能完了 (0%) +- **Phase 2 (視覚的改善)**: 0/8機能完了 (0%) +- **Phase 3 (リアルタイム)**: 0/8機能完了 (0%) +- **Phase 4 (拡張機能)**: 0/15機能完了 (0%) +- **Phase 5 (品質向上)**: 0/25機能完了 (0%) + +## 注意事項 + +1. **チェックボックス更新**: 機能実装完了時は該当項目にチェックを入れてください +2. **優先順位**: Phase順に実装を進めることを推奨します +3. **依存関係**: 一部機能は前のPhaseの完了を前提としています +4. **テスト**: 各機能実装後は適切なテストを作成してください +5. **ドキュメント更新**: 実装内容に変更があった場合は本文書を更新してください + +--- + +**作成日**: 2025年8月8日 +**最終更新**: 2025年8月8日 +**バージョン**: 1.0 diff --git a/main.py b/main.py index e69de29b..cda1e014 100644 --- a/main.py +++ b/main.py @@ -0,0 +1,15 @@ +# Fibonacci数列を計算する関数 +def fibonacci(n): + if n <= 0: + return [] + elif n == 1: + return [0] + elif n == 2: + return [0, 1] + + fib_sequence = [0, 1] + for i in range(2, n): + next_value = fib_sequence[i - 1] + fib_sequence[i - 2] + fib_sequence.append(next_value) + + return fib_sequence \ No newline at end of file diff --git a/plan.md b/plan.md new file mode 100644 index 00000000..343b81fc --- /dev/null +++ b/plan.md @@ -0,0 +1,105 @@ +# ポモドーロタイマーアプリケーション 段階的実装計画 + +## 概要 + +本計画は、UIモック・アーキテクチャ・機能一覧を踏まえ、ポモドーロタイマーWebアプリケーションを段階的に開発するためのロードマップです。各段階は「粒度の細かい機能単位」で分割し、着実に完成度を高めていきます。 + +--- + +## Phase 1: MVP(最小限の動作) + +### 1-1. タイマーの基本動作 +- [ ] タイマーのカウントダウン(25分固定) +- [ ] デジタル時計表示(「25:00」) +- [ ] タイマー開始・リセットボタンのUI +- [ ] タイマー状態(作業中/停止中)の表示 + +### 1-2. サーバー・クライアントの基本構成 +- [ ] Flaskアプリのセットアップ +- [ ] index.html, style.css, timer.jsの作成 +- [ ] ボタン操作によるタイマー制御(開始・リセット) + +--- + +## Phase 2: UI/UX強化 + +### 2-1. 視覚的改善 +- [ ] 円形プログレスバーの実装 +- [ ] ボタンのデザイン・ホバーエフェクト +- [ ] 状態表示の日本語化・スタイル調整 + +### 2-2. レスポンシブ対応 +- [ ] モバイル・タブレット・PCでの表示最適化 +- [ ] タッチ操作対応 + +--- + +## Phase 3: セッション・統計管理 + +### 3-1. セッション記録 +- [ ] 作業セッションの開始・完了記録 +- [ ] 日別の完了数・集中時間の集計 +- [ ] 今日の進捗表示(完了数・集中時間) + +### 3-2. データ永続化 +- [ ] SQLiteによるセッション・統計データ保存 +- [ ] APIによる統計データ取得 + +--- + +## Phase 4: リアルタイム・複数タブ同期 + +### 4-1. WebSocket導入 +- [ ] Flask-SocketIOによるリアルタイム通信 +- [ ] タイマー状態の1秒ごとのブロードキャスト +- [ ] 複数タブ間のタイマー同期 + +### 4-2. エラー・接続管理 +- [ ] WebSocket接続断時の再接続処理 +- [ ] エラー通知UI + +--- + +## Phase 5: 拡張・カスタマイズ + +### 5-1. 設定機能 +- [ ] 作業・休憩時間のカスタマイズ +- [ ] 長い休憩の自動切り替え(4セッション後) + +### 5-2. 通知・履歴 +- [ ] ブラウザ通知・音声通知 +- [ ] セッション履歴表示 + +--- + +## Phase 6: 品質・運用 + +### 6-1. テスト・品質向上 +- [ ] 単体・統合・E2Eテストの実装 +- [ ] テストカバレッジ80%以上 + +### 6-2. セキュリティ・パフォーマンス +- [ ] CSRF/XSS/SQLインジェクション対策 +- [ ] 静的ファイル圧縮・キャッシュ最適化 + +### 6-3. 運用・監視 +- [ ] ログ・ヘルスチェック機能 +- [ ] Docker・CI/CD対応 + +--- + +## 実装粒度のポイント + +- 各Phaseは「UI/UX」「サーバー」「データ」「リアルタイム」「拡張」「品質」の観点で細分化 +- 1機能ごとにコミット・テスト・レビューを推奨 +- MVP完成後は、ユーザー体験・保守性・拡張性を段階的に高める + +--- + +**作成日**: 2025年8月8日 +**バージョン**: 1.0 +**作成者**: Development Team + +--- + +この計画に沿って、段階的に機能を実装・検証・改善していくことで、安定した高品質なポモドーロタイマーWebアプリケーションを構築できます。 diff --git a/point.py b/point.py index e69de29b..fb37a0bc 100644 --- a/point.py +++ b/point.py @@ -0,0 +1,16 @@ +import math + +class Point3D: + def __init__(self, x, y, z): + self.x = x + self.y = y + self.z = z + + def distance_to(self, other): + dx = self.x - other.x + dy = self.y - other.y + dz = self.z - other.z + return math.sqrt(dx * dx + dy * dy + dz * dz) + + def __str__(self): + return f"Point3D({self.x}, {self.y}, {self.z})" \ No newline at end of file diff --git a/pomodoro_app/app.py b/pomodoro_app/app.py new file mode 100644 index 00000000..44388335 --- /dev/null +++ b/pomodoro_app/app.py @@ -0,0 +1,10 @@ +from flask import Flask, render_template + +app = Flask(__name__, static_folder='static', template_folder='templates') + +@app.route('/') +def index(): + return render_template('index.html') + +if __name__ == '__main__': + app.run(debug=True) diff --git a/pomodoro_app/static/css/style.css b/pomodoro_app/static/css/style.css new file mode 100644 index 00000000..156efd72 --- /dev/null +++ b/pomodoro_app/static/css/style.css @@ -0,0 +1,62 @@ +body { + background: #7b7fd4; + font-family: 'Segoe UI', 'Meiryo', sans-serif; + margin: 0; + padding: 0; +} +.container { + background: #f8f8fc; + border-radius: 24px; + box-shadow: 0 8px 32px rgba(80,80,160,0.18); + width: 320px; + margin: 48px auto; + padding: 32px 24px; + text-align: center; +} +.timer-display { + font-size: 48px; + font-weight: bold; + margin: 24px 0 8px 0; +} +.status { + font-size: 18px; + color: #666; + margin-bottom: 24px; +} +.button-group { + display: flex; + justify-content: center; + gap: 16px; + margin-bottom: 16px; +} +#startBtn { + background: linear-gradient(90deg, #7b7fd4 60%, #a3a7e6 100%); + color: #fff; + border: none; + border-radius: 24px; + padding: 10px 32px; + font-size: 18px; + cursor: pointer; + font-weight: bold; + box-shadow: 0 2px 8px rgba(80,80,160,0.08); + transition: background 0.2s; +} +#startBtn:hover { + background: linear-gradient(90deg, #5a5eb0 60%, #7b7fd4 100%); +} +#resetBtn { + background: #fff; + color: #7b7fd4; + border: 2px solid #7b7fd4; + border-radius: 24px; + padding: 10px 32px; + font-size: 18px; + cursor: pointer; + font-weight: bold; + box-shadow: 0 2px 8px rgba(80,80,160,0.08); + transition: background 0.2s, color 0.2s; +} +#resetBtn:hover { + background: #eaeafd; + color: #5a5eb0; +} diff --git a/pomodoro_app/static/js/timer.js b/pomodoro_app/static/js/timer.js new file mode 100644 index 00000000..d7880440 --- /dev/null +++ b/pomodoro_app/static/js/timer.js @@ -0,0 +1,49 @@ +let timer = null; +let remainingSeconds = 25 * 60; +let isRunning = false; + +const timerDisplay = document.getElementById('timerDisplay'); +const startBtn = document.getElementById('startBtn'); +const resetBtn = document.getElementById('resetBtn'); +const statusText = document.getElementById('statusText'); + +function updateDisplay() { + const min = String(Math.floor(remainingSeconds / 60)).padStart(2, '0'); + const sec = String(remainingSeconds % 60).padStart(2, '0'); + timerDisplay.textContent = `${min}:${sec}`; +} + +function updateStatus() { + statusText.textContent = isRunning ? '作業中' : '停止中'; +} + +function startTimer() { + if (isRunning) return; + isRunning = true; + updateStatus(); + timer = setInterval(() => { + if (remainingSeconds > 0) { + remainingSeconds--; + updateDisplay(); + } else { + clearInterval(timer); + isRunning = false; + updateStatus(); + } + }, 1000); +} + +function resetTimer() { + clearInterval(timer); + remainingSeconds = 25 * 60; + isRunning = false; + updateDisplay(); + updateStatus(); +} + +startBtn.addEventListener('click', startTimer); +resetBtn.addEventListener('click', resetTimer); + +// 初期表示 +updateDisplay(); +updateStatus(); diff --git a/pomodoro_app/templates/index.html b/pomodoro_app/templates/index.html new file mode 100644 index 00000000..626b971d --- /dev/null +++ b/pomodoro_app/templates/index.html @@ -0,0 +1,21 @@ + + + + + + ポモドーロタイマー + + + +
+

ポモドーロタイマー

+
25:00
+
停止中
+
+ + +
+
+ + +