# TeamWorks 様 ご依頼: ステージングサーバーへの D-Watch の設置

**作成: 2026-10-07 / 作成者: DFA Robotics**

いつもお世話になっております。
弊社で開発中の監視画面（D-Watch）を、貴社に構築・保守をお願いしているステージングサーバーに、Docker のコンテナとして設置していただきたく、ご依頼申し上げます。本書だけで作業いただけるよう、必要なものと注意点をまとめました。
選択肢（A / B / C …）のある設問は、**記号だけでご回答いただければ結構です**。設問とお願いの一覧は10章にございます。

# 1. 依頼の概要

| 項目 | 内容 |
|---|---|
| 何を | D-Watch（Next.js 16 で作った Web アプリ。画面と API が1つのアプリ） |
| どこへ・どう | 既にご用意いただいているステージングサーバーで、Docker のコンテナ1つとして動かす。前段に nginx 等を置き、社外から HTTPS で閲覧できるようにする |
| 接続するDB | 現在のステージングDB（貴社で運用中のもの。新たな構築は不要です） |
| 載せる版 | 弊社 GitHub リポジトリの `develop` ブランチ、2026-10-07 時点の最新コミット `425bd96` |
| 認証 | 共有の合言葉（`AUTH_TOKEN`）によるログインのみ（9章） |

目的は、弊社の関係者が社外からも実データで画面を確認できるようにすることです（本番の公開ではなく、検証のための一時的な運用です）。
`425bd96` より後のコミットは文書の更新だけですので、`develop` の最新でも構いません。

# 2. 必要なもの

| 項目 | 内容 |
|---|---|
| Docker | Docker と Docker Compose（またはそれに準ずるもの） |
| イメージ | `npm ci` → `npx prisma generate` → `npm run build` でビルドし、`npm run start` で起動（`NODE_ENV=production` になります） |
| 待ち受けポート | コンテナの 3000 |
| 再起動 | 停止したときに自動で再起動する設定（`restart: unless-stopped` 等） |

`npm run seed:local` は弊社の開発用です。**実行しないでください。**

# 3. Docker で動かすときの注意点

- **ベースイメージ**: Node.js 22.12 以上が必要です（Prisma 7 の要件）。`node:24-slim`（Debian 系）をおすすめします。alpine（musl）は、sharp 等のネイティブモジュールでつまずくことがあるため避けてください。
- **`npx prisma generate` はイメージのビルドの中で実行してください。** 生成物はリポジトリに含めておらず、`npm ci` でも作られないため、省くとビルドが失敗します。
- **`.env.local` をイメージに入れないでください。** レイヤーに資格情報が残ります。環境変数は起動時に `env_file` / `environment` で渡してください。`.dockerignore` では `.env*`・`node_modules`・`.next`・`data` を除いてください。
- **環境変数はビルド時ではなく起動時に読まれます。** 1つのイメージを、環境変数だけ変えて使えます（サンプルデータの設定でビルドしたものを `USE_FIXTURES=false` で起動し、ステージングDBのデータが出ることを弊社で確認済みです）。環境変数を変えたときは、コンテナの再起動だけで結構です。
- **`data/settings/` は永続ボリュームとして、ディレクトリごとマウントしてください。** ファイル1つずつのバインドマウントは使えません（保存のとき、一時ファイルに書いてから名前を変えて置き換えるため、失敗します）。コンテナを実行するユーザーが、そこに書き込めるようにしてください。画面から変更する運用設定（アドバイス文・表示件数・D-Sデバイスのメモ）を保存しており、作り直しても消えないようにする必要があります。
- **ポートは `127.0.0.1:3000:3000` で公開してください。** `3000:3000` にすると、Docker が公開したポートは ufw 等のファイアウォールを通らないため、3000 番がインターネットに開いてしまいます。
- **nginx の前後に別のプロキシ（Traefik 等）を挟む場合は、お知らせください。** 将来 IP 制限を入れるときの設定（プロキシの段数）に関わります。その場合も `X-Forwarded-For` は追記にしてください（6章）。
- **`npm run check:env`（4章）は tsx（開発用の依存）を使います。** 開発用の依存を省いたイメージでは動きませんので、ビルド段階のイメージ等、開発用の依存が残っているもので実行してください。
- **ログ**は標準出力に1行1件の JSON で出します（`docker logs` で見られます）。ローテーション（`max-size` / `max-file` 等）を設定してください。
- **ビルドにはメモリが 1〜2GB ほど要る見込みです**（目安です。測定はしておりません）。
- **コンテナのタイムゾーンは UTC のままで結構です**（アプリの中で日本時間に換算しております）。

### Q1. Dockerfile と compose ファイルは、どちらが用意しますか

いまのリポジトリには、Dockerfile・compose ファイル・`.dockerignore` はございません。

| 選択肢 | 内容 |
|---|---|
| A | 弊社がリポジトリに用意し、貴社はそれを使って起動する |
| B | 貴社が作成する（上の注意点を織り込んでいただく） |
| C | その他（お教えください） |

# 4. 環境変数

起動時にコンテナへ渡してください（3章）。**値は本書には書いておりません。** 合言葉は5章、DB の接続情報は貴社でお持ちのものをお使いください。

| 変数 | 設定 | 説明 |
|---|---|---|
| `USE_FIXTURES` | `false` | 未設定だと、DB に接続せず弊社のサンプルデータ（架空の施設）のまま動きます（エラーは出ません） |
| `DATABASE_URL` | 参照用アカウントの接続URL | 必須です。`mysql://ユーザー:パスワード@ホスト:ポート/DB名` の形です |
| `DATABASE_HOST` / `DATABASE_PORT` / `DATABASE_NAME` | 現在のステージングDBの値 | 更新用アカウントを使うときに必要です（接続先は参照用と同じDB） |
| `DATABASE_USER` / `DATABASE_PASSWORD` | 参照用アカウント（任意） | `DATABASE_HOST` と一緒に設定すると、接続には `DATABASE_URL` よりこちらが優先されます（下の注記） |
| `DATABASE_WRITE_USER` / `DATABASE_WRITE_PASSWORD` | 更新用アカウント | 下の注記をご覧ください。**2つとも設定するか、2つとも空にしてください** |
| `AUTH_TOKEN` | 新しい合言葉 | 5章 |
| `LOG_LEVEL` | `info` | なお `NODE_ENV` は設定不要です（`npm run start` が `production` にします） |
| `ALLOW_DIRECT_ACCESS` | **設定しないでください** | 開発用のスイッチです。設定すると検査（下記）がエラーにします |

- **`DATABASE_URL` のパスワードに `%` や `@` が含まれる場合は、URL エンコードが必要です**（`@` は `%40`、`%` は `%25`）。`@` を含む場合は `DATABASE_USER` / `DATABASE_PASSWORD` の併用をおすすめします（URL がうまく読めなかった例がございます。`DATABASE_URL` も検査のために設定してください）。
- 更新用アカウントについて: アプリが DB に書き込むのは、対応状況を記録する4カラム（`status` / `comment` / `responded_at` / `resolved_at`）だけです。更新用アカウントの権限（`robot_error_reports` と `control_error_histories` のこの4カラム）の範囲内で、現時点では `robot_error_reports` だけです。2つとも空なら参照用アカウントで書き込むため、その権限が無いと対応状況の保存だけが失敗します（閲覧には影響しません）。
- 設定したら、**同じ環境変数で `NODE_ENV=production npm run check:env` を実行してください**（3章の tsx の注意をご覧ください）。`ERROR` が1件も無く、`USE_FIXTURES` の `WARN` が出ないことをご確認ください（`NODE_ENV=production` を付けないと「開発機」として検査され、`USE_FIXTURES` を確認しません）。この検査は値を出力しませんので、結果をそのままお送りいただけます。

# 5. 合言葉（AUTH_TOKEN）

ログインに使う共有の合言葉です。**開発用とは別の、32文字以上の乱数**にしてください（総当たりで当たらない長さにするためです）。
**URL と同じメールやチャットで送らないでください。** URL と合言葉が一緒に漏れると、誰でもログインできてしまうためです。

### Q2. 合言葉は、どちらで作成しますか

| 選択肢 | 内容 |
|---|---|
| A | 弊社が作成し、安全な方法（パスワード付きのファイルを別便で送る等）で貴社にお渡しする |
| B | 貴社が作成して環境変数に設定し、安全な方法で弊社にお知らせいただく |

# 6. 公開まわり

| 項目 | お願い |
|---|---|
| HTTPS | **必須です。** ログインの cookie に `Secure` 属性を付けているため、HTTP だけではログインできません。HTTP へのアクセスは HTTPS へ転送してください |
| リバースプロキシ | nginx 等で受けて、`127.0.0.1:3000` へ転送してください |
| `X-Forwarded-For` | **上書きではなく追記**にしてください（下の設定例）。アプリは末尾の値を接続元とみなします |
| ポート3000 | **外から直接届かないようにしてください**（3章の `127.0.0.1:3000:3000`） |
| セキュリティヘッダ | アプリでは付けておりません。プロキシ側で `X-Content-Type-Options: nosniff` / `Referrer-Policy: same-origin` / `X-Frame-Options: DENY` をお願いいたします。**CSP は付けないでください**（画面が壊れるおそれがあります） |
| DB への接続 | コンテナから現在のステージングDBへ接続できるようにしてください（サーバーが別の場合、DB 側で接続元の許可が要るかもしれません） |

設定例（nginx。証明書の設定は省いております）:

```
location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}
```

### Q3. 公開に使う URL（ドメイン）と証明書は、どのようにされますか

| 選択肢 | 内容 |
|---|---|
| A | 既にあるドメイン・証明書で公開できる |
| B | 新たにドメインや証明書の用意が必要（費用が発生する場合は、事前にお知らせください） |
| C | その他（お教えください） |

# 7. リポジトリの取得方法

### Q4. アプリのコードは、どの方法で取得されますか

| 選択肢 | 内容 |
|---|---|
| A | 弊社の GitHub リポジトリ（非公開）の読み取り権限を、貴社のアカウントまたはデプロイキーにお付けする（GitHub のアカウント名、またはデプロイキーの公開鍵をお知らせください） |
| B | 弊社がコミット `425bd96` のソース一式をアーカイブにしてお渡しする（イメージのビルドは貴社で行う） |
| C | その他（お教えください） |

# 8. 動作確認のお願いとご連絡

1. ブラウザで公開URLを開き、ログイン画面が出ることを確認する。
2. 合言葉でログインし、ダッシュボードが表示されることを確認する。
3. 「施設ロボットマスタ」画面に、ステージングDBの施設（店舗と本社）が出ることを確認する。
4. 社外から `http://（サーバーのアドレス）:3000` に直接つながらないことを確認する。

起動の目安は、ログの `app.start` の1行です。対応状況の保存（DB への書き込み）は実データが書き換わりますので、弊社で確認いたします。

作業が終わりましたら、公開URLと完了のご連絡（`check:env` の結果を添えて）をお願いいたします。エラーがあった場合は、その内容とログの抜粋をお送りください（ログに合言葉やパスワードは出ない作りですが、念のためご確認ください）。

# 9. ご承知おきいただきたいこと

- 今回は**検証のための一時的な運用**で、認証は共有の合言葉だけです。接続元の IP 制限も、ログインの試行回数の制限もまだございませんが、弊社で承知のうえでの判断です。
- リリース前に、接続元の制限（またはそれに代わる守り）と試行回数の制限を弊社で追加し、DB の接続元の制限や暗号化も貴社にご相談いたします。
- `develop` は開発に合わせて更新されますので、今後も何度か載せ替え（再設置）をお願いすることになります。

### Q5. 載せ替え（再設置）は、どのようにご依頼すればよろしいでしょうか

| 選択肢 | 内容 |
|---|---|
| A | 弊社がコミット番号をメール等でお知らせし、貴社でそのコミットからイメージを作り直してコンテナを再起動していただく |
| B | 弊社に更新作業用の権限をいただき、弊社で実施する（手順書は弊社でご用意します） |
| C | その他（お教えください） |

# 10. ご回答のお願い

| 番号 | 内容 | ご回答 |
|---|---|---|
| Q1 | Dockerfile と compose ファイルの用意 | A / B / C |
| Q2 | 合言葉の作成 | A / B |
| Q3 | 公開URL（ドメイン）と証明書 | A / B / C |
| Q4 | コードの取得方法 | A / B / C |
| Q5 | 載せ替えの依頼方法 | A / B / C |
| お願い1 | `data/settings/` の永続ボリューム・HTTPS・`X-Forwarded-For` の追記・ポートを `127.0.0.1` だけで公開（3章・6章） | 承知 / 難しい |
| お願い2 | 作業のご予定 | 完了の見込み日 |

**以上です。ご確認のほど、よろしくお願いいたします。**
