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