Skip to content

themobilefirstco/kudoz-oss

Repository files navigation

Kudoz

Virtual currency system for teams. Give kudos, catch lateness, run QA sessions, spend in the shop.

Built by The Mobile First Company. Used daily by our team of 20+.


What is Kudoz?

Kudoz is an internal virtual currency that turns peer recognition into a game. Every day, each team member gets 6 kudoz to give to teammates for great work. Recipients accumulate kudoz in their bank and spend them on real rewards (AirPods, team lunches, a ping pong table).

It ships as a Slack bot + web dashboard, backed by Supabase.


How the Game Works

Daily Giving

  • Every team member gets 6 kudoz per day to distribute
  • Give 1-6 kudoz per transaction to one or multiple recipients
  • Amounts split evenly across multiple recipients
  • Unused daily kudoz do not carry over
  • You cannot give kudoz to yourself

QA Sessions (Multipliers)

  • Authorized users can start QA sessions lasting 30 minutes
  • During a session, any kudoz with QA-related descriptions (qa, bug, test, fix, issue) get multiplied by 2x to 5x
  • One active session at a time

Late Reports

  • Report teammates who are late to meetings (1-60 minutes)
  • Creates a public "Wall of Shame" on the leaderboard
  • Deduplication: same person can't be reported twice within 25 minutes

The Shop

  • Personal rewards: Spotify, AirPods, iPhone, Apple Studio Display (20-1000 kudoz)
  • Team rewards: Coffee machine, ping pong table, team lunch, karting (30-200 kudoz)
  • Purchases go to "pending" status; an admin fulfills them manually

Cagnotes (Group Purchases)

  • Pool kudoz toward expensive team rewards
  • Set a goal amount and deadline (max 6 months)
  • Contributors are tracked; if the deadline passes unfunded, kudoz are refunded

Birthdays & Anniversaries

  • Birthday: The bank automatically sends 50 kudoz on your birthday
  • Anniversary: The bank sends 500 kudoz per year of tenure (e.g., 2 years = 1000 kudoz)
  • Both post a celebration message to the Slack channel

Yearly Reset

  • All balances reset to 0 on December 31st at 23:59
  • Use it or lose it — spend before year-end!

Digests

  • Weekly: Friday 6pm — top givers, top receivers, total kudoz given
  • Monthly: 1st of the month at 9am — same stats for the past 30 days
  • Sent as DMs to all active users

Architecture

kudoz/
├── shared/          # Types, constants, validators, Supabase client
│   ├── types.ts
│   ├── constants.ts
│   ├── validators.ts
│   ├── supabase.ts
│   └── index.ts
├── bot/             # Slack bot (Socket Mode)
│   └── src/
│       ├── commands/   # /give, /late, /qa, /bank, /invite-kudoz
│       ├── cron/       # daily-reset, birthday, anniversary, digest, qa-reminder, yearly-reset
│       ├── events/     # team_join auto-registration
│       ├── services/   # kudoz, late, shop (DB operations)
│       ├── middleware/  # rate-limit, input validation
│       └── utils/      # Slack block builders, formatters
├── web/             # Next.js 16 dashboard
│   └── src/
│       ├── app/        # Pages: feed, banks, shop, admin, login
│       ├── components/ # UI components + kudoz-specific cards
│       └── lib/        # Auth, Supabase clients, utilities
├── supabase/        # SQL schema + migrations
├── Dockerfile       # Bot container for Railway
└── .env.example     # All environment variables

Data Flow

Slack Command → Bot (Socket Mode) → Supabase RPC (send_kudoz) → DB
                                                                 ↓
Web Dashboard ← Supabase Realtime ← Transactions table ←────────┘

Tech Stack

Component Technology
Bot @slack/bolt 4.x, Socket Mode, node-cron
Web Next.js 16, React 19, Tailwind CSS 4, shadcn/ui
Database Supabase (PostgreSQL + Realtime + Storage + RLS)
Auth Magic link (Resend email + JWT) + admin password
Monorepo pnpm workspaces
Bot deploy Docker on Railway (or any container host)
Web deploy Vercel

Database Schema

Tables

Table Purpose
users Team members with Slack ID, balance, roles, birthday, start date, country
transactions Every kudoz movement (give, bank_give, birthday, anniversary, purchase, cagnote)
daily_allowances Tracks remaining daily kudoz per user per day
late_reports Who was late, how many minutes, which meeting
rewards Shop items with price, category, stock, image
purchases Purchase records with status (pending/fulfilled/cancelled)
cagnotes Group purchase pools with goal, deadline, status
cagnote_contributions Individual contributions to cagnotes
qa_sessions Active QA multiplier sessions
system_settings Key-value settings (last reset dates)

Key RPC: send_kudoz()

The heart of the system. This PostgreSQL function handles:

  • Sender validation
  • Self-send prevention (except for bank-originated types)
  • Daily allowance check and deduction
  • Active QA session detection (keyword matching for multiplier)
  • Even split across multiple recipients
  • Atomic balance updates and transaction recording

All in a single database transaction — no partial states.

Row Level Security

  • All tables have RLS enabled
  • Public SELECT on all tables (the dashboard is transparent by design)
  • Writes only via service_role key (bot and API routes)

Slack Bot Commands

/give [1-6] @user description

Give kudoz to teammates. Amount is split across multiple recipients.

/give 6 @alice Great work on the API refactor
/give 3 @bob @charlie Excellent pair programming session

/late [1-60] @user meeting_name

Report lateness to a meeting.

/late 15 @bob standup
/late 5 @alice @charlie sprint review

/qa start [2-5] description

Start a QA session with a multiplier (authorized users only).

/qa start 3 Testing the new checkout flow

/bank

Check your balance, daily allowance remaining, and last 5 transactions.

/invite-kudoz @user birthday:YYYY-MM-DD started:YYYY-MM-DD country:US

Add a new team member to the system (all fields optional except the @mention).


Web Dashboard Pages

Route Description
/ Live feed with realtime transaction stream, contribution heatmap, search & filters
/banks Leaderboards (best givers, most received, wall of shame), all bank accounts
/banks/[id] Individual bank detail — balance, received, given, late stats, transaction history
/shop Rewards catalog, cagnote progress bars, purchase flow
/login Magic link login (email)
/admin Bank give, reward management, purchase fulfillment, user management, team events calendar

Cron Jobs

Schedule Job Description
Midnight daily daily-reset Cleans up allowance rows older than 7 days
9am daily birthday Checks for birthdays, awards 50 kudoz, posts to channel
9am daily anniversary Checks for work anniversaries, awards 500*years kudoz
Friday 6pm digest (weekly) DMs weekly stats to all users
1st of month 9am digest (monthly) DMs monthly stats to all users
Thursday 6pm qa-reminder Reminds QA starters to plan Friday sessions
Dec 31 23:59 yearly-reset Resets all balances to 0

All times in Europe/Paris timezone (configurable in shared/constants.ts).


Step-by-Step Deployment

1. Create a Supabase Project

Go to supabase.com, create a new project. Note your:

  • Project URL (https://xxxxx.supabase.co)
  • Anon key (public)
  • Service role key (secret)

2. Run the Database Schema

In the Supabase SQL Editor, run these files in order:

  1. supabase/001_initial.sql — Creates all tables, RPC functions, RLS policies
  2. supabase/002_add_user_country.sql — Adds country column

Then run supabase/seed.sql to insert example data (edit with your real team members first).

3. Create a Slack App

  1. Go to api.slack.com/apps
  2. Click "Create New App" → "From a manifest"
  3. Paste the contents of slack-app-manifest.yaml
  4. Install to your workspace
  5. Note your:
    • Bot Token (xoxb-...) from OAuth & Permissions
    • App Token (xapp-...) from Basic Information → App-Level Tokens (create one with connections:write scope)
    • Signing Secret from Basic Information
  6. Create a #kudoz channel and note its Channel ID

4. Set Environment Variables

Copy .env.example to .env.local and fill in all values:

cp .env.example .env.local
Variable Where to find it
SLACK_BOT_TOKEN Slack app → OAuth & Permissions
SLACK_APP_TOKEN Slack app → Basic Information → App-Level Tokens
SLACK_SIGNING_SECRET Slack app → Basic Information
KUDOZ_CHANNEL_ID Right-click channel → Copy Channel ID
NEXT_PUBLIC_SUPABASE_URL Supabase → Settings → API
NEXT_PUBLIC_SUPABASE_ANON_KEY Supabase → Settings → API
SUPABASE_SERVICE_ROLE_KEY Supabase → Settings → API
ADMIN_PASSWORD Choose a strong password
ADMIN_SECRET Random string (for admin cookie)
AUTH_SECRET Random string (for JWT signing)
RESEND_API_KEY resend.com → API Keys
NOTIFICATION_EMAIL Email for purchase notifications

5. Deploy the Bot

The bot runs as a Docker container. Deploy to Railway, Fly.io, or any Docker host.

Railway:

# Install Railway CLI
npm i -g @railway/cli

# Login and init
railway login
railway init

# Set env vars
railway variables set SLACK_BOT_TOKEN=xoxb-...
railway variables set SLACK_APP_TOKEN=xapp-...
# ... set all variables from .env.example

# Deploy
railway up

Or Docker directly:

docker build -t kudoz-bot .
docker run --env-file .env.local kudoz-bot

6. Deploy the Web Dashboard

Vercel (recommended):

# Install Vercel CLI
npm i -g vercel

# Deploy from the repo root
cd web
vercel --prod

Set the same environment variables in Vercel's dashboard (Settings → Environment Variables).

Root directory: web/ Build command: pnpm build Framework: Next.js

7. Seed Your Team

Edit supabase/seed.sql with your real team members' data, then:

  1. Replace SLACK_ID_* placeholders with actual Slack user IDs
  2. Set real names, emails, birthdays, start dates
  3. Run in the Supabase SQL Editor

Or use the /invite-kudoz Slack command to add users one by one.


Environment Variables

Variable Required Used By Description
SLACK_BOT_TOKEN Bot Bot Slack bot OAuth token
SLACK_APP_TOKEN Bot Bot Slack app-level token for Socket Mode
SLACK_SIGNING_SECRET Bot Bot Slack request signing secret
KUDOZ_CHANNEL_ID Bot Bot Channel ID for public announcements
NEXT_PUBLIC_SUPABASE_URL Both Web + Bot Supabase project URL
NEXT_PUBLIC_SUPABASE_ANON_KEY Web Web Supabase anonymous key
SUPABASE_SERVICE_ROLE_KEY Both Web + Bot Supabase service role key
SUPABASE_URL Bot Bot Supabase URL (alias)
DATABASE_URL Optional Migrations Direct PostgreSQL connection
ADMIN_PASSWORD Web Web Admin panel password
ADMIN_SECRET Web Web Admin cookie signing secret
AUTH_SECRET Web Web JWT signing secret for magic links
RESEND_API_KEY Web Web Resend API key for emails
NOTIFICATION_EMAIL Web Web Email for purchase notifications

Game Constants

All tunable values live in shared/constants.ts:

Constant Default Description
DAILY_ALLOWANCE 6 Kudoz each person can give per day
MAX_PER_GIVE 6 Max kudoz in a single /give command
MIN_PER_GIVE 1 Min kudoz in a single /give command
MAX_LATE_MINUTES 60 Max minutes for a late report
LATE_DEDUP_WINDOW_MINUTES 25 Prevent duplicate reports within this window
QA_MIN_MULTIPLIER 2 Minimum QA session multiplier
QA_MAX_MULTIPLIER 5 Maximum QA session multiplier
QA_DURATION_MINUTES 30 How long a QA session lasts
BIRTHDAY_BONUS 50 Kudoz awarded on birthday
ANNIVERSARY_BASE_BONUS 500 Kudoz per year of tenure
CAGNOTE_DEADLINE_MONTHS 6 Max deadline for group purchases
TIMEZONE Europe/Paris Timezone for all cron jobs
RATE_LIMIT_WINDOW_MS 60000 Rate limit window (1 min)
RATE_LIMIT_MAX_COMMANDS 20 Max commands per window
COUNTRIES AR, FR, US Office country options
ADMINS [] Slack usernames with admin rights
QA_STARTERS [] Slack usernames who can start QA

Customization Guide

Change the daily allowance

Edit DAILY_ALLOWANCE in shared/constants.ts. Also update the hardcoded 6 in the send_kudoz() RPC function in supabase/001_initial.sql.

Add new rewards

Use the admin panel (/admin → Rewards tab) or insert directly into the rewards table.

Change the timezone

Edit TIMEZONE in shared/constants.ts. All cron jobs use this value.

Change the email domain

Search for @yourcompany.com in the codebase and replace with your domain:

  • web/src/app/login/page.tsx
  • web/src/app/api/auth/login/route.ts

Change the Resend "from" address

Update the from field in:

  • web/src/app/api/auth/login/route.ts
  • web/src/app/api/shop/purchase/route.ts

Add office countries

Edit the COUNTRIES array in shared/constants.ts.

Set admins and QA starters

Edit ADMINS and QA_STARTERS in shared/constants.ts with your Slack usernames (lowercase).


Local Development

# Install dependencies
pnpm install

# Copy env vars
cp .env.example .env.local
# Fill in all values

# Start the web dashboard (port 4005)
pnpm dev:web

# Start the Slack bot (connects via Socket Mode)
pnpm dev:bot

Contributing

See CONTRIBUTING.md — oh wait, we removed it. Here's the gist:

  1. Fork this repo
  2. Create a branch
  3. Make your changes
  4. Open a PR

License

MIT — see LICENSE.


Built with love at The Mobile First Company.

About

Virtual currency system for teams. Give kudos, catch lateness, run QA sessions, spend in the shop. Slack bot + Next.js dashboard + Supabase.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors