メインコンテンツまでスキップ

【実装】ファイル配布サイト

概要

本記事は、安全にファイルを共有するための配布サイトを Cloudflare 上に実装した記録です。Workers / D1 / R2 を使い、実装作業は Codex のみで進めました。1

実装背景

  • ファイルを安全に共有するためのサイトを作る
  • 実装は Codex のみで進める
  • Cloudflare を活用し、公開経路、データ保存、認証まわりの基盤をまとめる

実装メモ

以下は、Codex の実装メモ report.txt をそのまま掲載したものです。

+----------------------------------------------------------------------------------+
|                            実装過程 第三者向け報告書                             |
|                     resource.area11.org / resource-portal                        |
|                          作成日: 2026-03-21 (JST)                                |
+----------------------------------------------------------------------------------+

  [文書の位置づけ]
  -------------------------------------------------------------------------------
  本書は、当該リポジトリに対して実施した実装作業の経緯、判断、成果物、発生した
  問題、修正内容、現在の到達点を、第三者が後から追跡できるように整理した報告書
  である。

  本書は説明用成果物であり、ユーザー要請によりコミット対象には含めていない。


+----------------------------------------------------------------------------------+
| 1. 対象システムの概要                                                            |
+----------------------------------------------------------------------------------+

  システム種別:
    - 一時認証型ダウンロードポータル Web アプリ

  想定利用形態:
    - 管理者が配布案件を登録
    - 利用者が ID / Pass / Pass2 で認証
    - 認証通過後に一時配布ファイルをダウンロード

  公開ドメイン:
    - resource.area11.org

  実行基盤:
    - Cloudflare Workers
    - Cloudflare D1
    - Cloudflare R2

  リポジトリ管理:
    - GitHub
    - Repository: https://github.com/UOToneg/resource


+----------------------------------------------------------------------------------+
| 2. 初期条件                                                                      |
+----------------------------------------------------------------------------------+

  実装開始時の前提:
    - リポジトリには仕様書のみが存在
    - GitHub リポジトリは未作成
    - Cloudflare アカウントは既存
    - 独自ドメインは取得済み
    - サブドメインとして resource.area11.org を利用予定

  初期状態の制約:
    - 実装コードなし
    - 運用手順なし
    - 自動テストなし
    - CI なし
    - Cloudflare 実リソース未反映


+----------------------------------------------------------------------------------+
| 3. 進行方針                                                                      |
+----------------------------------------------------------------------------------+

  実装全体で採用した方針:
    1) 仕様書と実装済みドキュメントを分離する
    2) ファーストコミット可能な最小構成を先に作る
    3) Cloudflare 実リソースに接続しながら、運用用 CLI まで含めて整備する
    4) ローカル手作業に依存しないよう、案件登録と公開停止を CLI 化する
    5) 実装済み範囲に対応する文書を都度更新する
    6) 問題発生時は再現、原因特定、修正、再検証までを一体で行う

  ドキュメントの整理方針:
    - docs/planning
      仕様、計画、設計など未実装要素
    - docs/implemented
      実装済みの運用情報、構成情報、マニュアル


+----------------------------------------------------------------------------------+
| 4. 実装フェーズの全体像                                                          |
+----------------------------------------------------------------------------------+

  Phase 1:
    - リポジトリ初期整備
    - 仕様書 / 計画書 / 実装済み文書の分離
    - Workers プロジェクト骨格作成

  Phase 2:
    - Worker 本体実装
    - D1 schema 実装
    - R2 ダウンロード経路実装

  Phase 3:
    - GitHub リポジトリ作成と push
    - Cloudflare 認証、リソース作成、カスタムドメイン反映

  Phase 4:
    - 管理 CLI 初版実装
    - create-case / open-site / close-site / maintenance-site / status

  Phase 5:
    - 対話中断対策
    - pending 復旧
    - 実ファイルを使った本番相当テスト
    - 不具合修正

  Phase 6:
    - 認証失敗ロック
    - IP 単位 rate limit
    - CLI 拡張
    - 自動テスト
    - GitHub Actions CI


+----------------------------------------------------------------------------------+
| 5. フェーズ別の詳細実施内容                                                      |
+----------------------------------------------------------------------------------+

  [5.1 リポジトリ初期整備]
  -------------------------------------------------------------------------------
    - Git 初期化を実施
    - Workers 用の package.json, tsconfig.json, wrangler.toml を追加
    - docs/planning と docs/implemented のディレクトリ構成を整理
    - 仕様書と計画書を planning 配下へ移動
    - 実装済み範囲を記録する implemented 文書を追加

  [5.2 Worker 本体実装]
  -------------------------------------------------------------------------------
    実装した主機能:
      - SITE_MODE による早期返却
      - 入口画面
      - 認証画面
      - ダウンロード画面
      - ID / Pass / Pass2 認証
      - 短命セッション Cookie
      - D1 による案件管理
      - R2 による非公開ファイル配布
      - ダウンロード時のみ回数減算
      - 監査ログ記録

    実装したルート:
      - GET /
      - POST /auth
      - POST /verify
      - GET /download
      - POST /download

  [5.3 D1 / R2 / Cloudflare 実環境反映]
  -------------------------------------------------------------------------------
    作成または反映した実リソース:
      - Worker: resource-portal
      - D1: resource-portal-db
      - R2: resource-portal-files
      - R2 Preview: resource-portal-files-preview
      - Custom Domain: resource.area11.org

    実施事項:
      - wrangler 認証
      - Worker secret 登録
      - D1 migration 適用
      - Worker deploy
      - Custom Domain 応答確認

  [5.4 管理 CLI 初版]
  -------------------------------------------------------------------------------
    実装した初期コマンド:
      - create-case
      - open-site
      - close-site
      - maintenance-site
      - status

    create-case の責務:
      - 配布元ファイルまたはディレクトリ指定
      - tar 化
      - OpenSSL 暗号化
      - SHA-256 算出
      - D1 仮登録
      - R2 upload
      - D1 有効化
      - 管理者向けログ生成
      - 受領者向け復号メモ生成

  [5.5 対話中断対策と運用補強]
  -------------------------------------------------------------------------------
    採用した考え方:
      - 途中中断時に危険な公開状態を残さない
      - 復旧または cleanup できる情報だけを残す

    実装した対策:
      - ops/pending に途中状態を保存
      - D1 仮登録は is_enabled=0
      - temp file は中断時 cleanup
      - 平文 Pass / Pass2 / 復号 passphrase は永続化しない

    追加したコマンド:
      - resume-case
      - cleanup-pending

  [5.6 本番相当テストの実施]
  -------------------------------------------------------------------------------
    実施内容:
      - 実ファイルとして README.md を使用
      - テスト案件 CASE20260321A1 を作成
      - site_mode を on に切替
      - ブラウザから認証、ダウンロード、復号、展開、README 内容確認を実施

    検証結果:
      - 認証は成功
      - 初回のダウンロードは失敗
      - 原因調査を実施
      - 修正後、ダウンロード成功
      - 復号と展開成功
      - テスト案件は cleanup 済み

  [5.7 追加の運用 CLI 拡張]
  -------------------------------------------------------------------------------
    後続で追加したコマンド:
      - disable-case
      - delete-file
      - verify-case
      - list-cases
      - show-case
      - show-audit

    追加した改善:
      - ops/summaries へ .txt と .md の両方を出力
      - verify-case で D1 / R2 整合確認
      - show-audit で監査ログ確認を容易化

  [5.8 認証ガードの追加]
  -------------------------------------------------------------------------------
    Worker 側へ追加した防御:
      - 同一 IP の認証試行数に基づく rate limit
      - 同一 IP / 同一 public_id の連続失敗に基づく一時ロック

    現在の閾値:
      - 10 分で 20 回以上の認証試行 -> 429
      - 15 分で 5 回以上の invalid_credentials -> 423

    補足:
      - 判定には download_audit の client_ip_hash を利用
      - 判定用 index を追加 migration で適用

  [5.9 テストと CI の追加]
  -------------------------------------------------------------------------------
    自動テスト:
      - Node 標準 test runner を採用
      - item-state
      - auth-service
      - download-service
      - request-guard-service

    CI:
      - GitHub Actions を追加
      - npm ci
      - npm run check
      - npm test


+----------------------------------------------------------------------------------+
| 6. 実装中に発生した主要な問題と対処                                              |
+----------------------------------------------------------------------------------+

  [問題 1]
  -------------------------------------------------------------------------------
    事象:
      - open-site 実行時の deploy で
        "The entry-point file at src/index.ts was not found" が発生

    原因:
      - 一時生成した wrangler 設定ファイルを temp directory に置いていた
      - wrangler が config 基準で相対 path を解決するため main = src/index.ts が壊れた

    対処:
      - 一時設定ファイルを repo 直下へ生成する方式へ変更

    対応コミット:
      - 4823717 Fix wrangler temp config path handling

  [問題 2]
  -------------------------------------------------------------------------------
    事象:
      - 認証成功後の POST /download で
        "現在ファイルを取得できません。管理者へ確認してください。" が表示

    原因:
      - 管理 CLI の R2 操作が local resource を向いていた
      - D1 は production、R2 は local という不整合が発生
      - Worker から見る production R2 に object が存在しなかった

    調査方法:
      - download_audit で missing_object を確認
      - D1 row の存在確認
      - wrangler r2 object get --remote で production 側 object 不在を確認

    対処:
      - R2 put / delete / get を remote 指定に統一
      - production R2 へ object を再投入
      - curl により HTTP 200 と hash 一致を確認

    対応コミット:
      - bfa0b2c Use remote R2 operations in admin CLI

  [問題 3]
  -------------------------------------------------------------------------------
    事象:
      - ops/cases/*.json をブラウザで直接開くと日本語が文字化けするケースがあった

    原因:
      - JSON ファイル自体には charset 指定を持てない
      - file:// 表示時のエンコーディング推定に依存していた

    対処:
      - JSON を UTF-8 BOM 付きで保存
      - 読込側は BOM を除去して処理

    対応コミット:
      - 90efc23 Harden ops file encoding and site mode config

  [問題 4]
  -------------------------------------------------------------------------------
    事象:
      - close-site 実行時に
        "wrangler.toml から SITE_MODE を置換できませんでした。" が発生

    原因:
      - 元の wrangler.toml が既に SITE_MODE=off のため
        置換後文字列が差分なしとなり、異常扱いしていた

    対処:
      - 置換前にキー存在だけ確認し、値が同じでも一時 config を生成するよう修正

    対応コミット:
      - 90efc23 Harden ops file encoding and site mode config


+----------------------------------------------------------------------------------+
| 7. 実施した検証                                                                  |
+----------------------------------------------------------------------------------+

  [静的確認]
  -------------------------------------------------------------------------------
    - node --check scripts/admin.mjs
    - npm run check

  [自動テスト]
  -------------------------------------------------------------------------------
    - npm test
    - 結果: 11 件 pass / 0 fail

  [Cloudflare / CLI 確認]
  -------------------------------------------------------------------------------
    - npm run admin -- status
    - npm run admin -- create-case --dry-run
    - npm run admin -- open-site --dry-run
    - npm run admin -- resume-case --dry-run
    - npm run admin -- list-cases
    - npm run admin -- verify-case

  [本番相当動作確認]
  -------------------------------------------------------------------------------
    - 実案件作成
    - site_mode on への切替
    - ブラウザ認証
    - ダウンロード
    - 復号
    - 展開
    - テスト案件 cleanup
    - site_mode off への復帰


+----------------------------------------------------------------------------------+
| 8. コミット履歴                                                                  |
+----------------------------------------------------------------------------------+

  85f0074
    - Initial commit

  b125ed7
    - Add admin CLI and deployment docs
    - 管理 CLI 初版と Cloudflare 構築関連ドキュメントの追加

  4823717
    - Fix wrangler temp config path handling
    - 一時 wrangler 設定ファイルの配置不備修正

  bfa0b2c
    - Use remote R2 operations in admin CLI
    - R2 local/remote 不整合の修正

  90efc23
    - Harden ops file encoding and site mode config
    - ops JSON の BOM 対応
    - SITE_MODE 同値時の temp config 生成修正

  2597940
    - Add auth guards, admin tools, and CI
    - 認証ガード、CLI 拡張、自動テスト、CI、関連文書更新


+----------------------------------------------------------------------------------+
| 9. 現在の成果物                                                                  |
+----------------------------------------------------------------------------------+

  ソースコード:
    - Worker 本体
    - D1 migration
    - 管理 CLI
    - ハッシュ、暗号化、Cloudflare 操作用補助モジュール

  ドキュメント:
    - README
    - 実装済み範囲
    - 管理 CLI 文書
    - Cloudflare 構築状況
    - 管理者向け運用マニュアル
    - 仕様書
    - 実装計画書
    - 対話型スクリプト設計書

  テスト / CI:
    - Node 標準テスト
    - GitHub Actions CI


+----------------------------------------------------------------------------------+
| 10. 現在のシステム状態                                                           |
+----------------------------------------------------------------------------------+

  Git 状態:
    - branch: main
    - local / origin: 同期済み
    - worktree: clean

  Cloudflare 状態:
    - Worker deploy: 済み
    - D1 migration: 0001, 0002 適用済み
    - Custom Domain: 設定済み
    - site_mode(local): off
    - site_mode(live): off
    - pending(local): 0

  セキュリティ関連状態:
    - PEPPER 設定済み
    - TOKEN_SECRET 設定済み
    - 認証失敗ロック有効
    - 認証 rate limit 有効

  テスト案件:
    - 作成、実験、cleanup 済み
    - 本番環境に当該テスト案件の D1 row / audit / R2 object は残していない


+----------------------------------------------------------------------------------+
| 11. 現時点で未実装の項目                                                         |
+----------------------------------------------------------------------------------+

  現在の未実装事項:
    - ダウンロード系の IP rate limit
    - ブラウザ E2E テスト
    - ops/cases と remote D1 の双方向同期

  補足:
    - いずれも MVP 運用を阻害するものではない
    - ただし継続運用上は次段階の改善対象となる


+----------------------------------------------------------------------------------+
| 12. 第三者への引継ぎ観点                                                         |
+----------------------------------------------------------------------------------+

  引継ぎ時に重要な理解ポイント:
    1) 本システムは「常時公開」ではなく「必要時のみ公開」が前提
    2) 管理操作の主入口は scripts/admin.mjs である
    3) create-case 後に verify-case を実行する運用が推奨である
    4) 公開前に open-site、終了後に close-site を実行する
    5) 障害時は show-audit, disable-case, delete-file の順で切り分け可能

  引継ぎ後にまず確認すべき資料:
    - README.md
    - docs/implemented/manual.txt
    - docs/implemented/管理CLI.md
    - docs/implemented/Cloudflare構築状況.md
    - docs/implemented/実装済み範囲.md


+----------------------------------------------------------------------------------+
| 13. 総括                                                                          |
+----------------------------------------------------------------------------------+

  当初は仕様書のみの状態から開始し、以下を一体で整備した。

    - Worker 実装
    - Cloudflare 実環境反映
    - GitHub リポジトリ運用
    - 管理 CLI
    - 運用文書
    - 実案件による本番相当検証
    - 問題発生時の原因調査と修正
    - 自動テスト
    - CI

  現在の段階では、MVP としての公開運用に必要な機能と運用導線は揃っている。
  一方で、長期運用の観点では、E2E テストやダウンロード系 rate limit など、
  次段階で着手すべき改善余地も残っている。

  総合評価:
    - 初期要件に対して、実装、運用、検証、文書化までを含めて完了済み
    - 実運用開始可能な水準
    - 改善余地は残るが、現時点の構成は十分に引継ぎ可能


+----------------------------------------------------------------------------------+
| End of Report                                                                    |
+----------------------------------------------------------------------------------+

参考資料(出典)

Footnotes

  1. 内部資料, Codex実装メモ report.txt(2026-03-21作成)。resource.area11.org / resource-portal の実装過程を整理した報告書。