ICTラウンドアプリ「めぐる君」 技術仕様書
文書番号: ICT-TS-001
対象者: 情報システム部門・委員会担当者
作成日: 2026年4月18日
最終更新日: 2026年9月16日
対象バージョン: 1.13.0
1. システム概要
| 項目 | 内容 |
|---|---|
| システム名 | ICTラウンドアプリ「めぐる君」 |
| 種別 | クライアントサイド Web アプリケーション / PWA |
| 目的 | 感染対策ラウンドの記録、保存、報告書作成の効率化 |
| 利用者 | ICT メンバー、感染対策ラウンド実施者 |
| 配布形態 | 静的ファイル配信 |
| データ保管先 | ブラウザメモリおよび localStorage |
| ラウンド入力データの外部送信 | なし(第7章・第8章を参照) |
| アクセス解析 | Google Analytics 4 を導入(送信項目は 7.4 を参照) |
2. アーキテクチャ
2.1 構成
[利用者端末]
├── Webブラウザ
│ ├── React アプリ
│ ├── Service Worker
│ ├── localStorage
│ └── Web APIs
│ ├── File API
│ ├── Canvas API
│ └── Web Share API
│
├── 静的ファイル配信サーバー
├── Google Fonts(フォント取得)
└── Google Analytics 4(アクセス解析 / ラウンド入力データは送信しない)
2.2 バックエンド
- バックエンドサーバー: なし
- データベース: なし
- 認証基盤: なし
- 外部業務 API: なし
2.3 主要技術スタック
| 分類 | 技術 | 実装上のバージョン |
|---|---|---|
| フレームワーク | React | ^19.2.4 |
| 言語 | TypeScript | ~5.9.3 |
| ビルドツール | Vite | ^8.0.1 |
| CSS | Tailwind CSS | ^4.2.2 |
| Word 生成 | docx |
^9.6.1 |
| ファイル保存 | file-saver |
^2.0.5 |
| チェックリスト読込 | read-excel-file |
^9.3.5 |
3. 画面構成
3.1 画面一覧
- ラウンド開始画面
- 保存済みラウンド一覧画面
- メイン画面
- 写真追加画面
- レポートプレビュー画面
3.2 メイン画面のタブ
チェック写真総評
固定ヘッダーには以下を表示します。
- アプリアイコン(タップでラウンド開始画面に戻る。未保存の変更がある場合は保存確認ダイアログを表示)
- 担当者名 / 病棟名
- 評価進捗
- 保存ボタン
- 外観設定ボタン
固定フッターには以下を表示します。
- タブ切替
- 写真枚数バッジ
- 総評入力済みバッジ
- レポートボタン
3.3 インストールバナー
未インストール環境では、ホーム画面追加を促すバナーを表示します。
- 実装:
src/components/InstallBanner.tsx、src/usePwaInstall.ts - Android / デスクトップ Chrome では
beforeinstallpromptを保持し、バナー操作でインストールプロンプトを表示 - iOS Safari では
beforeinstallpromptが発火しないため、手動追加手順を案内 - 閉じた場合は
localStorageに記録し、以後表示しない
3.4 アプリ本体以外の公開ページ
同一ホスト上に、アプリ本体とは独立した静的ページを配置しています。
| パス | 内容 |
|---|---|
/about |
紹介ページ |
/updates |
更新履歴ページ(/updates/releases.json を読み込み) |
これらは React アプリではなく単体の HTML です。ラウンド入力機能は持ちません。外部リソースの読込先は 7.1 を参照してください。
4. データモデル
4.1 チェックリスト定義
interface ChecklistItemDef {
id: string;
category: string;
description: string;
}
interface ChecklistCategory {
category: string;
items: ChecklistItemDef[];
}
interface SavedChecklist {
id: string;
name: string;
createdAt: string;
isDefault?: boolean;
categories: ChecklistCategory[];
}
4.2 ラウンドデータ
type Rating = 'A' | 'B' | 'C' | null;
interface Photo {
id: string;
dataUrl: string;
comment: string;
timestamp: string;
}
interface ChecklistItemResult {
itemId: string;
rating: Rating;
photos: Photo[];
}
interface RoundData {
inspectorName: string;
wardName: string;
startTime: string;
checklistResults: ChecklistItemResult[];
generalPhotos: Photo[];
overallEvaluation: string;
checklistName?: string;
}
interface SavedRound {
id: string;
title: string;
savedAt: string;
version: 1;
checklistId: string;
roundData: RoundData;
}
5. 永続化仕様
5.1 localStorage キー
| キー | 内容 |
|---|---|
icn-round:checklist-library |
保存済みチェックリスト一覧 |
icn-round:active-checklist-id |
選択中チェックリスト ID |
icn-round:saved-rounds |
保存済みラウンド一覧(担当者名・病棟名・評価・写真・総評を含む) |
icn-round-theme |
テーマ設定 |
icn-round-icon |
アイコン設定 |
pwa_install_tracked |
インストール計測の重複送信防止フラグ |
pwa_banner_dismissed |
インストールバナーを閉じたかどうか |
IndexedDB、Cookie、sessionStorage はアプリ本体では使用していません。Cookie は Google Analytics 4 が設定します(7.4 を参照)。
5.2 保存方針
- 入力中ラウンドは React state 上に保持
保存操作時のみSavedRoundをlocalStorageに保存- チェックリストライブラリは追加 / 削除時に都度保存
- テーマ、アイコン、選択中チェックリストは変更時に保存
5.3 保存形式と暗号化
- 保存形式は
JSON.stringify()による平文の JSON 文字列です - 写真は Base64 の
dataUrlとして、同じく平文で JSON 内に格納します - アプリ独自の暗号化は実装していません
- 端末紛失時の情報保護は、OS のストレージ暗号化(iOS のデータ保護、Android の File-Based Encryption、BitLocker、FileVault 等)と画面ロックに依存する設計です
- したがって、端末に画面ロックとストレージ暗号化を設定した上での運用を前提とします
暗号化を実装していない理由
本アプリはバックエンドを持たないため、暗号鍵の保管場所が JavaScript のバンドル内しかありません。バンドルは誰でも取得して内容を確認できるため、鍵を同梱した暗号化は次のいずれの脅威にも効果がありません。
| 脅威 | バンドルに鍵を同梱した暗号化の効果 |
|---|---|
| 端末の紛失・盗難 | 効果なし(OS のストレージ暗号化と画面ロックが防御にあたる) |
| 共用端末で他者がアプリを開く | 効果なし(アプリが自動的に復号するため素通りする) |
| XSS・悪意のあるブラウザ拡張 | 効果なし(同一コンテキストから鍵を参照できる) |
| ストレージの物理的な解析 | 効果なし(鍵が公開されているため。OS 暗号化が防御にあたる) |
実効性を持たせるには利用者ごとのパスフレーズ入力と鍵導出(PBKDF2 等)が必要ですが、起動のたびに入力が発生すること、失念時に復号不能となりデータを失うことから、ラウンド業務での可用性を著しく損ないます。
以上より、保存データの機密性は端末側の管理策(画面ロック、ストレージ暗号化、MDM)で担保する方針としています。施設の要件として利用者認証つきの暗号化が必要な場合は、別途ご相談ください。
併用を推奨する運用上の対策
暗号化の有無にかかわらず、端末内に記録が残り続けること自体が主要なリスクです。次の運用を推奨します。
- 端末に画面ロックとストレージ暗号化を設定する
- レポート出力後、保存済みラウンドをアプリ内で削除する
- 共用端末では使用後にブラウザのサイトデータを削除する
- 可能であれば MDM 管理下の端末で利用する
5.4 初期データ
初回起動時、seedDefaultIfFirstRun() により標準チェックリストを 1 件生成します。
- ID:
default - 名称:
標準チェックリスト - 内容: 9カテゴリ・22項目
6. 機能仕様
6.1 ラウンド開始
- 担当者名は必須
- 病棟名は任意
- 担当者名の初期値は、直前に利用者が入力した担当者名(連続して別病棟を回る場合の再入力を省くため)。病棟名は毎回空にする
- この引き継ぎ値は React state のみで保持し、単独では永続化しないため再読み込みで空に戻る。保存済みラウンドを開いても引き継ぎ値は変化しない
- 開始時刻は
new Date().toLocaleString('ja-JP')で生成 - 選択中チェックリストに基づき
checklistResultsを初期化
6.2 チェックリスト評価
- 各項目に
ABCnullを設定 - 進捗は
rating !== nullの件数から算出 - カテゴリアコーディオンは先頭カテゴリのみ初期展開
6.3 チェックリスト取り込み
- 対応形式:
.csv.xlsx - CSV は独自パーサで 2 列を解析
- Excel は
read-excel-fileライブラリで先頭シートのみ読込 - 1 行目が
categoryで始まる場合は見出し行としてスキップ - 同一カテゴリ名は自動グルーピング
- 取り込み後は新規
SavedChecklistとして保存
6.4 写真入力
<input type="file" accept="image/*">を使用- 10MB を超える画像は拒否
Canvasで JPEG に再エンコード- 圧縮条件:
- 最大幅
1200px - 品質
0.8
- 最大幅
- 保存形式:
dataUrl - 項目紐付き写真と汎用写真を区別して保持
6.5 総評入力
- プレーンテキスト入力
- 箇条書き記号挿入補助あり
- アプリ独自の音声入力機能は提供しません(7.5)
6.6 レポートプレビュー / 出力
- プレビュー画面ではチェック結果、写真、総評を HTML で表示
- 出力時は
docxライブラリで.docxを生成 - 共有可能端末では
navigator.share({ files })を優先 - 共有非対応時は
file-saverによりダウンロード - ファイル名形式:
感染対策ラウンド_<病棟名または報告書>_<YYYY-MM-DD>.docx
6.7 外観設定
- テーマ 3 種:
warmminimalmedical
- アイコン 2 種:
ranmeguru
7. 通信・オフライン
7.1 外部通信
アプリ本体(/)から発生する通信は以下がすべてです。
| 通信先 | 用途 | ラウンド入力データの送信 |
|---|---|---|
| 配信元ホスト | HTML / JS / CSS / 画像配信 | なし |
fonts.googleapis.com |
Google Fonts CSS | なし |
fonts.gstatic.com |
Google Fonts 本体 | なし |
www.googletagmanager.com |
gtag.js の取得 | なし |
www.google-analytics.com |
アクセス解析イベントの送信(7.4) | なし |
紹介ページ /about と更新履歴ページ /updates は、上記に加えて以下を読み込みます。これらのページにラウンド入力機能はありません。
| 通信先 | 用途 |
|---|---|
cdn.tailwindcss.com |
Tailwind CSS(CDN 版) |
api.qrserver.com |
アプリ URL の QR コード画像生成(/about のみ) |
/about には問い合わせフォーム(forms.gle)へのリンクを設置していますが、これはページ読込時に通信するリソースではなく、利用者がリンクを押して遷移した場合にのみ通信が発生する外部サイトです。フォームへ入力した内容は Google のサービス上で処理されます。
7.2 Service Worker
index.html で ./sw.js を登録します。
キャッシュ戦略は以下です。
- アプリシェル: インストール時に事前キャッシュ
- Google Fonts: Cache First
- ナビゲーション: Network First
- 同一オリジンの
/assets/: Cache First - その他の同一オリジン GET: Network First
7.3 オフライン動作
- 初回アクセス後は、キャッシュ済みアセット範囲で再訪可能
- ただし外部フォント未取得時は代替フォント表示となる可能性あり
- ラウンドデータ共有や同期の仕組みは持たない
- gtag.js はオフライン時のイベント再送を行わないため、圏外で発生した解析イベントは復旧後も送信されず欠測する
7.4 アクセス解析(Google Analytics 4)
7.4.1 構成
- 実装:
src/analytics.ts - 測定 ID はビルド時の環境変数
VITE_GA4_MEASUREMENT_IDから埋め込みます - 環境変数が未設定のビルドでは gtag.js を読み込まず、解析は一切動作しません(
initAnalytics()が即 return) - 公開環境では GitHub Actions のシークレット経由で測定 ID を設定しています(
.github/workflows/deploy.yml) /aboutと/updatesは React アプリとは独立に、HTML 内へ gtag を直接記述しています
7.4.2 送信するイベント
| イベント | 送信契機 | パラメータ |
|---|---|---|
page_view |
初回表示時(SPA のため実質1回) | gtag 標準項目 |
pwa_install |
インストール検知時 | method(appinstalled / standalone_first_launch) |
pwa_install_banner_click |
インストールバナーの操作 | method |
pwa_install_prompt_result |
インストールプロンプトの結果 | outcome |
pwa_install_banner_dismiss |
バナーを閉じた時 | method |
上記に加え、GA4 が自動収集する session_start、first_visit、user_engagement が送信されます。
ユーザープロパティとして display_mode(standalone / browser)を設定します。
7.4.3 送信しないもの
以下は GA4 へ一切送信しません。送信する実装が存在しません。
- 担当者名
- 病棟名
- チェックリストの評価結果
- 写真
- 総評
- 取り込んだチェックリストの内容
- 保存済みラウンド
アプリは SPA であり、URL に入力値を含めないため、page_view の URL 経由で入力内容が送信されることもありません。
7.4.4 GA4 側で取得される標準情報
gtag.js の標準動作として、以下が Google に送信・記録されます。
- IP アドレス(GA4 では地域推定に使用後、レポートには保持されない)
- User-Agent(端末種別・OS・ブラウザ)
- 参照元 URL、閲覧ページの URL とタイトル
_gaCookie による匿名の識別子(client_id)
データ保持期間は GA4 の設定で 14 ヶ月としています。
7.4.5 エラーログ収集
Sentry 等のエラー監視サービスは導入していません。例外情報を外部へ送信する実装はありません。
7.5 音声入力について
本アプリに音声入力機能はありません。 マイクを使用せず、音声データを扱う実装も持ちません。
- v1.7.5 までは総評タブに
SpeechRecognitionを用いた音声入力を実装していましたが、端末本体の音声入力機能で代替できるため v1.7.6(2026年7月2日)で削除しました - 現在アプリがマイクへのアクセス許可を要求することはありません
なお、利用者が端末キーボードの音声入力(iOS の音声入力、Android の音声認識など)を用いて総評を入力することは可能です。この場合の音声データの扱いは端末 OS の機能に属し、本アプリの管理外です。OS の実装によっては音声が OS 提供元のサーバーへ送信されて認識されるため、利用可否は各施設のポリシーに従って判断してください。
8. セキュリティ・個人情報
8.1 取り扱うデータ
- 担当者名
- 病棟名
- チェック結果
- 写真
- 総評
これらはすべて利用端末内にとどまります。バックエンドが存在しないため、サーバー側に保管される複製はありません。
8.2 外部送信
- ラウンド内容(担当者名・病棟名・評価・写真・総評)を外部へ送信する処理は実装していません
- アプリが発生させる外部通信は、静的ファイル取得、フォント取得、アクセス解析の3種類です(7.1)
- アクセス解析では、入力データを含まない利用状況イベントのみを送信します(7.4)
- エラーログ収集サービスは導入していません
- マイクを使用する機能はありません(7.5)
8.3 保存データの暗号化
- 端末内の保存は平文の JSON です。アプリ独自の暗号化は行いません
- バックエンドを持たない構成では鍵をバンドル内に置くほかなく、暗号化が実効性を持たないためです。詳細な理由と代替の管理策は 5.3 を参照してください
- 通信は HTTPS により暗号化されます
- 端末紛失・盗難時の保護は、OS のストレージ暗号化と画面ロックに依存します
8.4 個人情報上の留意点
- 患者情報専用の入力欄はなし
- 写真に個人情報が写り込む運用リスクは残る
- 保存済みラウンドや写真は端末ブラウザの
localStorageに残る - 共用端末では、ブラウザのサイトデータ削除により保存内容を消去できる
- 担当者名は入力必須のため、端末内には職員氏名が保存される
8.5 認証
- アプリ自身はログイン機能を持ちません
- アクセス制限が必要な場合は、配信環境側で制御します
9. ホスティング要件
9.1 配信条件
- 静的ファイル配信のみ
- サーバーサイドランタイム不要
- HTTPS 推奨
9.2 Vite 設定
base: './'__APP_VERSION__をpackage.jsonから埋め込み__BUILD_DATE__をMMDD形式で埋め込みVITE_GA4_MEASUREMENT_ID(任意)を設定するとアクセス解析が有効になる。未設定ならビルド成果物に解析コードは含まれるが動作しない
9.3 配置ファイル
index.htmlmanifest.jsonsw.jsassets/*- アイコン画像
about/、updates/(紹介ページ・更新履歴ページ)robots.txt、sitemap.xmlround-checklist-template.xlsx(チェックリスト取り込み用テンプレート)
10. ビルド・運用
10.1 コマンド
npm install
npm run dev
npm run build
npm run preview
npm run lint
10.2 本番ビルド
tsc -b && vite build- 出力先:
dist/
10.3 更新反映
- Service Worker の更新検知時は自動で再読み込みを試行
- 静的ファイル差し替えで更新可能
11. 既知の実装前提
- 保存済みデータは同一ブラウザ内でのみ利用可能
localStorage容量に依存するため、大量の高解像度写真保存には限界がある- ファイル共有はブラウザ実装差異の影響を受ける
.docxのみ対応し、PDF 生成機能は未実装- 保存データはアプリ独自には暗号化しない
- 1回のラウンドを複数端末で分担して記録する機能は未実装
12 関連文書
| 文書 | 内容 | 公開 URL |
|---|---|---|
docs/privacy-policy.md |
プライバシーポリシー | https://ict-round.conect.llc/docs/privacy-policy |
docs/user-guide.md |
取扱説明書 | https://ict-round.conect.llc/docs/user-guide |
docs/ga4-plan.md |
アクセス解析の運用方針 | 非公開 |
この技術仕様書自体も https://ict-round.conect.llc/docs/technical-spec で公開しています。公開ページは上記の公開対象3文書の Markdown からビルド時に生成しており、内容は同一です。docs/ 配下のその他の文書は公開していません。
13 ライセンス
Apache 2.0