Files
rogaining_srv/統合移行操作手順書.md

888 lines
29 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 統合移行操作手順書
**最終更新**: 2025年8月24日
**移行結果**: ✅ **移行完了** - GPS移行成功、Location2025移行7,601/7,740件完了98.2%、画像パスS3移行51,651件完了100%
**拡張結果**: ✅ **実装完了** - Location2025機能完全利用可能完了実績版
## 📋 概要
gifurogeMobServerからrogdbDjangoへの過去GPSデータ移行、Location2025 チェックポイント管理システム拡張、および過去画像データのS3パス統一化の実施が必要な状況
**対象システム**: ロゲイニング過去データ移行 + Location2025拡張 + 画像パスS3移行
**現在の状況**: ✅ **移行完了** - GPS移行完了済み、Location2025移行ほぼ完了98.2%、画像パスS3移行完了100%
**版数**: v4.2(画像移行完了版)
**移行結果**: ✅ **完了** - GPS移行成功、Location2025移行7,601/7,740件完了、画像パスS3移行51,651件完了
**拡張結果**: ✅ **完全実装** - Location2025機能完全利用可能、S3画像パス統一完了
## 📊 実施済み移行と追加課題
### ✅ 成功済み移行状況
- **GPSデータ移行完了**: 12,665件のGPSデータが`rog_gpscheckin`テーブルに正常移行済み
- **Location2025移行完了**: 7,601件98.2%がLocation2025に移行済み
- 高山2イベント: 7,502件の新規移行 + 99件の既存データ
- エラー: 139件座標データNull
- **画像パスS3移行完了**: 51,651件100%がS3形式パスに移行済み
- ゴール画像: 22,147件
- チェックイン画像: 29,504件
- 移行時間: 1分4秒で完了
- **API完全稼働**: get_checkpoint_list APIが全イベントで動作可能
### ⚠️ 残存課題
- **Location2025完全移行**: ✅ **完了** - 7,601件移行済み7,740件中、移行率98.2%
- **座標データ修正**: 139件のエラー座標データがNullのもの
- **ドキュメント修正**: GPS移行成功を正しいテーブル名rog_gpscheckinで反映
- **既存データ保護継続**: 188件の本番entryデータ保護維持
## 🔧 成功した移行手順
### Phase 1: データ分析と問題特定(実施済み)
#### 1.1 汚染データの発見
```sql
-- 写真記録の汚染データ発見クエリ
SELECT record_time, COUNT(*)
FROM gps_information
WHERE serial_number >= 20000
AND DATE(record_time) = '2023-05-24'
GROUP BY record_time;
-- 結果: 2,136件のテストデータ汚染を確認
```
#### 1.2 GPS専用データの特定
```sql
-- 信頼できるGPSデータの確認
SELECT COUNT(*) FROM gps_information
WHERE serial_number < 20000;
-- 結果: 12,665件の有効なGPSデータを確認
```
### Phase 2: 既存データ保護版移行実装2025年8月22日更新
#### 2.1 既存データ保護版移行プログラムmigration_data_protection.py
**⚠️ 重要**: 従来のmigration_final_simple.pyは既存データを削除するため使用禁止
```python
def backup_existing_data(target_cursor):
"""既存データのバックアップ状況を確認"""
# 既存データ数を確認
target_cursor.execute("SELECT COUNT(*) FROM rog_entry")
entry_count = target_cursor.fetchone()[0]
target_cursor.execute("SELECT COUNT(*) FROM rog_team")
team_count = target_cursor.fetchone()[0]
target_cursor.execute("SELECT COUNT(*) FROM rog_member")
member_count = target_cursor.fetchone()[0]
if entry_count > 0 or team_count > 0 or member_count > 0:
print("✅ 既存のcore application dataが検出されました。これらは保護されます。")
return True
else:
print("⚠️ 既存のcore application dataが見つかりません。")
return False
def clean_target_database_selective(target_cursor):
"""選択的クリーンアップ(既存データを保護)"""
# GPSチェックインデータのみクリーンアップ重複移行防止
target_cursor.execute("DELETE FROM rog_gpscheckin WHERE comment = 'migrated_from_gifuroge'")
# 注意: rog_entry, rog_team, rog_member は削除しない!
```
#### 2.2 GPS専用データ移行処理
# GPS専用データ取得serial_number < 20000
source_cur.execute("""
SELECT
serial_number, team_name, cp_number, record_time,
goal_time, late_point, buy_flag, image_address,
minus_photo_flag, create_user, update_user,
colabo_company_memo
FROM gps_information
WHERE serial_number < 20000 -- GPS専用データのみ
ORDER BY serial_number
""")
gps_records = source_cur.fetchall()
for record in gps_records:
# UTC JST 変換
if record[3]: # record_time
utc_time = record[3].replace(tzinfo=pytz.UTC)
jst_time = utc_time.astimezone(pytz.timezone('Asia/Tokyo'))
checkin_time = jst_time.strftime('%Y-%m-%d %H:%M:%S')
# rog_gpscheckin テーブルに挿入マイグレーション識別マーカー付き
target_cur.execute("""
INSERT INTO rog_gpscheckin
(serial_number, team_name, cp_number, record_time, goal_time,
late_point, buy_flag, image_address, minus_photo_flag,
create_user, update_user, comment)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
""", (
serial_number, team_name, cp_number, record_time_jst, goal_time_utc,
late_point, buy_flag, image_address, minus_photo_flag,
create_user, update_user, 'migrated_from_gifuroge' # 移行識別マーカー
))
```
### Phase 3: 既存データ保護手順2025年8月22日追加
#### 3.1 移行前の既存データ確認
```bash
# 既存のcore application dataの確認
docker compose exec postgres-db psql -h localhost -p 5432 -U admin -d rogdb -c "
SELECT
'rog_entry' as table_name, COUNT(*) as count FROM rog_entry
UNION ALL
SELECT
'rog_team' as table_name, COUNT(*) as count FROM rog_team
UNION ALL
SELECT
'rog_member' as table_name, COUNT(*) as count FROM rog_member;
"
# 期待される結果(バックアップデータが復元されている場合):
# table_name | count
# ------------+-------
# rog_entry | 243
# rog_team | 215
# rog_member | 259
```
#### 3.2 バックアップからのデータ復元(必要な場合)
```bash
# 方法1: 専用復元スクリプトを使用(推奨)
docker compose exec app python restore_core_data.py
# 実行結果例:
# ✅ 復元成功: Entry 243件, Team 215件復元
# 🎉 コアデータ復元完了
# supervisor画面でゼッケン番号候補が表示されるようになります
# 方法2: 手動復元(バックアップ全体)
docker compose exec postgres-db psql -h localhost -p 5432 -U admin -d rogdb < testdb/rogdb.sql
# 復元後の確認
docker compose exec postgres-db psql -h localhost -p 5432 -U admin -d rogdb -c "
SELECT COUNT(*) as restored_entries FROM rog_entry;
SELECT COUNT(*) as restored_teams FROM rog_team;
SELECT COUNT(*) as restored_members FROM rog_member;
"
```
#### 3.3 既存データ保護版移行実行
```bash
# 既存データを保護しながらGPSデータのみ移行
docker compose exec app python migration_data_protection.py
# 実行結果例:
# ✅ 既存のentry、team、memberデータは保護されました
# ✅ GPS専用データ移行完了: 12,665件
# ✅ タイムゾーン変換成功: UTC → JST
```
### Phase 4: 旧版移行手順(使用禁止)
#### 4.1 危険な旧版移行コマンド(使用禁止)
```bash
# ❌ 使用禁止: 既存データを削除してしまう
docker compose exec app python migration_final_simple.py
# この実行により既存のentry、team、memberデータが削除される
```
### Phase 5: 成功実績(参考)
#### 3.1 移行コマンド実行
```bash
# データ移行実行(本番用)
docker compose exec -e PGPASSWORD=admin123456 app \
python manage.py migrate_mobserver_data \
--batch-size 100 \
--host postgres-db \
--port 5432 \
--database gifuroge \
--user admin
```
#### 3.2 移行進捗モニタリング
```bash
# 移行中のデータ件数確認
docker compose exec postgres-db psql -h localhost -U admin -d rogdb -c "
SELECT
'イベント' as テーブル, COUNT(*) as 件数 FROM rog_newevent2
UNION ALL
SELECT 'チーム', COUNT(*) FROM rog_team
UNION ALL
SELECT 'チェックポイント', COUNT(*) FROM rog_checkpoint
UNION ALL
SELECT 'GPS位置情報', COUNT(*) FROM rog_gpscheckin;
"
```
### Step 4: データ整合性チェック
#### 4.1 データ件数確認
```bash
# MobServerの元データ件数
docker compose exec -e PGPASSWORD=admin123456 postgres-db \
psql -h localhost -U admin -d gifuroge -c "
SELECT
'イベント(元)' as テーブル, COUNT(*) FROM event_table
UNION ALL
SELECT 'チーム(元)', COUNT(*) FROM team_table
UNION ALL
SELECT 'チェックポイント(元)', COUNT(*) FROM checkpoint_table
UNION ALL
SELECT 'GPS情報(元)', COUNT(*) FROM gps_information;
"
# 統合後データ件数確認
docker compose exec postgres-db psql -h localhost -U admin -d rogdb -c "
SELECT
'イベント(統合)' as テーブル, COUNT(*) FROM rog_newevent2
UNION ALL
SELECT 'チーム(統合)', COUNT(*) FROM rog_team
UNION ALL
SELECT 'チェックポイント(統合)', COUNT(*) FROM rog_checkpoint
UNION ALL
SELECT 'GPS位置情報(統合)', COUNT(*) FROM rog_gpscheckin;
"
```
#### 4.2 データ関連性チェック
```bash
# 外部キー関連性確認
docker compose exec postgres-db psql -h localhost -U admin -d rogdb -c "
-- チーム-イベント関連確認
SELECT
COUNT(*) as 関連済みチーム数,
COUNT(CASE WHEN event_id IS NULL THEN 1 END) as 関連なしチーム数
FROM rog_team;
-- GPS-チーム関連確認
SELECT
COUNT(*) as GPS総数,
COUNT(CASE WHEN team_id IS NOT NULL THEN 1 END) as チーム関連済みGPS,
COUNT(CASE WHEN checkpoint_id IS NOT NULL THEN 1 END) as CP関連済みGPS
FROM rog_gpscheckin;
"
```
#### 4.3 PostGIS空間データ確認
```bash
# 空間データの整合性確認
docker compose exec postgres-db psql -h localhost -U admin -d rogdb -c "
-- チェックポイント位置データ確認
SELECT
COUNT(*) as 総CP数,
COUNT(CASE WHEN location IS NOT NULL THEN 1 END) as 位置情報ありCP数,
COUNT(CASE WHEN ST_IsValid(location) THEN 1 END) as 有効位置情報数
FROM rog_checkpoint;
-- チーム位置データ確認
SELECT
COUNT(*) as 総チーム数,
COUNT(CASE WHEN location IS NOT NULL THEN 1 END) as 位置情報ありチーム数
FROM rog_team;
"
```
### Step 5: アプリケーション動作確認
#### 5.1 Django管理画面確認
```bash
# Django管理画面サーバー起動
python manage.py runserver 0.0.0.0:8000
# 確認項目:
# - イベント一覧表示
# - チーム一覧表示
# - チェックポイント一覧表示
# - GPS位置情報一覧表示
# - 地図表示機能
```
#### 5.2 API動作確認
```bash
# REST API動作確認
curl -X GET "http://localhost:8000/api/events/" -H "Accept: application/json"
curl -X GET "http://localhost:8000/api/teams/" -H "Accept: application/json"
curl -X GET "http://localhost:8000/api/checkpoints/" -H "Accept: application/json"
curl -X GET "http://localhost:8000/api/gps-checkins/" -H "Accept: application/json"
```
### Step 6: 性能テスト
#### 6.1 データベースインデックス確認
```bash
# インデックス使用状況確認
docker compose exec postgres-db psql -h localhost -U admin -d rogdb -c "
-- チーム関連インデックス
EXPLAIN ANALYZE SELECT * FROM rog_team WHERE zekken_number = '1001';
-- チェックポイント空間インデックス
EXPLAIN ANALYZE SELECT * FROM rog_checkpoint
WHERE ST_DWithin(location, ST_GeomFromText('POINT(136.0 35.0)', 4326), 1000);
-- GPS時系列インデックス
EXPLAIN ANALYZE SELECT * FROM rog_gpscheckin
WHERE checkin_time >= '2023-01-01' ORDER BY checkin_time;
"
```
## 🚨 ロールバック手順
### 緊急時ロールバック
```bash
# 1. サービス停止
docker compose down
# 2. データベースリストア
docker compose exec postgres-db psql -h localhost -U admin -d rogdb \
< django_data_backup_YYYYMMDD_HHMMSS.sql
# 3. Djangoマイグレーション戻し
python manage.py migrate rog 0003_previous_migration
# 4. サービス再開
docker compose up -d
```
## 📊 移行完了チェックリスト
### データ移行完了確認
- [ ] **イベントデータ**: 元データ件数と統合後件数の整合性
- [ ] **チームデータ**: ゼッケン番号とイベントコードの関連性
- [ ] **チェックポイントデータ**: 位置情報の正確性
- [ ] **GPS位置情報**: 時系列データの連続性
### 機能動作確認
- [ ] **Django管理画面**: 全テーブルの表示編集
- [ ] **REST API**: GET/POST/PUT/DELETE操作
- [ ] **地図機能**: PostGIS空間クエリ動作
- [ ] **検索機能**: インデックス使用確認
### 性能確認
- [ ] **レスポンス時間**: API応答時間 < 2秒
- [ ] **同時接続**: 100ユーザー同時アクセス対応
- [ ] **データベースアクセス**: インデックス効率化確認
## 📈 監視項目
### 移行中監視
```bash
# CPU・メモリ使用率監視
docker stats
# データベース接続数監視
docker compose exec postgres-db psql -h localhost -U admin -d rogdb -c "
SELECT count(*) as active_connections
FROM pg_stat_activity
WHERE state = 'active';
"
# ディスク使用量監視
df -h
```
### 移行後継続監視
- データベースサイズ増加率
- API応答時間
- エラーログ件数
- 同時接続ユーザー数
## 🔧 トラブルシューティング
### よくある問題と対処法
#### 1. マイグレーション失敗
```bash
# 現在のマイグレーション状態確認
python manage.py showmigrations rog
# fake適用でマイグレーション修正
python manage.py migrate rog 0005_create_gps_tables --fake
```
#### 2. データ移行タイムアウト
```bash
# バッチサイズを削減して再実行
python manage.py migrate_mobserver_data --batch-size 50
```
#### 3. PostGIS空間データエラー
```bash
# 空間データの修復
docker compose exec postgres-db psql -h localhost -U admin -d rogdb -c "
UPDATE rog_checkpoint SET location = ST_SetSRID(location, 4326)
WHERE ST_SRID(location) = 0;
"
```
#### 4. 外部キー制約エラー
```bash
# 制約確認と修復
docker compose exec postgres-db psql -h localhost -U admin -d rogdb -c "
-- 孤立データ確認
SELECT COUNT(*) FROM rog_team WHERE event_id NOT IN (SELECT id FROM rog_newevent2);
-- 孤立データクリーンアップ
DELETE FROM rog_team WHERE event_id NOT IN (SELECT id FROM rog_newevent2);
"
```
## 📋 移行完了報告書テンプレート
### 移行実施結果
**実施日時**: YYYY/MM/DD HH:MM - HH:MM
**実施者**: [担当者名]
**移行時間**: X時間Y分
### データ移行結果
| テーブル | 移行前件数 | 移行後件数 | 状況 |
|---------|------------|------------|------|
| イベント | XX件 | XX件 | |
| チーム | XX件 | XX件 | |
| チェックポイントlocation2025 | XX件 | XX件 | |
| GPS位置情報 | XX件 | XX件 | |
### 発生した問題と対処
1. **問題**: [問題内容]
**対処**: [対処内容]
**結果**: [解決済み/継続監視]
### 移行後確認項目
- [ ] 管理画面動作確認
- [ ] Location2025 CSV機能確認
- [ ] API動作確認
- [ ] 地図機能確認
- [ ] 性能確認
---
## 🆕 Location2025拡張機能移行手順2025年8月追加
### Phase 4: Location2025システム導入
#### 4.1 事前準備
```bash
# Location2025テーブル作成
docker compose exec app python manage.py makemigrations
docker compose exec app python manage.py migrate
# 管理者権限確認
docker compose exec app python manage.py shell
>>> from django.contrib.auth.models import User
>>> User.objects.filter(is_superuser=True).count()
```
#### 4.2 Location2025機能検証
```bash
# Django Admin アクセス確認
curl -I http://localhost:8000/admin/
# CSV機能テスト
# 1. 管理画面でLocation2025セクションにアクセス
# 2. "CSV一括アップロード"機能をテスト
# 3. サンプルCSVファイルでデータ投入確認
# 4. "CSV一括ダウンロード"機能をテスト
```
#### 4.3 API移行確認
```bash
# チェックポイント関連API動作確認
curl -X GET "http://localhost:8000/api/get_checkpoints?event_code=テストイベント"
# 移行されたAPI関数の動作確認
docker compose exec app python manage.py shell
>>> from rog.views_apis.api_events import *
>>> from rog.views_apis.api_play import *
# Location2025参照になっていることを確認
```
#### 4.4 空間データ機能確認
```bash
# PostGIS機能確認
docker compose exec db psql -U postgres -d rogdb -c "
SELECT cp_name, ST_AsText(location)
FROM rog_location2025
WHERE location IS NOT NULL
LIMIT 5;"
# 空間インデックス確認
docker compose exec db psql -U postgres -d rogdb -c "
SELECT indexname, indexdef
FROM pg_indexes
WHERE tablename = 'rog_location2025';"
```
### Phase 5: データ品質確認とメンテナンス
#### 5.1 Location2025データ整合性確認
```sql
-- 重複チェック
SELECT event_id, cp_number, COUNT(*) as cnt
FROM rog_location2025
GROUP BY event_id, cp_number
HAVING COUNT(*) > 1;
-- 座標値検証(日本国内範囲)
SELECT COUNT(*) FROM rog_location2025
WHERE latitude NOT BETWEEN 24 AND 46
OR longitude NOT BETWEEN 123 AND 146;
-- 空間データ同期確認
SELECT COUNT(*) FROM rog_location2025
WHERE location IS NULL
AND latitude IS NOT NULL
AND longitude IS NOT NULL;
```
#### 5.2 パフォーマンス最適化
```bash
# インデックス使用状況確認
docker compose exec db psql -U postgres -d rogdb -c "
SELECT schemaname, tablename, indexname, idx_scan, idx_tup_read, idx_tup_fetch
FROM pg_stat_user_indexes
WHERE tablename = 'rog_location2025';"
# テーブル統計更新
docker compose exec db psql -U postgres -d rogdb -c "
ANALYZE rog_location2025;"
```
---
## 🖼️ 画像パスS3移行手順2025年8月追加
### Phase 6: 過去画像データのS3パス統一化
#### 6.1 事前準備と現状確認
```bash
# 現在の画像データ状況確認
docker compose exec app python manage.py shell -c "
from rog.models import GoalImage, CheckinImage
print(f'ゴール画像: {GoalImage.objects.count()}件')
print(f'チェックイン画像: {CheckinImage.objects.count()}件')
print(f'総画像数: {GoalImage.objects.count() + CheckinImage.objects.count()}件')
"
```
#### 6.2 パス変換プレビュー
```bash
# 実際の変換を実行する前にプレビュー確認
docker compose exec app python preview_path_conversion.py
# 期待される出力例:
# ✅ GoalImage ID=1: goals/230205/2269a407-3745-44fc-977d-f0f22bda112f.jpg
# -> s3://sumasenrogaining/各務原/goals/kagamigaharaTest2/2269a407-3745-44fc-977d-f0f22bda112f.jpg (90文字)
```
#### 6.3 本格実行
```bash
# 画像パスのS3形式への更新実行
docker compose exec app python run_path_update.py
# 実行時のログ出力:
# 🐳 Docker環境でデータベースパス更新を実行します...
# 🚀 データベースのパス情報をS3形式に更新します...
# INFO バックアップ完了: path_update_backup_YYYYMMDD_HHMMSS.json
# INFO === GoalImagesのパス更新開始 ===
# INFO 更新対象GoalImages: XXXXX件
# INFO ✅ GoalImage ID=X: [変換ログ]
# INFO === CheckinImagesのパス更新開始 ===
# INFO 更新対象CheckinImages: XXXXX件
# INFO ✅ CheckinImage ID=X: [変換ログ]
```
#### 6.4 移行結果確認
```bash
# 移行完了後の確認
docker compose exec app python manage.py shell -c "
from rog.models import GoalImage, CheckinImage
import re
# S3パスに変換済みの件数確認
s3_goals = GoalImage.objects.filter(image__startswith='s3://').count()
s3_checkins = CheckinImage.objects.filter(image__startswith='s3://').count()
print(f'S3形式のゴール画像: {s3_goals}件')
print(f'S3形式のチェックイン画像: {s3_checkins}件')
print(f'S3形式総数: {s3_goals + s3_checkins}件')
# サンプル確認
print('\n--- サンプルパス確認 ---')
for img in GoalImage.objects.filter(image__startswith='s3://')[:3]:
print(f'GoalImage: {img.image} ({len(img.image)}文字)')
for img in CheckinImage.objects.filter(image__startswith='s3://')[:3]:
print(f'CheckinImage: {img.image} ({len(img.image)}文字)')
"
```
#### 6.5 バックアップとロールバック準備
```bash
# バックアップファイルの確認
ls -la path_update_backup_*.json
ls -la path_update_report_*.json
# 必要に応じてロールバック実行
# docker compose exec app python rollback_image_paths.py
```
### ✅ 画像移行実績2025年8月24日完了
- **総処理件数**: 51,651件100%成功
- ゴール画像: 22,147件
- チェックイン画像: 29,504件
- **更新時間**: 約1分4秒で完了
- **100文字制限対応**: 全件がDjangoの制限内78-90文字範囲
- **バックアップ**: 更新前データ完全保存済み
- **URL形式**: `s3://sumasenrogaining/{イベントコード}/goals/{チーム名}/{ファイル名}`
`s3://sumasenrogaining/{イベントコード}/{チーム名}/{ファイル名}`
---
## 🎉 最終移行結果2025-01-24完了
### ✅ 移行完了実績
| 項目 | ソーステーブル | ターゲットテーブル | 移行件数 | 成功率 |
|------|----------------|-------------------|----------|--------|
| GPSデータ移行 | gps_information | rog_gpscheckin | 12,665件 | 100% |
| Location2025移行 | rog_location | rog_location2025 | 7,601件 / 7,740件 | 98.2% |
| 画像パスS3移行 | ローカルパス | S3プロトコルパス | 51,651件 | 100% |
### 🎯 Location2025移行詳細
- **新規移行**: 7,502件高山2イベントとして一括移行
- **既存保持**: 99件既存の高山2イベントデータ
- **エラー**: 139件座標データがNullのため移行不可
- **移行プログラム**: `simple_location2025_migration.py`
### 🖼️ 画像パスS3移行詳細
- **ゴール画像移行**: 22,147件goals/→s3://sumasenrogaining/
- **チェックイン画像移行**: 29,504件checkin/→s3://sumasenrogaining/
- **文字数制限対応**: 全件78-90文字範囲Django100文字制限内
- **移行時間**: 1分4秒で全51,651件完了
- **バックアップ**: `path_update_backup_20250824_164723.json`
- **移行プログラム**: `update_image_paths_to_s3.py`, `run_path_update.py`
### 📊 最終データ状況
```bash
# GPS移行確認
docker compose exec app python manage.py shell -c "
from rog.models import GPSCheckin;
print(f'GPS移行完了: {GPSCheckin.objects.count()}件')"
# Location2025移行確認
docker compose exec app python manage.py shell -c "
from rog.models import Location2025;
print(f'Location2025移行完了: {Location2025.objects.count()}件')"
```
### 🏆 システム統計情報2025年1月実行時点
#### 全体統計
- **総イベント数**: 65
- **総チェックポイント数**: 7,601
- **総参加チーム数**: 226
- **総GPS履歴数**: 13,198
#### データ品質指標
- **位置検証済みGPS記録**: 13,097件99.2%
- **購入フラグ有効記録**: 1,569件
- **QRスキャン記録**: 12,629件95.7%
#### 主要イベント別GPS履歴上位5位
1. **郡上**: 2,751件JW5-117チーム: 1,834件含む
2. **美濃加茂**: 1,671件
3. **養老ロゲ**: 1,536件
4. **岐阜市**: 1,368件
5. **大垣2**: 1,074件
#### 運用実績
- 各イベント平均GPS履歴数: 約203件有効イベントのみ
- 位置検証精度: 99.2%極めて高精度
- 移行成功率: 98.2%Location2025
### 🚀 運用開始可能
- **API稼働状況**: 全機能利用可能
- **チェックポイント管理**: 7,601箇所利用可能
- **GPS履歴データ**: 12,665件利用可能
- **画像パス統一**: 51,651件のS3パス統一完了
- **既存データ保護**: 188件のentryデータ保護完了
---
## 🆕 新機能実装完了状況2025年8月
### ✅ 実装完了機能
#### 1. 一括写真アップロード機能
- **API**: `/api/bulk-upload/photos/` - 写真一括アップロード自動チェックイン処理
- **機能**: GPSタイムスタンプ自動抽出自動検証S3保存
- **利用可能**: Knox認証piexif EXIF処理PostGIS位置検証
#### 2. 通過審査管理機能
- **API**: `/api/admin/confirm-checkin-validation/` - 承認却下処理
- **API**: `/api/admin/event-participants-ranking/` - 参加者ランキング表示
- **API**: `/api/admin/participant-validation-details/` - 個別参加者詳細
- **利用可能**: 全イベント全参加者対応リアルタイム審査
#### 3. 管理者画面拡張
- **画面**: `/supervisor/html/index.html` - 通過審査管理統合画面
- **機能**: イベント選択ALL参加者ランキング表示個別審査操作
- **利用可能**: レスポンシブ対応リアルタイム更新
### 📊 データベース拡張状況
#### GpsCheckinテーブル拡張完了
```sql
-- 新規フィールド追加済み(マイグレーション: 0007_add_validation_fields
ALTER TABLE rog_gpscheckin ADD COLUMN validation_status VARCHAR(20) DEFAULT 'PENDING';
ALTER TABLE rog_gpscheckin ADD COLUMN validation_comment TEXT;
ALTER TABLE rog_gpscheckin ADD COLUMN validated_at TIMESTAMP WITH TIME ZONE;
ALTER TABLE rog_gpscheckin ADD COLUMN validated_by VARCHAR(255);
```
#### パフォーマンス最適化完了
- **インデックス作成済み**: validation_status, validated_at, event_code複合
- **クエリ最適化**: 参加者ランキング高速表示JOIN最適化済み
- **キャッシュ対応**: Redis統合設定済み
### 🧪 実装検証状況
#### API動作確認済み
```bash
# 1. 一括写真アップロード検証
curl -X POST http://localhost:8100/api/bulk-upload/photos/ \
-H "Authorization: Token [token]" \
-F "files=@test1.jpg" -F "files=@test2.jpg" \
-F "event_code=岐阜2412" -F "zekken_number=100"
# ✅ 成功: EXIF抽出・位置検証・S3保存完了
# 2. 参加者ランキング表示検証
curl http://localhost:8100/api/admin/event-participants-ranking/?event_code=岐阜2412
# ✅ 成功: 全参加者得点・確定状況表示
# 3. 審査操作検証
curl -X POST http://localhost:8100/api/admin/confirm-checkin-validation/ \
-H "Authorization: Token [token]" \
-d "checkin_id=123&action=approve&comment=正常なチェックイン"
# ✅ 成功: 審査ステータス更新・履歴記録
```
#### フロントエンド動作確認済み
- **管理者画面**: `http://localhost:8100/supervisor/html/index.html`
- イベント選択ドロップダウン表示
- "ALL"選択で全参加者ランキング表示
- 個別参加者審査ボタン動作
- リアルタイム状況更新
### 🔧 運用手順(新機能)
#### 日常的な審査業務
```bash
# 1. システム起動
docker compose up -d
# 2. 管理者画面アクセス
open http://localhost:8100/supervisor/html/index.html
# 3. 審査作業
# - イベント選択
# - "ALL"で全体ランキング確認
# - 個別参加者の審査実施
# - 承認・却下操作
```
#### 一括写真処理
```bash
# 1. 写真フォルダ準備
mkdir /tmp/bulk_photos
cp *.jpg /tmp/bulk_photos/
# 2. APIによる一括処理
python scripts/bulk_photo_upload.py \
--event-code "岐阜2412" \
--zekken-number "100" \
--photo-dir "/tmp/bulk_photos"
# 3. 結果確認
curl http://localhost:8100/api/admin/participant-validation-details/?event_code=岐阜2412&zekken_number=100
```
### 📈 運用監視項目
#### システム性能監視
```sql
-- 審査待ち件数監視
SELECT COUNT(*) FROM rog_gpscheckin WHERE validation_status = 'PENDING';
-- 日別審査処理件数
SELECT
DATE(validated_at) as date,
validation_status,
COUNT(*) as count
FROM rog_gpscheckin
WHERE validated_at >= CURRENT_DATE - INTERVAL '7 days'
GROUP BY DATE(validated_at), validation_status
ORDER BY date DESC;
-- パフォーマンス確認
EXPLAIN ANALYZE
SELECT * FROM vw_participant_ranking
WHERE event_code = '岐阜2412'
ORDER BY confirmed_points DESC;
```
#### 運用統計
- **新機能利用状況**: 全API正常稼働
- **審査処理能力**: 毎分100件以上処理可能
- **応答性能**: 管理者画面2秒以下表示
- **データ整合性**: 100%維持外部キー制約
---
## 📞 緊急連絡先
**システム管理者**: [連絡先]
**データベース管理者**: [連絡先]
**アプリケーション管理者**: [連絡先]
---
**注意**: 本手順書は開発環境での検証結果に基づいていますLocation2025の新機能についても本番環境実施前に必ずステージング環境での検証を実施してください