Skip to content

feat(frontend): FoR Status(ランクシステム)のロジック実装と残高カードへのバッジ表示 #155

@yu23ki14

Description

@yu23ki14

一行説明

FoR Status(ランクシステム)のロジックを実装し、ホーム画面の残高カードにランクバッジと減衰アラートを表示する。

詳細

What is FoR Status

「For Forest」な暮らしの証明。
FoR Status は、FoR のエコシステムにおいて、ユーザーがどれだけ「循環」と「再生」に貢献したかを表す証。森をケアし、交換頻度に応じてステータスが付与される。

航空会社のステータスに「有効期限」があるように、FoR のステータスも「活動の鮮度」によって変動する。どれだけ FoR を持っているかではなく、よく使い・よく回すことが評価ポイント。定期的に FoR を交換し循環に加わり続けることがステータス維持の鍵となる。

ステータスが上がるほど特別な権利(限定イベント参加権、投票力の重み付け、提携店での優待など)が付与される可能性がある(特典自体は本Issueのスコープ外)。

表示箇所

  • packages/frontend/app/routes/home.tsx の残高カード(<Card variant="wallet" topProps={{ badgeImage: ... }} />)にランクバッジ画像を表示する。
  • 既に topProps.badgeImage を渡す口がコメントアウトで用意されている(home.tsx 内)。ここに算出したランクのバッジ画像を渡す。
  • 減衰が近づいている場合、減衰アラートメッセージを表示する(表示場所・UIは別途デザイン)。

用語・ルールの定義(確定事項)

  • 「決済 / 利用」= ユーザーが送信者となる送金のみfrom === metransferViaRouter)。受信はカウントしない。
  • ランク(ティア)は永続保存せず、決済履歴(送信トランザクション列)と現在時刻から都度再構成する。過去のティア状態をDB等に持たない前提で、すべての判定を決済履歴から導出できる定義にする。
  • 昇格: 昇格トリガーを一度満たせばそのティアに到達。ただし一度に上がるのは1段階のみ(複数ティアを一気に飛び越えない)。
  • 減衰(ランクダウン): 維持条件を満たさなくなったら1段ずつ下がる(一気に最下位まで落とさない)。
  • Tier 6(オオカミ)の「フクロウを1ヶ月維持」: 直近1ヶ月、週3回以上の決済を満たし続けたことを決済履歴から判定する。

ランク仕様

ティア ステータス名 (JP/EN) 昇格トリガー 維持条件 減衰(鮮度)ロジック 減衰アラートメッセージ
Tier 1 ミツバチ / Honeybee アカウント作成時 条件なし(永続) 減衰なし (表示なし)
Tier 2 リス / Squirrel 初回決済完了 60日以内に1回以上の決済 最終決済から60日経過でランクダウン 「埋めた種を忘れていませんか?あと〇日以内にFoRをつかって、リスの活気を取り戻しましょう。」
Tier 3 鳥 / Bird 累計3回以上の決済 45日以内に1回以上の決済 最終活動から45日経過でランクダウン 「翼を休めすぎているようです。森の空気が淀む前に、あと〇日以内に新しいケアを。」
Tier 4 鹿 / Deer 月4回以上の利用 30日以内に1回以上の決済 最終活動から30日経過でランクダウン 「森が少し乾燥してきました。鹿の歩みを止めないよう、あと〇日以内に潤いを届けましょう。」
Tier 5 フクロウ / Owl 週3回以上の利用 21日以内に1回以上の決済 最終活動から21日経過でランクダウン 「賢者の眼が閉じかけています。森の秩序を保つため、あと〇日以内にFoRをつかってみましょう。」
Tier 6 オオカミ / Wolf フクロウを1ヶ月維持(直近1ヶ月 週3回以上を継続) 14日以内に1回以上の決済 最終活動から14日経過でランクダウン 「伝説が霧に消えようとしています。リーダーの帰還を森が待っています。あと〇日以内にケアを。」

※ アラートメッセージの文言は上記で確定〇日 の部分は「次のランクダウンまでの残日数」を動的に埋め込む(テンプレート化して残日数を差し込む)。

バッジの世界観(参考)

  • Tier 1 ミツバチ: 小さな行為で受粉を助ける循環の運び手
  • Tier 2 リス: あちこちに種を埋める未来の作り手
  • Tier 3 鳥: 遠くへ声を届け、点と線をつないでいく森の繋ぎ手
  • Tier 4 鹿: 森を美しく整え、光の道をつくる調和の象徴
  • Tier 5 フクロウ: 深い知恵で森の行く末を見極める賢き森の守り手
  • Tier 6 オオカミ: 生態系を根本から変容させる再生のリーダー

バッジ画像アセット

  • 画像は後ほど差し込むため、rankbadge_<tier>.png 形式のファイル名で配置する(rankbadge_1.pngrankbadge_6.png、ティア番号に対応)。
  • 配置先(案): packages/frontend/app/assets/images/badges/(既存の cards/logo/ と並ぶ形)。
  • 実画像が来るまでは同名でプレースホルダ画像を置いておき、後から差し替えるだけで反映される構成にする。

ロジック設計方針(案)

  • ランク判定は 純粋関数 として切り出す(例: app/lib/for-status.ts)。入力は「送信決済イベントの配列(timestamp 昇順/降順)」+「現在時刻」、出力は「現在ティア」+付随情報(最終活動日、次ランクダウンまでの残日数、減衰アラート要否など)。
  • データソースは useTransfersViaRoutertransferViaRouters)。各イベントは from / to / sender / timestamp を持つ。from === me のものだけを決済として抽出する。
  • 昇格は「累計回数」「直近の頻度(週/月)」「下位ティアの維持期間」の組み合わせで判定。一度満たせば到達するが1段階ずつ上がる。維持・減衰は「最終活動からの経過日数 vs ティアごとの閾値」で判定し、満たさなくなったら1段階ずつ下がる。すべて決済履歴から再構成する。
  • Tier 6: 直近1ヶ月にわたり週3回以上(=フクロウ昇格条件)を継続して満たしたかを決済履歴上で評価して判定する。
  • ティア → バッジ画像(rankbadge_<tier>.png)のマッピングを用意し、home.tsxtopProps.badgeImage に渡す。
  • 既存の取引履歴取得は最新N件のみ(home では3件)。ランク算出には十分な件数の決済履歴が必要なため、累計回数・頻度判定に足りるデータ取得方法を検討する。

減衰アラートメッセージ

  • 文言は確定済み(上記テーブル)。〇日 はロジックが算出する「次のランクダウンまでの残日数」を動的に埋め込む。
  • メッセージはティアごとのテンプレートとして定義する。
  • Tier 1(永続)はアラート対象外。
  • 表示場所・UIデザインは別途(至急)対応。ロジック側は「次のランクダウンまでの残日数」「アラート要否」を返せるようにしておき、デザイン確定後すぐ載せられるようにする。

要件

  • ランク判定の純粋関数を実装する(入力: 送信決済イベント+現在時刻、出力: 現在ティア+メタ情報+次ランクダウンまでの残日数)
  • 6ティアの昇格トリガー・維持条件・減衰ロジックを仕様どおり実装する
  • 決済 = 送信のみ(from === me)で transferViaRouters から抽出・カウントする
  • 昇格は1段階ずつ、減衰も1段階ずつ下がるよう実装する
  • Tier 6 を「直近1ヶ月 週3回以上を継続」で判定する
  • ランク・維持判定(Tier 6 含む)をすべて決済履歴から再構成できるようにする
  • ランク算出に必要な決済履歴を取得する hook を用意/拡張する
  • ティア → バッジ画像(rankbadge_1.pngrankbadge_6.png)のマッピングを用意する
  • バッジ画像を rankbadge_<tier>.png 形式(プレースホルダ可)で配置する
  • home.tsx の残高カードに、算出したティアに対応するバッジ画像を表示する
  • 減衰アラートメッセージのテンプレート+残日数の動的埋め込みを実装する(文言は確定済み)
  • ロジックのユニットテストを追加する(昇格・維持・減衰の境界値、残日数算出)

補足

別途対応(このIssueのロジック実装はブロックしない):

  • アラートの表示場所・UIデザイン: 後ほど至急で確定 → 確定次第表示を実装。
  • バッジ実画像: 後ほど差し込み。rankbadge_<tier>.png 同名で差し替えるだけにする。

確定事項:

  • アラートメッセージの文言は上記テーブルで確定
  • 決済の定義は送信のみfrom === me)。
  • ランク状態は保存せず、決済履歴から都度再構成する。
  • 昇格は一度満たせば到達するが1段階ずつ、減衰も1段階ずつ
  • Tier 6 は直近1ヶ月 週3回以上を継続で判定。
  • バッジ画像のファイル名は rankbadge_<tier>.png(1〜6)。

参考: packages/frontend/app/routes/home.tsx(残高カード badgeImage の口)、packages/frontend/app/hooks/useTransfersViaRouter.tspackages/frontend/app/graphql/queries.ts

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions