尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗Roommates, ranked by how well you'd actually live together.
Rumi is a free roommate-matching web app for college students, launching at Arizona State University. Students verify a school email, answer how they live, and get a ranked list of every compatible student: a 0–100 score, the reasons behind it, and their dealbreakers filtered out. No swiping. Intros unlock a realtime chat, and groups of 2–4 can match together for bigger places. The app installs as a PWA.
The school is configurable: allowed email domains and neighborhoods live in the database, and public copy comes from environment variables.
Design: warm paper and near-black ink with one accent (Ember), Instrument Serif display type, Inter UI, layered shadows and a hand-tuned dark mode.
Motion:
transform and opacity.prefers-reduced-motion.| Area | Choice |
|---|---|
| Framework | Next.js 14 (App Router, Server Actions), React 18, TypeScript |
| Styling | Tailwind CSS v4 (CSS-first tokens), shadcn-style components on Radix primitives, vaul, sonner |
| Motion | Motion (motion/react), Lenis (landing only) |
| Backend | Supabase: Postgres with RLS on every table, Auth, Storage, Realtime |
| Validation | Zod, shared by client and server |
| Resend (production) / SMTP to Mailpit (local) | |
| Tests | Vitest (matching engine), Playwright (end-to-end) |
| Hosting | Vercel, with Vercel Cron |
The engine lives in src/lib/matching/engine.ts (pure TypeScript, unit tested).
S = Σ(weight × similarity) / Σ weight. Weights come from their own importance settings: skip 0, nice 1, important 3, must 6.score = round(100 × √(S_a × S_b)). A high score means each person fits what the other wants.Scores are stored per direction in match_scores. Saving preferences or finishing onboarding recomputes every pair involving that person, in both directions, and prunes pairs that now fail a filter. A nightly job (/api/cron/recompute) repairs anything a recompute missed. Crossing 85 for the first time creates a "strong new match" notification, and /api/cron/digest emails a daily summary.
Prerequisites: Node.js 20+, npm, and Docker (for the local Supabase stack). The Supabase CLI runs through npx, so there's nothing to install globally.
Install dependencies and create your env file:
git clone https://github.com/kjodhpur/Rumi.git
cd Rumi
npm install
cp .env.example .env.local
Start Supabase. This applies every migration in supabase/migrations and starts Postgres, Auth, Storage, Realtime and Mailpit:
npm run db:start
Fill in .env.local:
Copy the printed API URL, anon key and service_role key into NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY and SUPABASE_SERVICE_ROLE_KEY.
Generate the two secrets:
echo "TOKEN_ENCRYPTION_KEY=$(openssl rand -hex 32)" >> .env.local
echo "CRON_SECRET=$(openssl rand -hex 32)" >> .env.local
Set ADMIN_EMAILS to your school email to get the admin dashboard.
Seed demo students and start the app:
npm run seed
npm run dev
Open http://localhost:3000 and sign in with any @asu.edu address. Codes arrive in Mailpit at http://127.0.0.1:54324. Nothing is sent to a real inbox.
| Script | What it does |
|---|---|
npm run dev | Next.js dev server |
npm run build / npm start | Production build / serve |
npm run lint / npm run typecheck / npm run format | ESLint / tsc --noEmit / Prettier |
npm test | Vitest unit tests (matching engine) |
npm run test:e2e | Playwright end-to-end tests |
npm run db:start / db:stop | Start / stop the local Supabase stack |
npm run db:reset | Recreate the local database from migrations (then re-run npm run seed) |
npm run db:types | Regenerate src/types/database.ts from the local schema |
npm run seed | Seed 50 fictional students, groups and chats (local only) |
npm run brand:generate | Regenerate the wordmark glyphs and icons |
.env.example documents every variable. The important ones:
| Variable | Required | Purpose |
|---|---|---|
NEXT_PUBLIC_APP_URL | ✓ | Public URL, used for email links and OAuth redirects |
NEXT_PUBLIC_SUPABASE_URL / NEXT_PUBLIC_SUPABASE_ANON_KEY | ✓ | Supabase project |
SUPABASE_SERVICE_ROLE_KEY | ✓ | Server-only. Recompute, notifications, moderation, deletion |
TOKEN_ENCRYPTION_KEY | ✓ | 64 hex chars. AES-256-GCM for third-party tokens |
CRON_SECRET | ✓ in prod | Authenticates /api/cron/* (Vercel sends it automatically) |
ADMIN_EMAILS | Comma-separated admin accounts | |
RESEND_API_KEY / SMTP_URL / EMAIL_FROM | Notification email delivery | |
NEXT_PUBLIC_SUPPORT_EMAIL | Shown on suspension, legal and footer pages | |
NEXT_PUBLIC_LAUNCH_SCHOOL_*, NEXT_PUBLIC_CAMPUS_TZ | Campus copy and time zone (defaults: ASU) | |
MODERATION_WEBHOOK_URL | Slack/Discord-style webhook for reports and auto-flags | |
NEXT_PUBLIC_GOOGLE_AUTH_ENABLED | Shows "Continue with Google" | |
NEXT_PUBLIC_SPOTIFY_ENABLED, SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET, SPOTIFY_REDIRECT_URI | Optional Spotify connection | |
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, BEDROCK_MODEL_ID | Optional. Profile "Why you match" blurb via Bedrock in us-east-1 (default Claude Opus 5.5, effort max). Falls back to the usual reasons. | |
SEED_PHOTOS, SEED_ALLOW_REMOTE | Seeding options | |
PLAYWRIGHT_BASE_URL, PLAYWRIGHT_CHROMIUM_PATH, MAILPIT_URL | End-to-end test options |
npm run seed # 50 ASU students, two groups, sample chats
npm run seed -- --demo [email protected] # also gives your account intros and a chat
SEED_PHOTOS=unsplash npm run seed # try real portraits (falls back to monograms)
seed.asu.edu domain and are marked is_seed. Re-running replaces them.SEED_ALLOW_REMOTE=true is set. Use that for staging only, never production.Unit tests cover the matching engine (hard filters, weights, mutual scoring, reasons and edge cases), staff roles, consent visibility and data-retention rules against a fixed clock.
Database security tests (src/test/) sign in as each staff role and as students against the local stack and check what Row Level Security lets each one read and write. They run with npm test and skip themselves when the local stack isn't running.
npm test
End-to-end tests run against the local stack and the dev server, which Playwright starts if it isn't already running. They read sign-in codes from Mailpit and create, then delete, their own users through the service role. The suite covers:
Onboarding and matching also run at a 375px mobile viewport.
npm run db:start && npm run seed # once
npx playwright install chromium # once, or set PLAYWRIGHT_CHROMIUM_PATH
npm run test:e2e
Measured with Lighthouse 12 on a local production build, served through a proxy that adds CDN-like latency, with Lighthouse's default throttling. Scores move from run to run on a shared machine, so ranges are shown.
| Page | Mobile | Desktop |
|---|---|---|
| Landing | 92–98 | 99 |
| Sign-in | 97 | 100 |
| Matches (signed in) | 75–96, median 85 | 99 |
Accessibility, Best Practices and SEO score 100 on all three pages.
What keeps it fast:
Known limit. On mobile, Matches is held back by Total Blocking Time (150–720 ms under Lighthouse's 4× CPU slowdown). Most of it is the Next.js and React runtime hydrating the signed-in page, then the animation library and the Supabase client. The realtime client already waits for idle time, but on a slow device it still runs inside the measured window.
Create a project at supabase.com, then push the schema:
npx supabase@2 login
npx supabase@2 link --project-ref <your-project-ref>
npx supabase@2 db push # applies supabase/migrations (tables, RLS, functions, storage, realtime, ASU data)
Authentication → URL Configuration:
https://<your-domain>/auth/callback and https://<your-domain>/auth/confirm to the redirect URLs.Authentication → Email Templates: for both Confirm signup (first sign-in) and Magic Link (returning students):
supabase/templates/otp.html.Your Rumi code: {{ .Token }}.The app signs people in with the 6-digit code; local development uses the same template via supabase/config.toml.
Authentication → SMTP Settings: use your own SMTP (for example Resend's SMTP). The built-in sender is rate-limited and meant only for testing.
(Optional) Authentication → Providers → Google: enable it and set NEXT_PUBLIC_GOOGLE_AUTH_ENABLED=true.
Import the repository in Vercel. The framework preset is detected as Next.js.
Add the environment variables from .env.example. At minimum:
NEXT_PUBLIC_APP_URLTOKEN_ENCRYPTION_KEYCRON_SECRETADMIN_EMAILSRESEND_API_KEY and EMAIL_FROMDeploy. vercel.json schedules two cron jobs:
/api/cron/recompute daily at 09:15 UTC/api/cron/digest daily at 17:00 UTC (10:00 in Phoenix)Hobby plans allow daily crons; on Pro you can run the repair job more often.
(Optional) Spotify:
https://<your-domain>/api/spotify/callback as a redirect URI.SPOTIFY_* variables and NEXT_PUBLIC_SPOTIFY_ENABLED=true.Sign in with an address listed in ADMIN_EMAILS to reach /admin. On mobile it's under Settings → Safety admin.
Allowed domains and neighborhoods are data:
insert into public.schools (id, name, short_name, email_domains, timezone)
values ('ucla', 'University of California, Los Angeles', 'UCLA', array['ucla.edu', 'g.ucla.edu'], 'America/Los_Angeles');
insert into public.areas (school_id, slug, name, description, sort_order) values
('ucla', 'westwood', 'Westwood', 'Walkable to campus.', 1),
('ucla', 'palms', 'Palms', 'Lower rents, Expo line.', 2);
Students are matched only within their own school. For a deployment dedicated to another campus, set the NEXT_PUBLIC_LAUNCH_SCHOOL_* variables so public pages use the right name, domain, city and campus police number.
Housing offices get their own workspace at /staff, separate from the student app. The build plan is in docs/MASTER-PROMPT.md; each phase's design is in docs/phase-N.md, and progress is logged in docs/PROGRESS.md.
ADMIN_EMAILS) can act for every school. Schools have housing admins, housing staff, RAs (scoped to buildings), analysts (totals only) and moderators. src/lib/staff/roles.ts lists what each role can do.housing_office_name, so students are never told an office is involved before a signed pilot exists./api/cron/recompute) applies it; /api/cron/retention runs it on demand.src/lib/matching/blossom.ts). Staff approve and send. Each student sees the suggestion at , and a two-person group with a chat forms only if both say yes.To give a school its first housing admin, sign in as a platform admin, open /staff, pick the school and send an invite from Team.
can_view_profile(). It checks same school, onboarding finished, not banned, not blocked, the hidden profile setting, the verified-only setting, the school's demo-profile switch, and that neither side is a staff account.has_role() and staff_scope_includes(); src/test/rls-staff.test.ts proves each role sees only what it should.security definer functions that check auth.uid().next.config.mjs).Next.js 14 advisories. The project targets Next.js 14 as specified. The latest 14.x release (14.2.35) still has published advisories, several of them critical, that are only fixed in Next 15/16.
Mitigations in place:
Before a public launch, plan an upgrade to the current Next.js major (npm audit lists the advisories).
src/
app/
(app)/ signed-in app: matches, profile/[id], messages, groups, notifications, settings, admin
staff/ housing staff workspace (team, privacy & retention, audit log, …)
invite/[token] staff invite acceptance
(auth)/login email-code sign-in
onboarding/ 10-step wizard
api/ matches feed, profile detail, Spotify OAuth, data export, cron jobs
actions/ server actions (auth, onboarding, photos, social, messages, groups, settings, admin…)
privacy, terms, offline, suspended, manifest.ts
components/ ui/ (design system), marketing/, matches/, profile/, chat/, groups/, settings/, admin/…
lib/
matching/ engine (pure) + recompute pipeline
supabase/ browser, server, admin and middleware clients
email/ templates, delivery, notification fan-out
… validation, rate limits, moderation, crypto, Spotify, time
supabase/
migrations/ schema, functions, RLS and grants, storage and realtime, reference data
templates/ sign-in code email
scripts/ seed data and brand asset generation
e2e/ Playwright specs and helpers
docs/PROPOSAL.md schema, page map, design tokens and motion spec
docs/phase-N.md design of each housing-staff phase (see MASTER-PROMPT.md, PROGRESS.md)
Rumi is an independent student project and is not affiliated with Arizona State University.
/staff). A separate workspace for a school's housing office. Free for students, always. See Housing staff./suggestions/[id]EntryID, Email, GroupName, GroupLeader, GroupSize, Term). Students can add an optional, encrypted student ID in Settings → Privacy. Cells are quoted and defused against spreadsheet formulas, and every export is audited./staff/ra see medium and high risk only when the student shared the check-in or asked for help, and only for buildings in their scope. The note stays hidden unless it was shared. Crisis language shows 988 to the student and is not copied to staff unless they shared the note./staff/outcomes shows confirmed groups, signed agreements and the check-in average, only from students who consented. Counts of 1–4 show as "<5". The agreement rate includes a 95% Wilson interval once there are at least 5 groups. With one arm there is nothing to call statistically significant.