本演習では、社内向けの「備品貸出・在庫管理システム」をFlaskで新規構築いたします。利用者は備品(ノートPC、モニター、ケーブル等)を検索し、貸出申請や返却登録を行うことができます。
管理者は備品マスタ、在庫・状態、貸出ルール、ユーザー権限を管理し、貸出状況の監査が可能です。アプリケーションには、HTML(Jinja2)による管理画面と、外部連携を想定したREST APIを併設いたします。
DBはSQLAlchemyで設計し、Flask-Migrateによってスキーマ変更を管理します。また、画像アップロード(備品写真)とPillowによるサムネイル生成を実装し、静的ファイルはBootstrapで画面品質を担保いたします。
申請承認や期限超過通知はCeleryの非同期タスクで実行し、メール送信を行います。外部API連携として、拠点住所から地図APIで位置情報を取得し、備品の保管場所を地図表示できるようにいたします。
全体を通じて、CSRFやXSS対策、入力バリデーション、エラーハンドリング、ロギング、テスト駆動(単体・統合・カバレッジ)を満たし、キャッシュやクエリ最適化で性能も担保します。
最終的には、要件定義から画面遷移、DB設計、結合テスト、受入テストまで、一通りの実務成果物を作成し、運用を想定した品質で納品可能なレベルを目指してまいります。
要件定義
目的
- 備品の所在・貸出状況を一元管理し、貸出手続きと監査性を向上する。
対象ユーザー
- 一般ユーザー:貸出申請、返却登録、自分の履歴閲覧
- 管理者:備品マスタ管理、申請承認、ユーザー/ロール管理、監査ログ確認
前提/制約
- 認証必須(ログインなしアクセス不可)
- 備品写真のアップロードは画像のみ(png/jpg/webp)
- 期限超過通知は定期タスクで送信
- 監査ログは改ざん防止のため更新不可(追記のみ)
- APIはJSON、認証はセッションクッキー(管理画面)+APIトークン(API)
非機能要件
- セキュリティ:CSRF、XSS、SQLi対策、パスワードハッシュ、権限分離
- 可用性:想定同時利用 50人、ピーク時も検索が2秒以内
- 保守性:マイグレーション管理、構造化ログ、テストカバレッジ70%以上
- 性能:備品一覧はページネーション、検索結果はキャッシュ(短時間)
画面遷移
- ログイン → ダッシュボード
- ダッシュボード
- 備品一覧 → 備品詳細 →(貸出申請)
- マイページ(自分の貸出履歴)→ 返却登録
- (管理者のみ)申請一覧 → 申請詳細 → 承認/却下
- (管理者のみ)備品管理(一覧→新規→編集)
- (管理者のみ)ユーザー管理(一覧→詳細→ロール変更)
- (管理者のみ)監査ログ閲覧
- エラーページ(403/404/500)は共通レイアウトで遷移
機能要件
1. 認証・認可
- ユーザー登録、ログイン、ログアウト
- パスワードはハッシュ化して保存
- ロール(user/admin)によるアクセス制御(デコレータ)
2. 備品管理(管理者)
- 備品のCRUD
- 状態(利用可/貸出中/修理中/廃棄)管理
- 画像アップロード、サムネイル自動生成、表示最適化
3. 貸出フロー(一般+管理者)
- 一般:貸出申請(開始日・返却予定日・理由)
- 管理者:承認/却下、却下理由登録
- 承認後、備品は「貸出中」に遷移
- 返却登録により「利用可」に戻す(破損時は「修理中」も選択可)
4. 検索・一覧
- 備品一覧:カテゴリ/状態/キーワードで検索、ページネーション
- 貸出履歴:ユーザー別、期間フィルタ
- クエリ最適化(N+1回避)、必要に応じてインデックス
5. 通知(非同期)
- 承認・却下時メール通知(Celery)
- 期限超過の定期チェック(1日1回)で督促メール
6. 外部API連携
- 拠点住所から地図ジオコーディング(requests)
- 備品保管拠点の地図表示用に緯度経度を保持
- APIキーは環境変数で管理、ログに出さない
7. REST API
- GET /api/items(検索+ページネーション)
- GET /api/items/
- POST /api/requests(申請)
- GET /api/requests/mine(自分の申請)
- 管理者向け:PATCH /api/requests/(承認/却下)
- エラー時はJSONで統一(コード、メッセージ、詳細)
8. エラーハンドリング/ログ
- 403/404/500のカスタムページ
- 例外は適切に握り、監査ログ+アプリログへ記録
- ログはリクエストIDを付与
9. テスト
- 単体:モデル、サービス層、バリデーション
- 統合:主要画面・API・権限
- カバレッジ計測(閾値設定)
テーブル設計書(案)
users
- id(PK)
- email(Unique, NotNull)
- password_hash(NotNull)
- name(NotNull)
- is_active(Bool, default true)
- created_at, updated_at
roles
- id(PK)
- name(Unique) 例: user/admin
user_roles(多対多)
- user_id(FK users.id, PK)
- role_id(FK roles.id, PK)
locations(拠点)
- id(PK)
- name(NotNull)
- address(NotNull)
- latitude, longitude(ジオコーディング結果)
- created_at, updated_at
items(備品)
- id(PK)
- asset_tag(Unique, NotNull) 管理番号
- name(NotNull)
- category(NotNull) 例: pc/monitor/other
- status(NotNull) 例: available/borrowed/repair/disposed
- location_id(FK locations.id)
- description(Text)
- image_path
- thumb_path
- created_at, updated_at
- index: (status), (category), (location_id)
loan_requests(貸出申請)
- id(PK)
- user_id(FK users.id, NotNull)
- item_id(FK items.id, NotNull)
- start_date(NotNull)
- due_date(NotNull)
- reason(Text, NotNull)
- status(NotNull) 例: pending/approved/rejected/returned
- decision_by(FK users.id, Null) 承認者
- decision_note(Text, Null)
- decided_at(Null)
- returned_at(Null)
- created_at, updated_at
- index: (user_id, status), (item_id, status), (due_date)
audit_logs(監査ログ)
- id(PK)
- actor_user_id(FK users.id, Null) 未ログイン操作の可能性考慮
- action(NotNull) 例: ITEM_CREATE, REQUEST_APPROVE
- target_type(NotNull) 例: item/request/user
- target_id(NotNull)
- detail_json(JSON/Text)
- ip_address
- user_agent
- created_at
- 更新/削除禁止(アプリ側で制御)
結合テスト(主要観点)
IT-01 認証~一覧表示
- 前提:一般ユーザーが存在
- 手順:ログイン→備品一覧表示→検索→ページ遷移
- 期待:未ログイン時はログインへリダイレクト、検索条件が反映、ページネーション正常
IT-02 申請~承認~状態遷移
- 前提:備品がavailable、管理者が存在
- 手順:一般が申請→管理者が承認→備品詳細確認
- 期待:申請status=approved、備品status=borrowed、承認メールが非同期キューに積まれる
IT-03 却下フロー
- 手順:申請→却下(理由必須)
- 期待:status=rejected、備品statusはavailableのまま、却下理由が履歴に残る
IT-04 返却登録
- 手順:承認済み申請を返却登録(返却時状態選択)
- 期待:status=returned、returned_at設定、備品statusがavailableまたはrepairへ
IT-05 画像アップロード
- 手順:備品にjpgをアップロード→詳細表示
- 期待:拡張子/ContentTypeチェック、サムネ生成、パスがDBに保存、一覧はサムネ表示
IT-06 API認証と権限制御
- 手順:トークン無しでPOST /api/requests→失敗、一般トークンで管理PATCH→失敗、管理トークンで成功
- 期待:401/403が正しく返る、エラーJSON形式統一
IT-07 例外とエラーページ
- 手順:存在しない備品IDアクセス、権限無し画面アクセス
- 期待:404/403がカスタムページで表示、ログに記録される
IT-08 期限超過通知(疑似)
- 手順:due_dateが過去のapprovedを作成→定期タスク相当処理を実行
- 期待:対象抽出が正しい、通知が重複送信されない(送信済みフラグ or auditで制御)
受け入れテスト仕様書(抜粋)
UAT-01 基本業務が完遂できること
- シナリオ:一般ユーザーが備品を探し、申請し、承認され、返却まで完了
- 合格条件:各ステップで画面・メール通知・状態遷移が矛盾なく完了
UAT-02 管理者が備品台帳を維持できること
- シナリオ:備品の新規登録、画像登録、拠点紐付け、廃棄まで実行
- 合格条件:一覧/検索に反映、監査ログに記録、誤操作時もエラーが分かりやすい
UAT-03 セキュリティ要件を満たすこと
- シナリオ:CSRFが必要なフォームでトークン無し送信、XSSを含む入力、SQLi風入力
- 合格条件:送信拒否/無害化、エラーが適切、データ破壊が起きない、機密がログに出ない
UAT-04 性能要件を満たすこと
- シナリオ:備品1000件、貸出履歴5000件相当データで一覧検索
- 合格条件:主要検索が2秒以内、ページネーションが破綻しない、N+1が発生しない
UAT-05 運用要件(障害時の追跡)
- シナリオ:意図的に例外を起こす、404を発生させる
- 合格条件:ログにリクエストID・ユーザー・エラーが残り、原因追跡が可能