diff --git a/apps/reminder-worker/src/index.ts b/apps/reminder-worker/src/index.ts index a1092a0..295ba72 100644 --- a/apps/reminder-worker/src/index.ts +++ b/apps/reminder-worker/src/index.ts @@ -15,7 +15,7 @@ interface Env { APP_URL: string } -const NOTIFICATION_QUEUE = 'todo-notifications' +const NOTIFICATION_QUEUE = 'kanban-notifications' const RETRY_DELAY_SECONDS = 60 export default { diff --git a/apps/reminder-worker/wrangler.jsonc b/apps/reminder-worker/wrangler.jsonc index 30995e6..24024e4 100644 --- a/apps/reminder-worker/wrangler.jsonc +++ b/apps/reminder-worker/wrangler.jsonc @@ -1,6 +1,6 @@ { "$schema": "../../node_modules/wrangler/config-schema.json", - "name": "todo-reminder-worker", + "name": "kanban-reminder-worker", "main": "src/index.ts", "compatibility_date": "2026-01-01", "vars": { @@ -14,7 +14,7 @@ "d1_databases": [ { "binding": "DB", - "database_name": "todo-db", + "database_name": "kanban-db", "database_id": "replace-with-production-database-id", "migrations_dir": "../../packages/db/migrations", }, @@ -23,22 +23,22 @@ "producers": [ { "binding": "REMINDER_QUEUE", - "queue": "todo-reminders", + "queue": "kanban-reminders", }, ], "consumers": [ { - "queue": "todo-reminders", + "queue": "kanban-reminders", "max_batch_size": 10, "max_retries": 3, // A mail that still fails after its retries is kept here instead of being dropped. - "dead_letter_queue": "todo-mail-dead-letter", + "dead_letter_queue": "kanban-mail-dead-letter", }, { - "queue": "todo-notifications", + "queue": "kanban-notifications", "max_batch_size": 10, "max_retries": 3, - "dead_letter_queue": "todo-mail-dead-letter", + "dead_letter_queue": "kanban-mail-dead-letter", }, ], }, diff --git a/apps/web/wrangler.jsonc b/apps/web/wrangler.jsonc index ef49c83..4b77f8d 100644 --- a/apps/web/wrangler.jsonc +++ b/apps/web/wrangler.jsonc @@ -1,6 +1,6 @@ { "$schema": "../../node_modules/wrangler/config-schema.json", - "name": "todo-web", + "name": "kanban-web", "main": "dist/server/server.js", "compatibility_date": "2026-01-01", "compatibility_flags": ["nodejs_compat"], @@ -11,7 +11,7 @@ "d1_databases": [ { "binding": "DB", - "database_name": "todo-db", + "database_name": "kanban-db", "database_id": "replace-with-production-database-id", "migrations_dir": "../../packages/db/migrations", }, @@ -19,7 +19,7 @@ "r2_buckets": [ { "binding": "FILES", - "bucket_name": "todo-files", + "bucket_name": "kanban-files", }, ], "queues": { @@ -27,7 +27,7 @@ "producers": [ { "binding": "NOTIFICATION_QUEUE", - "queue": "todo-notifications", + "queue": "kanban-notifications", }, ], }, @@ -51,11 +51,11 @@ // not inherited by an environment, so each one is written out again. See docs/deploy.md. "env": { "preview": { - "name": "todo-web-preview", + "name": "kanban-web-preview", "d1_databases": [ { "binding": "DB", - "database_name": "todo-db-preview", + "database_name": "kanban-db-preview", "database_id": "replace-with-preview-database-id", "migrations_dir": "../../packages/db/migrations", }, @@ -63,14 +63,14 @@ "r2_buckets": [ { "binding": "FILES", - "bucket_name": "todo-files-preview", + "bucket_name": "kanban-files-preview", }, ], "queues": { "producers": [ { "binding": "NOTIFICATION_QUEUE", - "queue": "todo-notifications-preview", + "queue": "kanban-notifications-preview", }, ], }, diff --git a/docs/architecture.md b/docs/architecture.md index f740c69..5c78608 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -4,20 +4,20 @@ Cloudflare 上で動く Web アプリ (TanStack Start) と、メール送信用のワーカー (リマインド、共有の通知) の 2 つの Worker で構成する。ブランチや PR の動作確認用に、Web アプリのプレビュー用の Worker もある ([デプロイとプレビュー](deploy.md))。 -図は大まかなもので、共有の通知用のキュー (`todo-notifications`) などは描いていない。 +図は大まかなもので、共有の通知用のキュー (`kanban-notifications`) などは描いていない。 ## コンポーネント -| コンポーネント | 役割 | 状態 | -| -------------------------------- | -------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | -| Workers (`apps/web`) | 画面、タスク API、認証 | 実装済み → [Web アプリ仕様](web-app.md) | -| Workers (`apps/reminder-worker`) | cron で起動してリマインドを Queues に積み、リマインドと共有の通知のメールを送る | 実装済み。送信の設定は [#8](https://github.com/tknkaa/todo-app/issues/8) → [ワーカー仕様](worker.md) | -| D1 | ユーザー、セッション、タスク (本文、順番を含む)、添付のメタデータ、共有と招待の保存 | 実装済み → [テーブル定義](database.md) | -| Cron Triggers | リマインド Worker を 15 分ごとに起動 | 実装済み | -| Queues | メールの送信キュー (リマインド用の `todo-reminders` と、共有の通知用の `todo-notifications`) | 実装済み | -| Resend | リマインドと共有の通知のメールの送信 | コードあり。API キーとドメインの設定は未了 | -| R2 | タスクのファイル添付 | 実装済み (`FILES`) → [Web アプリ仕様](web-app.md) | -| Durable Objects | 共有したタスクの変更をリアルタイムに通知 (WebSocket) | 実装済み (`COLLABORATION`) → [Web アプリ仕様](web-app.md) | +| コンポーネント | 役割 | 状態 | +| -------------------------------- | ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- | +| Workers (`apps/web`) | 画面、タスク API、認証 | 実装済み → [Web アプリ仕様](web-app.md) | +| Workers (`apps/reminder-worker`) | cron で起動してリマインドを Queues に積み、リマインドと共有の通知のメールを送る | 実装済み。送信の設定は [#8](https://github.com/tknkaa/todo-app/issues/8) → [ワーカー仕様](worker.md) | +| D1 | ユーザー、セッション、タスク (本文、順番を含む)、添付のメタデータ、共有と招待の保存 | 実装済み → [テーブル定義](database.md) | +| Cron Triggers | リマインド Worker を 15 分ごとに起動 | 実装済み | +| Queues | メールの送信キュー (リマインド用の `kanban-reminders` と、共有の通知用の `kanban-notifications`) | 実装済み | +| Resend | リマインドと共有の通知のメールの送信 | コードあり。API キーとドメインの設定は未了 | +| R2 | タスクのファイル添付 | 実装済み (`FILES`) → [Web アプリ仕様](web-app.md) | +| Durable Objects | 共有したタスクの変更をリアルタイムに通知 (WebSocket) | 実装済み (`COLLABORATION`) → [Web アプリ仕様](web-app.md) | ## リポジトリ構成 @@ -41,7 +41,7 @@ docs/ このドキュメント - **タスク操作:** ブラウザ → `apps/web` の `/api/tasks` → D1。リクエストごとにセッションを確認し、ログインしていなければ 401 を返す。 - **リアルタイム通知:** タスクの変更後、`apps/web` が、そのタスクを見られる全員の Durable Object に通知する。各ブラウザは WebSocket でつながり、通知を受けると一覧を取得し直す。 -- **共有の通知メール:** タスクを共有すると、`apps/web` が `todo-notifications` に積み、`reminder-worker` が Resend で送る。アカウントがない相手は招待として保存され、アカウントを作ると共有される。 +- **共有の通知メール:** タスクを共有すると、`apps/web` が `kanban-notifications` に積み、`reminder-worker` が Resend で送る。アカウントがない相手は招待として保存され、アカウントを作ると共有される。 - **リマインド:** Cron → `reminder-worker` が D1 から対象タスクを検索 → Queues に投入 → 同じ Worker のコンシューマが Resend でメール送信。 ## ドキュメント一覧 diff --git a/docs/database.md b/docs/database.md index 13d10cc..cfd0b26 100644 --- a/docs/database.md +++ b/docs/database.md @@ -147,4 +147,4 @@ Cloudflare D1 (SQLite)。スキーマは `packages/db/src/schema.ts` (Drizzle) just sql "select * from tasks" ``` -`just` が使えない場合は、`apps/web` で `pnpm exec wrangler d1 execute todo-db --local --persist-to .wrangler/state-drizzle-baseline --command "..."` を実行する。 +`just` が使えない場合は、`apps/web` で `pnpm exec wrangler d1 execute kanban-db --local --persist-to .wrangler/state-drizzle-baseline --command "..."` を実行する。 diff --git a/docs/deploy.md b/docs/deploy.md index 742062e..7da707d 100644 --- a/docs/deploy.md +++ b/docs/deploy.md @@ -4,13 +4,25 @@ Cloudflare にデプロイする手順。**ここに書いたことのうち、 [#3](https://github.com/tknkaa/todo-app/issues/3) で扱う。 +## 名前 + +Cloudflare のリソースの名前は、**Cloudflare のアカウントの中で一意**になる (GitHub の org ではない)。共有のアカウントで他のプロジェクトとぶつからないよう、すべての名前に `kanban-` を付けている。名前を変えるときは、`wrangler.jsonc` (2 つ)、`apps/reminder-worker/src/index.ts` (通知のキューの名前)、`package.json` と `justfile` と `e2e/start-server.sh` (D1 の名前)、この docs をそろえて直す。 + +## アカウントの指定 + +Wrangler が複数のアカウントにログインしているときは、どれを使うかを環境変数で指定する (指定しないと、対話できない場所ではエラーになる)。 + +```sh +export CLOUDFLARE_ACCOUNT_ID=<アカウント ID> # `wrangler whoami` で分かる +``` + ## 構成 -| Worker | 設定 | 役割 | -| ---------------------- | ------------------------------------------ | ------------------------------------------------------------------- | -| `todo-web` | `apps/web/wrangler.jsonc` | 画面、API | -| `todo-reminder-worker` | `apps/reminder-worker/wrangler.jsonc` | リマインドと共有の通知のメール (cron、Queues) | -| `todo-web-preview` | `apps/web/wrangler.jsonc` の `env.preview` | ブランチや PR の動作確認用。本番とは別の DB、バケット、キューを使う | +| Worker | 設定 | 役割 | +| ------------------------ | ------------------------------------------ | ------------------------------------------------------------------- | +| `kanban-web` | `apps/web/wrangler.jsonc` | 画面、API | +| `kanban-reminder-worker` | `apps/reminder-worker/wrangler.jsonc` | リマインドと共有の通知のメール (cron、Queues) | +| `kanban-web-preview` | `apps/web/wrangler.jsonc` の `env.preview` | ブランチや PR の動作確認用。本番とは別の DB、バケット、キューを使う | プレビューにはリマインド用のワーカーを置かない。cron が動いて、本番と同じようにメールを送ってしまうのを避けるため。 @@ -21,16 +33,16 @@ Wrangler にログインする (`pnpm --filter @todo/web exec wrangler login`) ```sh cd apps/web # 本番 -pnpm exec wrangler d1 create todo-db # 出てきた database_id を、下の 2 つの設定に書く -pnpm exec wrangler r2 bucket create todo-files -pnpm exec wrangler queues create todo-reminders -pnpm exec wrangler queues create todo-notifications -pnpm exec wrangler queues create todo-mail-dead-letter # 再試行しても送れなかったメールの置き場 +pnpm exec wrangler d1 create kanban-db # 出てきた database_id を、下の 2 つの設定に書く +pnpm exec wrangler r2 bucket create kanban-files +pnpm exec wrangler queues create kanban-reminders +pnpm exec wrangler queues create kanban-notifications +pnpm exec wrangler queues create kanban-mail-dead-letter # 再試行しても送れなかったメールの置き場 # プレビュー -pnpm exec wrangler d1 create todo-db-preview # database_id を apps/web/wrangler.jsonc の env.preview に書く -pnpm exec wrangler r2 bucket create todo-files-preview -pnpm exec wrangler queues create todo-notifications-preview +pnpm exec wrangler d1 create kanban-db-preview # database_id を apps/web/wrangler.jsonc の env.preview に書く +pnpm exec wrangler r2 bucket create kanban-files-preview +pnpm exec wrangler queues create kanban-notifications-preview ``` `database_id` を書く場所 (いまは `replace-with-…` になっている): @@ -68,7 +80,7 @@ pnpm exec wrangler secret put BETTER_AUTH_SECRET --env preview `BETTER_AUTH_URL` は、`wrangler.jsonc` の `vars` に書くか、ダッシュボードの Variables で設定する。 -**プレビューの URL の注意:** ログインは、`BETTER_AUTH_URL` と同じオリジンからのリクエストしか受け付けない。プレビューでログインを試すには、`https://todo-web-preview.<アカウントのサブドメイン>.workers.dev` のように、**固定の URL** を `BETTER_AUTH_URL` に設定して、その URL で開く。ブランチごとに変わるバージョンの URL (`<ハッシュ>-todo-web-preview…`) では、ログインできない。 +**プレビューの URL の注意:** ログインは、`BETTER_AUTH_URL` と同じオリジンからのリクエストしか受け付けない。プレビューでログインを試すには、`https://kanban-web-preview.<アカウントのサブドメイン>.workers.dev` のように、**固定の URL** を `BETTER_AUTH_URL` に設定して、その URL で開く。ブランチごとに変わるバージョンの URL (`<ハッシュ>-kanban-web-preview…`) では、ログインできない。 ## 4. 初回のデプロイ @@ -82,22 +94,22 @@ pnpm deploy:preview # プレビューの Web (Worker を作るため、最初 ダッシュボードの Workers & Pages で、Worker ごとに、リポジトリ (`tknkaa/todo-app`) を接続する。Worker の名前は、設定ファイルの `name` と同じにする。 -**`todo-web`** (本番とプレビューを兼ねる): +**`kanban-web`** (本番とプレビューを兼ねる): -| 設定 | 値 | -| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Root directory | `/` | -| Build command | `pnpm install --frozen-lockfile && pnpm --filter @todo/web build` | -| Deploy command (`main`) | `pnpm --filter @todo/web exec wrangler d1 migrations apply todo-db --remote && pnpm --filter @todo/web exec wrangler deploy` | -| Production branch | `main` | -| Non-production branch builds | 有効 | -| Non-production deploy command | `pnpm --filter @todo/web exec wrangler d1 migrations apply todo-db-preview --remote --env preview && pnpm --filter @todo/web exec wrangler versions upload --env preview` | -| Build watch paths | `apps/web/**`、`packages/**`、`pnpm-lock.yaml` | +| 設定 | 値 | +| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Root directory | `/` | +| Build command | `pnpm install --frozen-lockfile && pnpm --filter @todo/web build` | +| Deploy command (`main`) | `pnpm --filter @todo/web exec wrangler d1 migrations apply kanban-db --remote && pnpm --filter @todo/web exec wrangler deploy` | +| Production branch | `main` | +| Non-production branch builds | 有効 | +| Non-production deploy command | `pnpm --filter @todo/web exec wrangler d1 migrations apply kanban-db-preview --remote --env preview && pnpm --filter @todo/web exec wrangler versions upload --env preview` | +| Build watch paths | `apps/web/**`、`packages/**`、`pnpm-lock.yaml` | - `main` に入ると、本番の DB にマイグレーションを適用してから、デプロイする。 -- `main` 以外のブランチや PR は、プレビュー用の DB にマイグレーションを適用して、`todo-web-preview` の新しいバージョンとして、本番に出さずにアップロードする。ダッシュボードや PR のコメントに、そのバージョンの URL が出る (上の注意のとおり、ログインには固定の URL を使う)。 +- `main` 以外のブランチや PR は、プレビュー用の DB にマイグレーションを適用して、`kanban-web-preview` の新しいバージョンとして、本番に出さずにアップロードする。ダッシュボードや PR のコメントに、そのバージョンの URL が出る (上の注意のとおり、ログインには固定の URL を使う)。 -**`todo-reminder-worker`** (本番だけ。プレビューなし): +**`kanban-reminder-worker`** (本番だけ。プレビューなし): | 設定 | 値 | | --------------------- | ---------------------------------------------------------- | @@ -114,7 +126,7 @@ pnpm deploy:preview # プレビューの Web (Worker を作るため、最初 - [ ] 本番で、ログイン、タスクの追加、添付、共有、リアルタイムの反映が動く (WebSocket と Durable Objects は、本番の設定で初めて確かめる) - [ ] リマインドの cron が動く (ダッシュボードの Triggers で、実行の履歴を見る) - [ ] メールが届く ([ワーカー仕様](worker.md) の「未了」) -- [ ] デッドレターキュー (`todo-mail-dead-letter`) に、送れなかったメールが溜まっていない +- [ ] デッドレターキュー (`kanban-mail-dead-letter`) に、送れなかったメールが溜まっていない ## 設定を変えたとき diff --git a/docs/worker.md b/docs/worker.md index fa837ac..f90beaa 100644 --- a/docs/worker.md +++ b/docs/worker.md @@ -6,13 +6,13 @@ ## ハンドラ -| ハンドラ | 起動 | 内容 | -| ----------- | ----------------------------- | ----------------------------------------------- | -| `scheduled` | Cron Triggers (15 分ごと) | リマインドの対象のタスクを探して、Queues に積む | -| `queue` | Queues (`todo-reminders`) | リマインドのメールを送る | -| `queue` | Queues (`todo-notifications`) | タスクを共有したときのメールを送る | +| ハンドラ | 起動 | 内容 | +| ----------- | ------------------------------- | ----------------------------------------------- | +| `scheduled` | Cron Triggers (15 分ごと) | リマインドの対象のタスクを探して、Queues に積む | +| `queue` | Queues (`kanban-reminders`) | リマインドのメールを送る | +| `queue` | Queues (`kanban-notifications`) | タスクを共有したときのメールを送る | -cron と Queues の設定は `wrangler.jsonc` (`triggers.crons`、`queues`)。`todo-notifications` には、`apps/web` がタスクを共有したときにメッセージを積む。 +cron と Queues の設定は `wrangler.jsonc` (`triggers.crons`、`queues`)。`kanban-notifications` には、`apps/web` がタスクを共有したときにメッセージを積む。 ## リマインドの流れ @@ -43,7 +43,7 @@ cron と Queues の設定は `wrangler.jsonc` (`triggers.crons`、`queues`)。`t - 締め切りかリマインドの設定を変えると `reminder_queued_at` を空に戻し、新しい設定でもう一度リマインドする。 - cron は 15 分ごとなので、実際の送信は設定した時刻から最大 15 分遅れる。 - リマインドの宛先はタスクの所有者だけ。共有された人には送らない。 -- メールの送信が失敗したら、そのメッセージだけを 60 秒後にもう一度試す (最大 3 回。Queues の設定)。うまくいったメッセージは、同じバッチの中でも先に完了させる。それでも送れなかったメッセージは、捨てずにデッドレターキュー (`todo-mail-dead-letter`) に残る。溜まっていないかを、ダッシュボードで見る。 +- メールの送信が失敗したら、そのメッセージだけを 60 秒後にもう一度試す (最大 3 回。Queues の設定)。うまくいったメッセージは、同じバッチの中でも先に完了させる。それでも送れなかったメッセージは、捨てずにデッドレターキュー (`kanban-mail-dead-letter`) に残る。溜まっていないかを、ダッシュボードで見る。 - `RESEND_API_KEY` がないとき、ローカル (`APP_URL` が localhost) だけは、メールを送らずに宛先と件名をログに出す。それ以外 (本番) ではエラーにして、再試行とデッドレターキューに回す。黙って送らないと、メールが失われるのに送信済みになってしまうため。 ## 設定 diff --git a/e2e/start-server.sh b/e2e/start-server.sh index 28fe1db..477bf79 100755 --- a/e2e/start-server.sh +++ b/e2e/start-server.sh @@ -9,7 +9,7 @@ PORT=8788 rm -rf "$STATE" pnpm --filter @todo/web build -pnpm --filter @todo/web exec wrangler d1 migrations apply todo-db --local --persist-to "../../$STATE" +pnpm --filter @todo/web exec wrangler d1 migrations apply kanban-db --local --persist-to "../../$STATE" exec pnpm --filter @todo/web exec wrangler dev --local --port "$PORT" --persist-to "../../$STATE" \ --var BETTER_AUTH_SECRET:e2e-secret-e2e-secret-e2e-secret-1234 \ --var BETTER_AUTH_URL:"http://localhost:$PORT" diff --git a/justfile b/justfile index 50d0377..a42883a 100644 --- a/justfile +++ b/justfile @@ -3,4 +3,4 @@ state := ".wrangler/state-drizzle-baseline" # ローカル D1 に SQL を実行する: just sql "select * from tasks" sql query: - cd apps/web && pnpm exec wrangler d1 execute todo-db --local --persist-to {{state}} --command "{{query}}" + cd apps/web && pnpm exec wrangler d1 execute kanban-db --local --persist-to {{state}} --command "{{query}}" diff --git a/package.json b/package.json index 1c38eaa..3d7adfa 100644 --- a/package.json +++ b/package.json @@ -11,10 +11,10 @@ "test": "pnpm -r --if-present test", "check": "pnpm format:check && pnpm lint && pnpm typecheck && pnpm test", "db:generate": "pnpm --filter @todo/db db:generate", - "db:migrate:local": "pnpm --filter @todo/web exec wrangler d1 migrations apply todo-db --local --persist-to .wrangler/state-drizzle-baseline", - "db:migrate:remote": "pnpm --filter @todo/web exec wrangler d1 migrations apply todo-db --remote", + "db:migrate:local": "pnpm --filter @todo/web exec wrangler d1 migrations apply kanban-db --local --persist-to .wrangler/state-drizzle-baseline", + "db:migrate:remote": "pnpm --filter @todo/web exec wrangler d1 migrations apply kanban-db --remote", "test:e2e": "playwright test", - "db:migrate:preview": "pnpm --filter @todo/web exec wrangler d1 migrations apply todo-db-preview --remote --env preview", + "db:migrate:preview": "pnpm --filter @todo/web exec wrangler d1 migrations apply kanban-db-preview --remote --env preview", "deploy:web": "pnpm --filter @todo/web deploy", "deploy:preview": "pnpm --filter @todo/web build && pnpm --filter @todo/web exec wrangler deploy --env preview", "deploy:worker": "pnpm --filter @todo/reminder-worker deploy",