rdyrct について
rdyrctはCloudflare上で動作する組織単位の短縮リンクサービスです。独自ドメインとクリック分析を必要とするチーム向けで、エイリアスやQRコードにも対応し、IPアドレスを保存せずに分析できます。
主な機能
- 01カスタムまたはランダムな短縮リンクの作成
- 02リンクのエイリアスとUTMパラメーターの管理
- 03QRコードの生成とダウンロード
- 04組織ロールによるメンバー管理
- 05クリック、参照元、国、端末の統計表示
活用シーン
- 01チームや組織向けのブランド短縮リンクを作成
- 02UTMパラメーターを付けてキャンペーンのクリックを計測
- 03短縮リンクのQRコードを配布
- 04リンクの参照元や端末の分布を確認
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://rdyrct.com/api/mcpclaude mcp add --transport http baronunread-rdyrct https://rdyrct.com/api/mcp{"mcpServers":{"baronunread-rdyrct":{"type":"http","url":"https://rdyrct.com/api/mcp"}}}Cursor で開く{"servers":{"baronunread-rdyrct":{"type":"http","url":"https://rdyrct.com/api/mcp"}}}VS Code で開く{"mcpServers":{"baronunread-rdyrct":{"type":"http","url":"https://rdyrct.com/api/mcp"}}}{"mcpServers":{"baronunread-rdyrct":{"serverUrl":"https://rdyrct.com/api/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
ツール
詳細
ワンクリックでデプロイ
Cloudflare はこのリポジトリをあなたの GitHub アカウントにコピーし、データベース、ストレージ、キューを作成して、プラットフォーム管理者となるアカウントのメールアドレスを尋ねます。それ以外の値はすべてそのままにしてください。最初のビルドで、workers.dev のアドレス上にあなたのコピーが配信され、セッションキーが生成されてマイグレーションが適用されます。コピーへのプッシュごとに、再びデプロイされます。独自ドメインを使う場合は、独自ドメインに移行するをご覧ください。
ターミナルから実行したい場合は、bun run setup でクローンから同じことができます。Cloudflare Workers にデプロイするをご覧ください。
機能
- 短縮リンク:カスタムまたはランダムなスラッグを指定できます。オプションで UTM パラメーター(source、medium、campaign、term、content)をリダイレクト時に適用できます。
- グループ化されたリンクアドレス:リンクの名前を変更しても、古いスラッグは解放されるまで48時間リダイレクトされます。また、リンクに追加のエイリアスを設定して、すべて同じ宛先にリダイレクトできます。
- リンクごとの QR コード(有料プラン):中央にロゴを配置でき、ライブプレビューと PNG/SVG ダウンロードに対応しています。
- カスタムドメイン(Pro):Cloudflare for SaaS 経由で
links.yourbrand.comを接続でき、スラッグはドメインごとに名前空間が分かれます。 - 組織:
owner/admin/memberのロールに対応しています。管理者はチーム、ドメイン、請求を管理し、メンバーはリンクを管理します。 - マジックリンク招待:メールで送信され、1回のみ使用でき、有効期間は7日間です。
- プライバシーに配慮した分析:日ごとのクリック数、人気のリンク、国、参照元、デバイスを確認できます。IP アドレスは一切保存されません。
- Polar によるユーザーごとの Free/Hobby/Pro の請求。Polar は Merchant of Record として機能し、税金/VAT を処理します。
- シークレットで保護されたスーパー管理者コンソール:
SUPERADMIN_EMAILと一致するアカウントには、使用状況、組織の詳細表示、プラン管理用のクラウドコンソールパネルが表示されます。それ以外のユーザーには404を返します。
技術スタック
rdyrct は Cloudflare を第一に設計されており、ホストする別個のバックエンドを必要とせず、製品全体が単一の Worker で動作します。
- Cloudflare Workers:1つの Worker で API、リダイレクトのホットパス、静的な React アプリを提供します。
- D1:エッジ上の SQLite で、認証、組織、リンク、クリック、ドメインの信頼できる唯一の情報源です。
- KV:リダイレクトのホットパスで、スラッグから宛先を検索します。クリック処理が D1 の応答を待つことはありません。
- R2:組織ごとにキー付けされた QR ロゴ画像を、変更不可として配信・キャッシュします。
- Cloudflare for SaaS:Pro 組織が独自の短縮リンクドメインを使うためのカスタムホスト名に対応します。
- Workers Rate Limiting:認証、メール、書き込み、アップロード、ドメイン、請求、クリック記録に対して、それぞれ個別の不正利用対策を適用します。
アプリケーション層:
- ルーティングにはHono
- メールアドレスとパスワードによる認証にはBetterAuthを使用し、メール OTP 認証と PBKDF2/WebCrypto によるハッシュ化に対応
- D1 上の ORM としてDrizzle ORM
- React 19 + Vite +
@cloudflare/vite-plugin - Tailwind v4 + Base UI
- TanStack Query + React Router
- 請求にはPolar、トランザクションメールにはResend
ローカル開発
bun install
cp .dev.vars.local.example .dev.vars # then edit; at minimum set SUPERADMIN_EMAIL
bunx emulate --service resend # local Resend inbox on :4000
bun run db:migrate:local
bun run dev # https://rdyrct.localhost
-
管理コンソールを利用するには、
SUPERADMIN_EMAILに設定したアドレスで登録してください。それ以外のアドレスは通常のユーザーになります。 -
開発サーバーではセルフホスト版アプリが実行されます。rdyrct.com 独自のランディングページやマーケティングページを作業するには、
.envにVITE_RDYRCT_SITE=1を追加してください。 -
新しいアカウントでは、最初の組織を作成するまで、組織スコープのページに組織作成のプロンプトが表示されます。
-
メール認証コードは、実際の受信トレイではなく、emulate.dev の Resend エミュレーターを通じて送信されます。次のコマンドで確認してください。
curl localhost:4000/emails -H 'authorization: Bearer test_token_admin'最新のメッセージから6桁のコードをコピーしてください。
-
CF_DEV_ENV=simulated(.dev.vars.local.exampleのデフォルト)を設定すると、Cloudflare Custom Hostnames API をローカルでスタブします。DNS は約3秒後、TLS は約12秒後に準備完了となるため、実際のゾーンがなくても「ステータスを確認」に同じ進行状況が表示されます。CF_DEV_ENV=instantを設定すると、両方がすぐに準備完了として報告されます。e2e テストでは、タイマーを待たずに済むようこちらを使用します。どちらも設定せず、CF_API_TOKEN/CF_ZONE_IDがない場合は、応答を偽装せずに失敗します。 -
実際の Polar sandbox アカウントで課金するには、Webhook が
/api/webhooks/polarに到達できるよう、公開 URL(wrangler dev --remoteまたはトンネル)が必要です。
テスト
bun run test # fast unit tests
bun run test:worker # Worker routes with local D1 and KV bindings
bun run e2e:install # install Chromium for Playwright once
bun run e2e:smoke # real-browser baseline regression checks
bun run verify # types, lint, formatting, unit, and Worker tests
Playwright がローカルサーバーのライフサイクルを管理し、ローカルの Cloudflare 状態をリセットしたりシードしたりすることはありません。ブラウザーテストが失敗した場合は、スクリーンショットとトレースが
test-results/ に保存されます。
Cloudflare Workers にデプロイする
git clone https://github.com/baronunread/rdyrct
cd rdyrct && bun install
bun run setup
セットアップでは、3つの項目を確認します。Worker の名前(Enter キーを押すと rdyrct のままになります)、Cloudflare アカウントのドメイン(無料の *.workers.dev アドレスを使う場合は Enter キーを押します)、プラットフォーム管理者となるアカウントのメールアドレスです。アカウントですでに同じ名前の Worker が実行されている場合は停止するため、既存の Worker に上書きしてデプロイすることはありません。その後、次の処理を行います。
wrangler.jsoncのコピーを書き換えます。APP_URLとAPP_HOSTにドメインを設定し、rdyrct.com 独自の ID と設定(メール送信者、Polar の製品、Cloudflare ゾーン、Sentry)を取り除きます。- Wrangler により、アカウントに D1 データベース、KV 名前空間、R2 バケット、キューを作成します。ID のないバインディングは初回デプロイ時に新しいリソースを作成するため、それぞれ Worker と同じ名前が付けられます。
BETTER_AUTH_SECRETを生成し、それとSUPERADMIN_EMAILをシークレットとして設定してから、ビルド、デプロイ、マイグレーションの適用、ドメインの割り当てを行います。
書き換えられた wrangler.jsonc をフォークにコミットしてください。その後は、bun run deploy で更新をデプロイできます。新しいマイグレーションを適用してからデプロイします。すべてのビルドはセルフホスト版アプリとなり、サインイン画面が開き、rdyrct.com のマーケティングページ、アナリティクス、検索タグは含まれません。rdyrct.com 自体をビルドするのは VITE_RDYRCT_SITE=1 の場合のみで、bun run deploy は rdyrct.com 以外のホストへのデプロイを拒否します。
その他はすべて任意です。それぞれの項目で、追加される機能について説明します。
| 設定 | 追加される機能 |
|---|---|
RESEND_API_KEY, MAIL_FROM | メール:サインアップ認証コード、パスワードのリセット、招待、通知。設定しない場合、サインアップ時の認証は省略されます(下記を参照)。 |
POLAR_* | Hobby プランと Pro プランの販売。設定しない場合、利用制限はなく、課金機能も表示されません。 |
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET | 「Google で続行」。 |
CF_API_TOKEN, CF_ZONE_ID | Cloudflare for SaaS を介した顧客独自のドメイン。 |
SHARED_LINK_HOST | 新しい共有ドメインリンク用の、2 つ目の短いホスト。 |
TURNSTILE_SITE_KEY, TURNSTILE_SECRET_KEY | サインアップ、パスワードのリセット、報告フォームの前に Cloudflare Turnstile を設置します。両方を 1 回の wrangler secret bulk 呼び出しで設定します。片方だけでは、これらのフォームは利用できません。Cloudflare はその後、これらの訪問者を認識します。 |
WEB_RISK_API_KEY | 2 つ目の宛先チェックとして Google Web Risk を使用します。リストに掲載された宛先へのリンクは保留されます。 |
SENTRY_DSN | Sentry プロジェクトにエラーレポートを送信します。 |
SITE_NAME | すべてのタブに表示される名前(例:「Acme links」)。設定しない場合、タブにはコピーのホスト名が表示されます。 |
メールプロバイダーも Google サインインも設定しない場合、アカウントは認証されず、パスワードもリセットできません。 プライベートなインスタンスであれば問題ありませんが、公開インスタンスには推奨されません。この状態が続く間、管理コンソールにその旨が表示されます。
変数は wrangler.jsonc に記述します。シークレットは bunx wrangler secret put <NAME> で 1 つずつ設定するか、cp prod.secrets.env.example prod.secrets.env を実行してファイルに値を入力し、次のコマンドを実行してまとめて設定します。
bunx wrangler secret bulk prod.secrets.env && rm prod.secrets.env
独自ドメインに移行する
ボタンから、またはセットアップから workers.dev で開始しましたか?自分用のコピーをクローンし、bun run setup を実行してドメインを指定してください(Cloudflare アカウントに登録されている必要があります)。その後、wrangler.jsonc をコミットしてプッシュします。セットアップによってドメインが割り当てられ、データ、シークレット、セッションキーはそのまま維持されます。手動で設定する場合は、Cloudflare ダッシュボード → Workers → 対象のワーカー → Settings → Domains & Routes → Add → Custom domain の順に進み、wrangler.jsonc で APP_URL と APP_HOST を設定し、rdyrct.com 用の変数(MAIL_FROM、WELCOME_FROM、POLAR_*、CF_ZONE_ID、SENTRY_DSN)を削除して、bun run deploy を実行します。短縮リンクはルート(https://links.example.com/<slug>)で利用でき、その他のすべてのパスではアプリが配信されます。wrangler.jsonc にルートを記述しないでください。routes リストを設定すると、ダッシュボードで割り当てられているルートがすべて置き換えられ、これをコミットすると、すべてのフォークにその設定が渡ってしまいます。*/* ルートは、お客様独自のドメイン(以下を参照)にのみ使用します。
メール(任意)
RESEND_API_KEY と MAIL_FROM を設定します(Resend で認証したドメインの送信元アドレスを指定してください)。これらを設定しないとメールは送信されません。サインアップ時には認証コードが省略され、ユーザーはサインインします。また、パスワードリセットフォームにはメールプロバイダーが必要であることが表示されます。メール送信処理は src/worker/email.ts の sendEmail() という1つの関数にまとまっているため、別のプロバイダーを使う場合はここを変更します。
販売プラン(任意)
上限や課金を設定せずに実行する場合は、このセクションをスキップしてください。プランを販売するには、POLAR_SERVER=sandbox(本番稼働時は production)、POLAR_PRO_PRODUCT_ID、POLAR_HOBBY_PRODUCT_ID(Polar で作成した定期購入商品)、およびシークレットの POLAR_ACCESS_TOKEN と POLAR_WEBHOOK_SECRET を設定します。
Polar の設定: スコープ checkouts:write と customer_sessions:write を持つ Organization Access Token を作成します。https://rdyrct.com/api/webhooks/polar に webhook エンドポイントを追加し、Worker が処理する 5 つすべてのイベントを登録します。1 つでも漏れると、課金状態が実際とずれていきます。
| イベント | 処理内容 |
|---|---|
subscription.active | サブスクリプションを開始します:プラン、顧客、価格、アクセス権を設定します |
subscription.updated | サブスクリプションの全スナップショットです:ステータス、商品、解約状態、期間終了日 |
subscription.canceled | 期間終了時に終了するよう設定します。終了日まではアクセス権が継続します |
subscription.uncanceled | 予定されている解約を取り消します |
subscription.revoked | サブスクリプションを終了します。サブスクリプションとアクセス権がなくなります |
どのサブスクリプションのステータスでアクセス権を維持するかは、src/worker/entitlement.ts で決めます。active、trialing、past_due ではアクセス権を維持します。Polar は支払い失敗後も数日間再試行し、再試行を諦めると subscription.revoked を送信するためです。unpaid、canceled、incomplete、incomplete_expired ではアクセス権を維持せず、ルールのないステータスでもアクセス権は維持されません。
管理者が手動で付与する有料アクセス権はコンプで、サブスクリプションとは別に保存され、サブスクリプション数には数えられません。コンプはそれより下位のサブスクリプションより優先されるため、サブスクリプションを取り消しても、管理者が付与したアクセス権は失われません。
管理コンソールに表示されるのは金額ではなく件数です。有料プランを利用している人、その料金を支払っている人、コンプを付与されている人の数を確認できます。解約中の利用者は、ユーザー一覧の本人の行に表示され、該当する利用者の名前が示されます。割引、税金、返金を差し引いた請求額を把握している Polar ダッシュボードで、収益を確認してください。
2 つ目の共有ドメインホスト(任意)。 短いドメインも同じ方法で接続し、https://<it>/ がリダイレクトを返すことを確認してから、bunx wrangler secret put SHARED_LINK_HOST で有効にします。デプロイなしで反映され、bunx wrangler secret delete SHARED_LINK_HOST で無効にできます。この順序で行うのは、新しいリンクがすべて即座にそのホストを使い始めるためです。ドメインが解決される前に設定すると、リンク先のないリンクが発行されます。共有ドメインのスラッグの KV キーにはホストが含まれないため、古いリンクはどちらのホストでも引き続き動作します。未設定の場合、共有リンクには APP_HOST が使われます。
本番環境への初回デプロイ前に、レート制限ポリシー、監視、WAF ルール、ロールバック手順を確認してください。
リンク、ドメイン、ロゴ、組織の削除に関するフローを変更する前に、アーキテクチャ、データフロー、改善の優先事項を確認してください。
顧客独自ドメイン(Pro): 組織が links.theirbrand.com を使用できるようにするには、rdyrct.com ゾーンで Cloudflare for SaaS を有効にし、オリジンのないプロキシ済みフォールバックオリジン(例:fallback.rdyrct.com AAAA 100::)を作成して、rdyrct Worker を指す Worker ルート */* を追加します。CF_API_TOKEN には、ゾーンを対象とする Zone → SSL and Certificates → Edit の権限が必要です。また、トランザクションメールがブロックされないよう、Resend で送信ドメイン(例:mail.rdyrct.com)も認証してください。
設定
| 名前 | 種類 | 用途 |
|---|---|---|
BETTER_AUTH_SECRET | シークレット | セッションとトークンに署名します |
SUPERADMIN_EMAIL | シークレット | プラットフォーム管理者になるアカウント |
RESEND_API_KEY | シークレット | トランザクションメール用の Resend API キー |
POLAR_ACCESS_TOKEN | シークレット | Polar API アクセストークン(スコープ:checkouts:write、customer_sessions:write) |
POLAR_WEBHOOK_SECRET | シークレット | Polar Webhook の署名を検証します。エンドポイントは https://rdyrct.com/api/webhooks/polar です |
CF_API_TOKEN | シークレット | Zone → SSL and Certificates → Edit 権限を持つ Cloudflare トークン(カスタムドメイン用) |
APP_URL | 変数 | アプリの公開 URL 全体。例:https://rdyrct.com |
APP_HOST | 変数 | 公開ホスト。例:rdyrct.com |
SHARED_LINK_HOST | シークレット(任意) | 新しいリンク用の第 2 の共有ドメインホスト。例:rdyr.cc。名前解決後に設定します |
MAIL_FROM | 変数 | 送信メールの差出人アドレス |
RESEND_BASE_URL | 変数(開発時のみ) | ローカルの Resend エミュレーターを指定します |
POLAR_SERVER | 変数 | sandbox または production |
POLAR_PRO_PRODUCT_ID | 変数 | Pro プランの Polar 製品 ID |
POLAR_HOBBY_PRODUCT_ID | 変数 | Hobby プランの Polar 製品 ID |
CF_ZONE_ID | 変数 | カスタムホスト名に使用するゾーン ID |
CF_DEV_ENV | 変数(開発時のみ) | simulated はタイマーでカスタムホスト名 API を偽装し、instant はタイマーを使いません |
本番環境では、wrangler secret put NAME または wrangler secret bulk prod.secrets.env を使ってシークレットを設定します。ローカル環境では、すべて .dev.vars から読み込まれます(.dev.vars.local.example を参照してください)。
プロジェクト構成
migrations/ D1 schema (numbered SQL migrations, applied in order)
scripts/ Local dev utilities (e.g. seed-local.ts)
src/worker/ Hono API, BetterAuth, KV publishing, redirect hot path
routes/ auth/user, orgs, links, qr-logos, domains, billing, admin
better-auth.ts plan.ts util.ts guards.ts org-role.ts rate-limit.ts session.ts
email.ts password.ts kv.ts storage.ts alerts.ts clicks.ts workflows.ts
src/shared/types.ts DTOs + PLAN_LIMITS (shared worker ↔ app)
src/app/ React SPA
routes/ page-level route components
ui/ design-system primitives
components/ feature components
lib/ client utilities, API hooks
.agents/skills/ Agent skills (react-doctor)
.claude/skills/ Claude skills (fallow, react-doctor)
ライセンス
MIT © Andrea Bruno。LICENSE を参照してください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。