本アプリは訪問看護事業所スタッフが、担当利用者の残薬数・服薬スケジュール・受診日程を一元管理するための業務支援ツールです。
| 機能 | 概要 |
|---|---|
| 利用者管理 | ニックネームによる利用者登録・一覧表示 |
| 定期薬管理 | 服薬タイミング別の残薬数記録・更新 |
| 頓用薬管理 | 頓用薬の残薬数記録・更新 |
| 受診カレンダー | 受診予定日の登録・1週間前アラート表示 |
| カルテ転記 | 残薬情報をテキストでコピーしてカルテへ貼り付け |
| 未登録薬剤ログ | ローカルDBに未登録の薬名を自動記録(DB拡充用) |
| レイヤー | 技術 | 役割 |
|---|---|---|
| フロントエンド | React 18 + Vite | SPA(シングルページアプリケーション)。ブラウザ上で動作 |
| バックエンドAPI | Supabase(PostgREST) | PostgreSQLをREST APIとして自動公開。独自サーバーなし |
| データベース | PostgreSQL(Supabase管理) | 全データの永続化。行レベルセキュリティ(RLS)で保護 |
| 認証 | Supabase Auth | メール/パスワード認証。JWTトークン発行・検証 |
| ホスティング | Vercel | 静的ファイルのCDN配信。HTTPS強制 |
| サービス | 事業者 | データセンター |
|---|---|---|
| Supabase(DB・認証) | Supabase Inc.(米国) インフラはAWS |
Supabase管理(詳細はSupabaseダッシュボードで確認) |
| Vercel(フロントエンド) | Vercel Inc.(米国) | グローバルCDN(静的ファイルのみ。個人情報なし) |
| ライブラリ | 用途 | バージョン |
|---|---|---|
| react / react-dom | UIフレームワーク | 最新安定版 |
| @supabase/supabase-js | Supabase APIクライアント | 最新安定版 |
外部依存は最小限(3パッケージ)に抑えています。サードパーティのアナリティクス・広告・トラッキングライブラリは一切含みません。
| テーブル名 | 用途 | 個人情報 |
|---|---|---|
organizations |
事業所マスタ(名称・ID) | 事業所名のみ |
staff |
スタッフアカウント(メール・表示名) | メールアドレス・氏名 |
patients |
利用者(ニックネームのみ) | ニックネームのみ |
medications |
定期薬(薬剤名・残数・タイミング) | なし |
prn_medications |
頓用薬(薬剤名・残数) | なし |
visits |
受診予定(日付・医療機関名・担当医) | 医療機関名・担当医名のみ |
unknown_drugs |
ローカルDB未登録の薬剤名ログ | なし |
audit_logs |
操作ログ(ログイン・薬の更新・利用者登録など) | スタッフ名のみ |
すべてのデータテーブルに org_id(事業所ID)カラムが付与されており、複数の事業所が同一データベースを共有しても、互いのデータには一切アクセスできません。
▲ 同一DBに共存するが、RLSにより各事業所は自分のデータのみ参照・操作可能
データ変更の追跡のため、主要テーブルに以下のカラムを設けています。
| カラム | 内容 | 対象テーブル |
|---|---|---|
created_by |
登録したスタッフ名 | patients, medications, prn_medications, visits |
updated_by |
最終更新したスタッフ名 | medications, prn_medications |
updated_at |
最終更新日 | medications, prn_medications |
noted_by |
未登録薬を入力したスタッフ名 | unknown_drugs |
localStorage に保管、セッション管理は Supabase が自動処理PostgreSQL の RLS(Row Level Security)を全テーブルで有効化しています。これにより、APIに正規トークンを持っていても、自分の事業所のデータ以外には物理的にアクセスできません。
| テーブル | SELECT | INSERT | UPDATE | DELETE |
|---|---|---|---|---|
| patients / medications prn_medications / visits |
同一org_idのみ | 同一org_idのみ | 同一org_idのみ | 管理者ロールのみ ※ migration 006 で追加 |
| unknown_drugs | 管理者(SQL Editor) | 認証済みユーザー全員 | — | — |
| organizations / staff | 自組織のみ | Edge Function 経由のみ | 制限あり | 管理者ロールのみ |
| audit_logs | 自組織のみ | 直接 INSERT 禁止 SECURITY DEFINER 関数経由のみ |
— | — |
ログイン中のユーザーが所属する事業所IDを返す my_org_id() 関数(SECURITY DEFINER)を定義し、全RLSポリシーで使用しています。
is_org_admin() 関数(SECURITY DEFINER)により、RLSポリシー内でスタッフのロールを判定しています。staff.role = 'admin' を持つユーザーのみが削除・退職処理を実行できます。クライアントからロールを偽装することはできません。
| 経路 | 暗号化 |
|---|---|
| ブラウザ ↔ Vercel(フロントエンド) | TLS 1.2以上(HTTPS強制) |
| ブラウザ ↔ Supabase API | TLS 1.2以上(HTTPS強制) |
| Supabase内部(DB) | 保存時暗号化(AES-256、Supabase管理) |
フロントエンドで使用するAPIキーは Supabase Anon Key(公開可能なキー)のみです。このキーは:
.env)で管理し、GitリポジトリにコミットしないVercel のエッジで全レスポンスにセキュリティヘッダーを付与しています(vercel.json で設定)。
| ヘッダー | 設定値 | 効果 |
|---|---|---|
Strict-Transport-Security |
max-age=31536000; includeSubDomains; preload | HTTPS強制(1年間・サブドメイン含む) |
Content-Security-Policy |
default-src 'self'; connect-src *.supabase.co; frame-ancestors 'none' 等 | XSS・クリックジャッキング・外部スクリプト挿入を制限 |
X-Frame-Options |
DENY | iframe での埋め込み禁止(クリックジャッキング対策) |
X-Content-Type-Options |
nosniff | MIMEタイプスニッフィング防止 |
Referrer-Policy |
strict-origin-when-cross-origin | 外部サイトへのURL情報漏洩を制限 |
Permissions-Policy |
camera=(), microphone=(), geolocation=() | カメラ・マイク・位置情報へのアクセス禁止 |
事業所登録(register-org Edge Function)に以下の制限を追加しました。
zannyaku-v6.vercel.app)および localhost に限定(* 廃止)ALLOWED_ORIGIN で本番 URL をサーバー側に保持(クライアント非公開)従来、クライアントから audit_logs テーブルへ直接 INSERT していたため、org_id や staff_name をクライアントが自由に偽装できる状態でした。
現在は insert_audit_log()(SECURITY DEFINER)関数経由のみに変更し、org_id と user_id は DB 側で auth.uid() から取得・強制します。クライアントからの偽装は不可能です。
| リスク項目 | 現状 | 対応 |
|---|---|---|
| MFA(多要素認証) | 設定可能 | 管理者設定で有効化可能。組織の方針に応じて導入 |
| パスワードポリシー | 最小限 | Supabase Auth 側で強度要件の設定が可能 |
| ログイン試行制限 | 対応済 | Supabase Auth がブルートフォース対策を内蔵 |
| XSS対策 | 対応済 | React の JSX エスケープにより自動的に防止 |
| SQLインジェクション | 対応済 | Supabase SDK がパラメータ化クエリを使用 |
| CSRF対策 | 対応済 | JWTベース認証のためCSRFトークン不要 |
| ロール別権限分離(admin/staff) | 対応済 | migration 006 で実装。削除操作は admin のみ |
| HTTPセキュリティヘッダー | 対応済 | HSTS / CSP / X-Frame-Options 等を vercel.json で設定 |
| 登録 API のアクセス制限 | 対応済 | CORS 制限・POSTのみ・入力バリデーション追加 |
| 監査ログ改ざん防止 | 対応済 | SECURITY DEFINER 関数経由に変更。クライアント偽装不可 |
| JWT のブラウザ保存(localStorage) | 既知のリスク | XSS が起きると token 奪取の可能性。CSP + MFA で軽減。根本解決は Next.js 移行が必要 |
| データバックアップ | Supabase依存 | Supabase 有料プランでは自動バックアップあり(現在Freeプラン) |
| アクセスログ | Supabase依存 | Supabase ダッシュボードでAPIアクセスログを確認可能 |
| 項目 | 内容 |
|---|---|
| 開発者 | 長田 裕乃(Yuno Nagata) |
| SNS | X: @nurselog_ |
| メール | ✉️: nurselog.app.official@gmail.com |
| 位置づけ | 個人開発・内部利用ツール(現在) |
本章は、残薬管理アプリが取り扱う医療関連情報の管理方針を定めるものです。
「医療情報システムの安全管理に関するガイドライン(厚生労働省)」および「医療情報を取り扱う情報システム・サービスの提供事業者における安全管理ガイドライン(経産省・総務省)」(いわゆる3省2ガイドライン)を参考に策定しています。
本アプリは小規模個人事業者が運営するため、全項目への完全準拠を現時点では保証しませんが、以下の技術的・運用的対策を実施しています。
| ガイドライン | 版 | 発行元 |
|---|---|---|
| 医療情報システムの安全管理に関するガイドライン | 第6.0版 | 厚生労働省 |
| 医療情報を取り扱う情報システム・サービスの提供事業者における安全管理ガイドライン | 第1.1版 | 経済産業省・総務省 |
| 情報 | 具体例 | 性質 |
|---|---|---|
| 識別子 | ニックネーム・任意の表示名 | 事業所内識別のみ |
| 薬剤情報 | 薬の名称・数量・処方日・残薬数 | 準医療情報 |
| 訪問記録 | 訪問日時・記録者 | 業務記録 |
| 操作ログ | 操作者・操作内容・日時 | 監査情報 |
| 責任主体 | 範囲 |
|---|---|
| 運営者(Yuno) |
アプリケーションのセキュリティ対策・維持 サービス基盤(Supabase・Vercel)の選定・管理 インシデント発生時の通知と対応 |
| 事業所(管理者・スタッフ) |
アカウント管理(スタッフの追加・削除・権限設定) ログイン情報の適切な管理 退職者アカウントの速やかな削除 利用端末・環境のセキュリティ確保 患者情報の入力内容に関する判断(何を記録するか) |
| ステップ | 内容 |
|---|---|
| 1. 検知 | 不審なアクセス・操作ログを確認する |
| 2. 初動 | 疑いのあるアカウントのアクセスを停止する |
| 3. 報告 | 運営者(Yuno)へメール連絡(nurselog.app.official@gmail.com) |
| 4. 対応 | Supabase管理コンソールで調査・復旧 |
| 5. 通知 | 影響を受けた事業所に72時間以内を目標に通知 |
| 6. 再発防止 | 原因分析と設定変更 |