尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗Find your artists. Catch the moment. Go together.
A mobile-first music and concert discovery app. It imports your top artists from Spotify, lets you curate a fan list, watches official ticket providers for concerts and sale dates near you, and lets accepted friends see shared artists and coordinate plans.
This repository implements the Phase 1 foundation of the product spec (v0.2), with the social data model, access control and core social flows already in place.
| Layer | Choice |
|---|---|
| App | Next.js 16 (App Router, TypeScript, Server Actions), Tailwind CSS v4 |
| Data | Supabase Postgres with row-level security on every table |
| Auth | Supabase Auth with Spotify OAuth (authorisation code + PKCE) |
| Jobs | Daily Vercel cron for data, pg_cron every 5 min for reminder delivery, or pnpm worker locally; all state in Postgres |
| Tests | Vitest (unit) and pgTAP (database access control and pipelines) |
Prerequisites: Node 22+, pnpm 10, Docker (for local Supabase).
pnpm install
cp .env.example .env.local # then fill in the values (see below)
pnpm db:start # local Postgres, Auth and API in Docker; applies migrations
pnpm dev # http://127.0.0.1:3000
pnpm worker # background jobs, in a second terminal
pnpm exec supabase status prints the local PUBLISHABLE_KEY and SECRET_KEY for .env.local.
http://127.0.0.1:54321/auth/v1/callback. Spotify rejects localhost.SPOTIFY_CLIENT_ID and SPOTIFY_CLIENT_SECRET in .env.local, and export them (or place them in supabase/.env) before pnpm db:start, because supabase/config.toml reads them for the Auth provider.Set TICKETMASTER_API_KEY. Without it, the event jobs log skipped and the app shows explicit "no concerts yet" states. Nothing is faked.
pnpm dev:fixtures (local Supabase only; it refuses any other URL) creates two test accounts and pushes Ticketmaster-shaped payloads through the real pipeline: normaliser → ingest_provider_event → notification scheduling → delivery. Use it to exercise every screen. It is never imported by the app.
| Script | Purpose |
|---|---|
pnpm dev / build / start | Next.js |
pnpm check | Typecheck + lint + unit tests |
pnpm test | Vitest unit tests |
pnpm db:test | pgTAP: RLS, privilege and pipeline tests against the local database |
pnpm db:reset | Recreate the local database from migrations |
pnpm db:types | Regenerate src/lib/database.types.ts from the local schema |
pnpm worker / worker:once | Run background jobs continuously or once (--job=<name> for one job, e.g. --job=concert-search) |
src/
app/ routes (App Router)
(app)/ authenticated screens: discover, artists, friends, saved, profile, events, notifications
onboarding/ five-step first-run flow
auth/callback/ OAuth callback: stores encrypted Spotify tokens server-side
api/cron/[job]/ authenticated hosted-cron entry point
components/ shared design-system components
lib/ pure, client-safe logic: events, ranking, formatting, env, types
server/
actions/ server actions (session re-verified, input validated with zod)
data/ per-user read models (RLS-scoped queries)
providers/ provider adapter contract, Ticketmaster client + normaliser, artist matching
spotify/ Spotify API client and sync
notifications/ pure delivery decision, delivery, Web Push
jobs/ job registry and runner (logs to job_runs)
supabase/
migrations/ schema, RLS/grants/social RPCs, pipelines, reference cities
tests/database/ pgTAP tests
scripts/ worker and local fixtures
tests/ unit tests
security definer SQL functions that only service_role may execute. They are transactional and idempotent, so retries never duplicate artists, events or notifications.events.lifecycle_status holds the provider status. Sale phases live in event_sales and ticket categories in ticket_offers. The UI derives "presale scheduled", "on sale" and so on (src/lib/events.ts).decide() re-checks event status, sale time, preferences, friendship and quiet hours. Stale reminders are cancelled when an event changes. Time-critical alerts during quiet hours go to the inbox without push; others are deferred.security definer RPC that checks friendship, visibility and blocks. Blocking overrides everything. Tokens are AES-256-GCM encrypted, and their columns are not even selectable by the owner's client.src/lib/ranking.ts is rules-based, and every point carries a human-readable reason. Cancelled, postponed and stale events always sink. Affiliate status is not an input.text-muted is lightened from #897C7D to #9C8E8F: the original measured 4.16:1 on surface and 3.54:1 on surface-elevated, below WCAG AA. A border-strong token (#857579) is added for 3:1 control boundaries. tests/foundation.test.ts verifies every pair.users.home_location_id → user_locations → reference cities. No precise coordinates are ever stored for users.user_artists.is_dismissed instead of deleting the row, so the weekly Spotify import does not silently re-add it. The canonical artist is untouched.supabase link and supabase db push, and enable the Spotify provider in Auth (same client ID/secret; add the hosted callback URL in Spotify)..env.example. Set NEXT_PUBLIC_APP_URL to the public URL and add <app-url>/auth/callback to Supabase Auth → URL configuration → redirect URLs.vercel.json runs /api/cron/daily at 05:00 UTC. It runs the weekly Spotify sync for accounts that are due, matches new artists on Ticketmaster, refreshes concert lists (one request per artist), delivers anything already due and cleans up, all within a 270 s budget. Work that doesn't fit is picked up the next day, oldest first.after(), so new users don't wait for the next daily run.pg_cron + pg_net) calls /api/cron/notifications-deliver, which only delivers reminders that were already scheduled. It needs two Vault secrets, set once in the Supabase SQL editor:
select vault.create_secret('https://<your-app>.vercel.app', 'encore_app_url');
select vault.create_secret('<same value as CRON_SECRET>', 'encore_cron_secret');
Without them the trigger does nothing (local development uses pnpm worker instead).pnpm worker on any Node host.Jobs are safe to run concurrently or retry: claims use FOR UPDATE SKIP LOCKED leases and every write is idempotent. Failed runs are recorded in job_runs.
Ticket availability (sold out / few left): the Discovery API has no such field, and Ticketmaster's Inventory Status API rejects standard keys ("Invalid ApiKey for given resource"). It needs partner access from Ticketmaster; Encore only shows the provider's "off sale" status until then.
Spotify and Ticketmaster against live APIs. Both integrations are implemented against the documented APIs, but no real credentials were available while building, so neither has been exercised live. Spotify development-mode and quota restrictions change over time; check the current Web API policies before launch.
Song previews come from Deezer's public API (popular tracks + 30-second previews), because Spotify no longer offers top tracks or preview URLs to development-mode apps. Audio streams from Deezer and is never stored. Review Deezer's API terms for commercial use before a public launch.
Phase 2/3 items: companion invitations ("Ask to join"), reporting, artist swipe discovery, EVENTIM adapter, affiliate links.
Legal: /legal holds draft product notes and must be replaced by a reviewed privacy policy, imprint and terms before public launch.
Native push reliability differs per platform: iOS supports Web Push only for installed PWAs. The in-app inbox is always the source of truth.