WallpaperMachine
당신이 사랑하는 배경화면, 맥에서 새롭게 만나보세요
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Build a perfume collection, choose which notes you care about, and get recommendations built from them.
Live app: https://dbs-w4.vercel.app. Sign up with any email; your data is private to your account.
MPCS 51238 Design, Build, Ship, Assignment 4 (full stack app with Clerk, Supabase and one external API).
Everything you save is still there after you sign out and back in, on any device.
| Part | Choice |
|---|---|
| App | Next.js 16 (App Router, Cache Components) + Tailwind CSS 4 |
| Sign-in | Clerk (development instance) |
| Database | Supabase Postgres, connected to Clerk with Supabase third-party auth |
| External API | 10ML Fragrance Index: free, no key, read-only |
| Test | Playwright with @clerk/testing |
| Hosting | Vercel (Hobby) |
Browser ──▶ Next.js server (Vercel) ──▶ 10ML API (perfume search, details, similar)
│
├──▶ Clerk (who is signed in, session token)
└──▶ Supabase + RLS (collection, wishlist, favorites)
src/proxy.ts) runs clerkMiddleware(), and each
private page calls auth.protect(), so a signed-out visitor is sent to sign in.src/lib/supabase/server.ts). Supabase trusts Clerk as a third-party auth provider, and every table has
row-level security: (select auth.jwt()->>'sub') = user_id. The app never filters by user itself; the
database does. Only the publishable key is used. The service-role key is never used anywhere, so RLS
always applies.src/lib/tenml.ts), never from the browser. Responses
are cached for a few minutes with "use cache", failures become an "unavailable" state instead of an
error page, and no key is involved. Every API view has designed loading, nothing found, and unavailable
states.user_id column defaults to the Clerk user ID, so the browser never sends it.Every table has a user_id (the Clerk user ID), RLS enabled, and select / insert / update / delete
policies for signed-in users on their own rows only. Signed-out visitors get no policies, so they read
nothing. Recommendations aren't stored; they're computed on each visit.
| Table | Holds |
|---|---|
collection_items | Perfumes in your collection, with the notes you've chosen to leave out |
wishlist_items | Perfumes you want but don't own yet |
taste_preferences | One row per person: favorite notes and accords |
Full column definitions are in AGENTS.md; the SQL is in supabase/migrations.
Install dependencies:
npm install
Create .env.local with your own keys (never commit it):
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=
CLERK_SECRET_KEY=
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=
In Supabase, add Clerk as a third-party auth provider (Authentication → Sign In / Providers → Clerk) and
apply the migrations in supabase/migrations.
Start the dev server and open http://localhost:3000:
npm run dev
e2e/rls.spec.ts signs in two users in separate browsers. Each one saves a different
perfume, and the test checks that neither can see the other's, even by opening the other's perfume URL.
To run it, create two test users in your Clerk development instance (emails with +clerk_test, e.g.
[email protected]) and add them to .env.local:
E2E_USER_A_EMAIL=
E2E_USER_B_EMAIL=
Then:
npm run test:e2e
Watching it fail first. I broke row-level security on purpose by changing the select policy to
using (true) (migration). The test
failed because user A's collection showed user B's perfume (Expected: 0, Received: 1). The full output is
in docs/rls-test-failed.txt. Restoring the policy
(migration) made it pass again.
.env.local and in Vercel environment variables. A deny rule in
.claude/settings.json stops the coding agent from reading .env files./security-review run before merging.