経費精算OCR アプリ 引き継ぎ資料

nurse-expense-app | 訪問看護ステーション向け経費精算PWA

2026-03-25 更新

1. プロジェクト概要

訪問看護ステーションのスタッフが、スマホで領収書を撮影しOCRで自動読み取り、経費申請から管理者承認・CSV出力までを完結させるPWAアプリ。

業務フロー

領収書撮影
Gemini OCR
申請
管理者承認
CSV出力

対象ユーザー

  • スタッフ — 経費申請(撮影・OCR・フォーム入力)、履歴確認
  • 管理者 — 全申請の承認/差し戻し、月別CSV出力

2. 技術スタック

領域技術備考
FrontendNext.js 16 (App Router) + TypeScriptReact 19
CSSTailwind CSS v4
認証Firebase Authメール/パスワード
DBFirestoreクライアントSDK直接
ストレージFirebase Storage領収書画像
OCRGAS + Gemini 2.0 Flash API無料枠: 15RPM / 1500RPD
PWAnext-pwaオフライン対応
バリデーションZod
DeployVercelCDN配信

3. ディレクトリ構成

C:\Users\kawag\work\nurse-expense-app\
├── src/
│   ├── app/
│   │   ├── layout.tsx              # ルートレイアウト(フォント・PWA・AuthProvider)
│   │   ├── page.tsx                # ルートリダイレクト
│   │   ├── login/page.tsx          # ログイン・新規登録
│   │   ├── api/export/route.ts     # CSV生成 API Route
│   │   └── (dashboard)/
│   │       ├── layout.tsx          # 認証ガード付きレイアウト
│   │       ├── submit/page.tsx     # 経費申請(撮影→OCR→フォーム)
│   │       ├── history/page.tsx    # 申請履歴
│   │       └── admin/page.tsx      # 管理者承認 + CSV出力
│   ├── components/
│   │   ├── receipt-camera.tsx      # カメラ撮影・プレビュー
│   │   ├── receipt-form.tsx        # OCR結果入力フォーム
│   │   ├── status-badge.tsx        # ステータスバッジ表示
│   │   ├── nav-header.tsx          # ナビゲーション
│   │   └── toast.tsx               # トースト通知
│   └── lib/
│       ├── firebase.ts             # Firebase初期化(環境変数から設定読込)
│       ├── types.ts                # 型定義(Expense, OcrResult, UserProfile等)
│       ├── validators.ts           # Zodスキーマ
│       ├── expense-service.ts      # Firestore CRUD操作
│       └── auth-context.tsx        # Firebase Auth コンテキスト
├── gas/
│   └── ocr.gs                      # GAS Web App(Gemini OCR本体)
├── public/
│   └── manifest.json               # PWAマニフェスト
├── firestore.rules                 # Firestoreセキュリティルール
├── storage.rules                   # Storageセキュリティルール
├── next.config.ts
├── CLAUDE.md
└── package.json

4. データモデル

Expense(経費申請)

フィールド説明
idstringFirestoreドキュメント ID
userIdstring申請者UID
userNamestring申請者名
receiptUrlstringStorage上の領収書画像URL
amountnumber金額(税込、1〜1,000,000円)
datestring日付(YYYY-MM-DD)
categoryExpenseCategory交通費 / 消耗品 / 通信費 / その他
descriptionstring摘要
statusExpenseStatuspending / approved / rejected / paid
reviewerIdstring | null承認者UID
reviewerCommentstring | null承認/差し戻しコメント
reviewedAtDate | null承認日時
createdAtDate申請日時

ステータス遷移

pending
approved
paid
pending
rejected

5. OCR処理フロー

  1. スマホカメラで領収書を撮影(input[capture="environment"]
  2. 画像をbase64エンコード
  3. GAS Web Appへ POST 送信(NEXT_PUBLIC_GAS_OCR_URL
  4. GAS側でGemini 2.0 Flash APIに画像+プロンプトを送信
  5. 構造化JSON(日付・金額・店舗名・カテゴリ・摘要)を返却
  6. フォームに自動入力 — OCR失敗時は手入力にフォールバック

Geminiプロンプトの主要ルール

  • 金額は税込み総額を優先
  • 和暦は西暦に変換
  • 読み取り不能な項目は null
  • JSON以外のテキストは含めない
Gemini 2.0 Flash 無料枠の制限: 15リクエスト/分、1,500リクエスト/日。大量のOCR処理が必要な場合は有料プランへの切り替えを検討。

6. セキュリティ設計

Firestore Security Rules

コレクション操作権限
profilesread自分のみ
create自分のみ(role は必ず staff
update自分のみ(role 変更不可)
delete不可
expensesreadスタッフ: 自分の申請のみ / 管理者: 全件
create認証済みユーザー(status は必ず pending
update管理者のみ(申請内容フィールドの変更不可)
delete不可(監査証跡保持)

Storage Rules

  • ユーザー別ディレクトリ制限(receipts/{uid}/
  • ファイルサイズ上限: 10MB
  • 画像ファイルのみ許可(image/*
  • 削除不可

管理者ロール

Firebase Console から手動でプロフィールの role フィールドを "admin" に変更。API経由での昇格はできない設計。

7. CSV出力

  • API Route: /api/export
  • エンコーディング: UTF-8 with BOM(Excelインポート対応)
  • CSVインジェクション対策: = + - @ で始まるセルをエスケープ
  • 管理者画面から月別でダウンロード可能

8. 環境変数・セットアップ

Next.js 側(.env.local)

変数名説明
NEXT_PUBLIC_FIREBASE_API_KEYFirebase APIキー
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN認証ドメイン
NEXT_PUBLIC_FIREBASE_PROJECT_IDプロジェクトID
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKETStorageバケット
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_IDメッセージング送信者ID
NEXT_PUBLIC_FIREBASE_APP_IDアプリID
NEXT_PUBLIC_GAS_OCR_URLGAS Web App デプロイURL

GAS 側(スクリプトプロパティ)

プロパティ説明
GEMINI_API_KEYGoogle AI Studio で取得したAPIキー

Firebase Console 有効化手順(手動)

  1. Authentication: Console → Authentication → 始める → メール/パスワードを有効化
  2. Firestore: Console → Firestore Database → データベースを作成 → ロケーション asia-northeast1(東京)→ 本番モード
  3. Storage: Console → Storage → 始める → 本番モード → ロケーション asia-northeast1

有効化後、firebase deploy --only firestore:rules,storage --project nurse-expense-app でSecurity Rulesをデプロイ

GAS セットアップ手順

  1. Google Apps Script で新規プロジェクト作成
  2. gas/ocr.gs の内容をエディタに貼り付け
  3. スクリプトプロパティに GEMINI_API_KEY を設定
  4. Web App としてデプロイ(アクセス: 全員)
  5. デプロイURLを NEXT_PUBLIC_GAS_OCR_URL に設定

9. 開発コマンド

# 開発サーバー起動
npm run dev

# プロダクションビルド
npm run build

# ESLint
npm run lint

10. 現在の状態と残課題

完了済み

  • 全画面のUI実装(ログイン・申請・履歴・管理者) 完了
  • Firebase Auth 認証フロー 完了
  • Firestore CRUD + Security Rules 完了
  • Storage Rules 完了
  • GAS + Gemini OCR実装 完了
  • CSV出力(BOM付きUTF-8 + インジェクション対策) 完了
  • PWA対応(manifest.json) 完了
  • Zodバリデーション 完了

デプロイ前に対応が必要

  • PWAアイコン画像の配置(public/icon-192.png, public/icon-512.png未着手
  • Firebase プロジェクト作成 + .env.local 設定 完了
    • プロジェクトID: nurse-expense-app
    • 表示名: Nurse Expense App
    • Web App登録済み(App ID取得済み)
    • .env.local にFirebase設定値 + GAS OCR URL設定済み
  • Firebase Console で手動有効化が必要:
    • Authentication(メール/パスワード) 未着手
    • Firestore Database(asia-northeast1) 未着手
    • Storage(asia-northeast1) 未着手
  • Firestore / Storage Security Rules のデプロイ 未着手
  • GAS プロジェクト作成 + デプロイ 完了
  • Vercel へのデプロイ + 環境変数設定 未着手

今後の拡張候補

  • 申請の編集・取り下げ機能
  • プッシュ通知(承認/差し戻し通知)
  • 経費カテゴリの追加・カスタマイズ
  • 月次集計ダッシュボード
  • 複数拠点対応(department別フィルタ)

11. Git / リポジトリ情報

  • パス: C:\Users\kawag\work\nurse-expense-app\
  • コミット: 1件(5a1818f Initial commit from Create Next App
  • 全コードが初期コミットに含まれている状態