Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

baronunread/rdyrct

Open more actions menu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

123 Commits
123 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

rdyrct

Organization-based link shortener + QR codes, running entirely on Cloudflare's edge.

License: MIT Built on Cloudflare Workers Bun React 19


Deploy in one click

Deploy to Cloudflare

This provisions the Worker from the Cloudflare dashboard and may prompt you to create or select the KV namespace and D1 database. You'll still need to paste their ids into wrangler.jsonc, set the secrets below, configure Polar, and point a domain at the Worker; see Deploy to Cloudflare Workers.


Features

  • Short links with custom or random slugs, optional UTM parameters (source, medium, campaign, term, content) applied at redirect time.
  • QR codes per link (paid plans), with an optional logo in the center, live preview, and PNG/SVG download.
  • Custom domains (Pro): connect links.yourbrand.com via Cloudflare for SaaS, with slugs namespaced per domain.
  • Organizations with owner / admin / member roles: admins manage the team, domains, and billing; members manage links.
  • Magic-link invites: single-use, valid for 7 days, sent by email.
  • Privacy-friendly analytics: clicks per day, top links, countries, referrers, devices. No IP addresses are ever stored.
  • Per-user Free/Hobby/Pro billing through Polar, which acts as Merchant of Record and handles tax/VAT.
  • Secret-pinned superadmin console: the account matching SUPERADMIN_EMAIL gets a cloud-console panel for usage, org drill-down, and plan management. It 404s for everyone else.

Stack

rdyrct is built Cloudflare-first: the entire product runs in a single Worker with no separate backend to host:

  • Cloudflare Workers: one Worker serves the API, the redirect hot path, and the static React app.
  • D1: SQLite at the edge, source of truth for auth, orgs, links, clicks, and domains.
  • KV: slug → destination lookups on the redirect hot path, so a click never waits on D1.
  • R2: QR logo images, keyed by org, served immutable and cached.
  • Cloudflare for SaaS: custom hostnames for Pro orgs' own short-link domains.
  • Workers Rate Limiting: separate abuse controls for auth, email, writes, uploads, domains, billing, and click recording.

Application layer:


Local development

bun install
cp .dev.vars.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
  • Sign up with the address you set as SUPERADMIN_EMAIL to unlock the admin console; any other address is a normal user.

  • New accounts see a create-org prompt on org-scoped pages until they create their first organization.

  • Email verification codes are sent through emulate.dev's Resend emulator instead of a real inbox. Read it with:

    curl localhost:4000/emails -H 'authorization: Bearer test_token_admin'

    and copy the 6-digit code out of the latest message.

  • DEV_FAKE_CF=1 (the .dev.vars.example default) stubs the Cloudflare Custom Hostnames API locally, so custom domains activate instantly on "Check status" without a real zone.

  • Billing against a real Polar sandbox account needs a public URL (wrangler dev --remote or a tunnel) for webhooks to reach /api/webhooks/polar.


Tests

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 owns the local server lifecycle and never resets or seeds local Cloudflare state. Failed browser tests keep a screenshot and trace in test-results/.


Deploy to Cloudflare Workers

Prefer the manual path, or need to redeploy after the button above? Create the resources:

bunx wrangler kv namespace create LINKS
bunx wrangler d1 create rdyrct
bunx wrangler r2 bucket create rdyrct-qr-logos

Paste the returned ids into wrangler.jsonc:

  • kv_namespaces[0].id
  • d1_databases[0].database_id

Fill in the non-secret vars in wrangler.jsonc:

  • APP_URL=https://rdyrct.com
  • APP_HOST=rdyrct.com
  • MAIL_FROM=rdyrct <no-reply@mail.rdyrct.com>
  • POLAR_SERVER=sandbox (or production when live)
  • POLAR_PRO_PRODUCT_ID — create a recurring Pro product in Polar and paste its id
  • POLAR_HOBBY_PRODUCT_ID — create a recurring Hobby product in Polar and paste its id
  • CF_ZONE_ID — your rdyrct.com zone id

Set the secrets. Either one by one:

bunx wrangler secret put BETTER_AUTH_SECRET
bunx wrangler secret put SUPERADMIN_EMAIL
bunx wrangler secret put RESEND_API_KEY
bunx wrangler secret put POLAR_ACCESS_TOKEN
bunx wrangler secret put POLAR_WEBHOOK_SECRET
bunx wrangler secret put CF_API_TOKEN

or in bulk with cp prod.secrets.env.example prod.secrets.env, fill it in, then:

bunx wrangler secret bulk prod.secrets.env && rm prod.secrets.env

Then migrate and ship:

bun run db:migrate:remote
bun run deploy

Polar setup: create an Organization Access Token with scopes checkouts:write and customer_sessions:write. Add a webhook endpoint at https://rdyrct.com/api/webhooks/polar and subscribe to subscription.active, subscription.revoked, subscription.canceled, and subscription.uncanceled.

Finally, point rdyrct.com at the Worker as a custom domain: Cloudflare dashboard → Workers → your worker → Settings → Domains & Routes. Short links live at the root (https://rdyrct.com/<slug>); the app is served on every other path.

Review the rate-limiting policies, monitoring, WAF rule, and rollback steps before the first production deploy.

Review the storage recovery and reconciliation guide before changing link, domain, logo, or organization delete flows.

Customer custom domains (Pro): to let orgs use links.theirbrand.com, enable Cloudflare for SaaS on the rdyrct.com zone, create an originless proxied fallback origin (e.g. fallback.rdyrct.com AAAA 100::), and add a Worker route */* pointing at the rdyrct worker. The CF_API_TOKEN needs permission Zone → SSL and Certificates → Edit scoped to the zone. Also verify your sending domain (e.g. mail.rdyrct.com) in Resend so transactional email isn't blocked.


Configuration

Name Kind Purpose
BETTER_AUTH_SECRET secret Signs sessions and tokens
SUPERADMIN_EMAIL secret The account that becomes the platform admin
RESEND_API_KEY secret Resend API key for transactional email
POLAR_ACCESS_TOKEN secret Polar API access token (scopes: checkouts:write, customer_sessions:write)
POLAR_WEBHOOK_SECRET secret Verifies Polar webhook signatures; endpoint https://rdyrct.com/api/webhooks/polar
CF_API_TOKEN secret Cloudflare token with Zone → SSL and Certificates → Edit (custom domains)
APP_URL var Full public URL of the app, e.g. https://rdyrct.com
APP_HOST var Public host, e.g. rdyrct.com
MAIL_FROM var From address for outgoing email
RESEND_BASE_URL var (dev only) Points at the local Resend emulator
POLAR_SERVER var sandbox or production
POLAR_PRO_PRODUCT_ID var Polar product id for the Pro plan
POLAR_HOBBY_PRODUCT_ID var Polar product id for the Hobby plan
CF_ZONE_ID var Zone id used for Custom Hostnames
DEV_FAKE_CF var (dev only) 1 to stub the Cloudflare API locally

Secrets are set with wrangler secret put NAME or wrangler secret bulk prod.secrets.env in production; locally they all come from .dev.vars (see .dev.vars.example).


Project layout

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
  plan.ts util.ts email.ts password.ts kv.ts storage.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)

License

MIT © Andrea Bruno. See LICENSE.

About

Open-source URL shortener for teams: branded short links, QR codes, and custom domains on Cloudflare Workers.

Topics

Resources

Stars

Watchers

Forks

Contributors

Languages

Morty Proxy This is a proxified and sanitized view of the page, visit original site.