DEMO / KOTO_10B

Claim Link で贈る琴デジポイント

会員でも未会員でも、LINE 友だちでなくても、相手にリンクを送るだけで 琴デジポイントを贈れる仕組み。受領者は会員登録と同時にポイントを受け取れます。

本番ページを開く(琴デジポイントを贈る)

🎁① 何ができる?

  • 琴平デジタル町民が、自分の琴デジポイント残高から好きな金額を「ギフトリンク」 として発行できる。
  • 発行したリンク (例: /c/kotohira/gift/K7P2X9) を LINE / メール / SMS / QR / 紙 / 口頭、 なんでも好きな手段で相手に渡せる。
  • 相手が会員でなくても、リンクを踏めば LINE 登録 → 同意 → DID 発行 → ポイント受領が1 分の 1 フローで完結する。
  • 未受領のリンクは贈り主が 取消可能(残高が戻る)。期限切れも自動で残高に戻る。

📤② どう使う? 贈り主の手順

1

マイページから「贈る」を開く

/c/kotohira/mypage?giftLink=1を開く(マイページからもリンクできます)。
2

金額・メッセージを入力して発行

プリセット (100/500/1000/3000pt) かカスタムで金額を指定。任意でメッセージを 200 字以内で添える。 「リンクを発行する」を押すと自分の残高から差し引かれる。
3

リンクを共有

発行直後のカードに「LINE で送る」「URL をコピー」のボタンが出る。 LINE シェアは line.me/R/share を経由するので、贈り主の好きな相手に送れる(システムが勝手に push しない=LINE 通数を消費しない)。

📥③ 受領者がリンクを踏むと?

未会員(LINE 友だちですらない)の場合

受領ページで「LINE で登録して受け取る」を押す → LINE OAuth → 同意 4 チェック (利用規約/年齢/DID/任意 LINE 連携) → 同意完了と同時に琴平デジタル町民として登録され、ポイントが残高に追加される。

既会員 (CONSENTED/DID_ISSUED) の場合

「今すぐ受け取る」を 1 タップ → ポイント即時付与。

既会員だが kotohira 同意未取得 (PROSPECT) の場合

「琴平デジタル町民の同意をして受け取る」→ 同意ページに自動誘導。同意完了で受領まで一気通貫。

既受領 / 期限切れ / 取消済み / 自分宛の場合

それぞれに合った理由メッセージを表示し、誤って二重受領できないようにする。

🔁④ ポイント / 体験のフロー図

贈り主 (会員)               未会員の受領者
─────────────────────────────────────────────
[贈る] 押す
   │
   │ POST /api/c/kotohira/gift/issue
   │ → code 生成 / 残高差引 / 7 日有効
   │
   │ "URL を共有してください"
   │ [LINE で送る] [URL コピー] [QR]
   │
   ├─→ LINE/メール/SMS/紙/QR で渡す ──→ [リンクを開く]
                                            │
                                            ▼
                                    /c/kotohira/gift/[code]
                                    "○○さんから 500pt"
                                    [LINE で登録して受け取る]
                                            │
                                            ▼
                                    LINE OAuth (cookie に
                                    pendingClaimCode を HMAC 署名)
                                            │
                                            ▼
                                    /c/kotohira/onboarding/consent
                                    ToS / 年齢 / DID / LINE
                                            │
                                            ▼
                                    POST /api/c/kotohira/onboarding/complete
                                      Phase 1: 同意 commit + Community 加入 + DID 申請
                                      Phase 2: claim (race-safe updateMany)
                                            │
                                            ▼
                                    /c/kotohira/gift/[code]/done
                                    "+500pt 受け取りました 🎉"

🛡⑤ 安全装置と運用ガード

  • race-safe: 受領は updateMany + count===1 の楽観的ロック。同時にリンクを踏まれても 1 回しか付与されない。
  • HMAC 署名 cookie: claim code は HttpOnly cookie に HMAC 署名 + 10 分 TTL。 改ざん・期限切れは即無効化。NextAuth state には触らないので CSRF 検証と衝突しない。
  • 同意 append-only: Phase 1 (同意 commit) と Phase 2 (claim) を別 tx に分離。 Phase 2 が失敗しても同意の証跡は消えない(個情法上の取消請求にも備える)。
  • 勝手に push しない: 受領者の LINE には Push しない(贈り主が手動で URL を共有する)。 未会員に対する「無同意の通信送付」を法的に回避。
  • 自己宛/未会員未同意ガード: 自分宛・取消済・期限切れ・SUSPENDED は受領できない。
  • レート制限: 1 ユーザー 1 日 30 件・1 件 100,000pt 上限。
  • 期限切れ自動戻し: Vercel Cron が毎日 expire-gifts を実行し、未受領の期限切れを invalidate して残高を贈り主に戻す(GIFT_REFUND)。
  • 監査ログ: 全 claim 試行を GiftClaimAttempt に append-only で記録(IP/UA ハッシュ + reason)。

💴⑥ 通数課金 (LINE) について

LINE Messaging API の Push は通数課金ですが、Claim Link はシステムから自動 Push しません。 贈り主が任意の手段で URL をシェアする方式なので、贈与のたびに LINE 通数を消費しません。 受領完了の通知も「アプリ内通知 (DB の Notification)」のみで、LINE Push は使いません。

LINE Push を使うのは、kotohira スコープでは別途設計した sendKotohiraLineNotification 経由のときだけ。phase ガードで未同意のユーザーには絶対に送らない。

📚⑦ 関連ファイル / 設計書

  • 設計書: docs/_kotohira/gift-claim-flow.md (v2.6)
  • 本番 UI: Claim Link 発行は /c/kotohira/mypage の「送る」タブ内。受領ページ: src/app/c/kotohira/gift/[code]/
  • 未会員フロー: src/app/c/kotohira/onboarding/consent/
  • API: /api/c/kotohira/gift/issue / /[id]/invalidate / /api/c/kotohira/onboarding/complete
  • Cron: /api/cron/expire-gifts
  • HMAC ヘルパ: src/lib/kotohira/pendingClaim.ts
  • phase ガード: src/lib/kotohira/userPhase.ts