NBA Feed
팀 뉴스와 경기 정보를 제공, 점수는 직접 확인할 때까지 숨겨져 있습니다
실시간 그룹 AMRAP 타이머로 미션을 주최·참여하고, 전화 간 카운트다운을 동기화해 순위표를 함께 경쟁
Live group AMRAP workout timer. Host or join a mission, sync one countdown across phones, and race the leaderboard together.
스포츠·피트니스TypeScript · PLpgSQLGitHub @jlfassio-vibecoder온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Standalone rebuild of AMRAP With Friends — social AMRAP workout sessions
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
AMRAP With Friends is a standalone web app for running social AMRAP (As Many Rounds As Possible) missions with friends in real time. This repository is a from-scratch rebuild focused on a single, self-contained experience—plan or join a mission, sync the timer, and track rounds together.
Plan mission (/create) also offers AMQAP — as many quality rounds as possible. That is a continuous mobility flow (I1, 10 or 15 minutes), not a metabolic race. See AMQAP quality flows.
The dev server runs at http://localhost:5173.README 전문 보기 ↗AMRAP With Friends is a standalone web app for running social AMRAP (As Many Rounds As Possible) missions with friends in real time. This repository is a from-scratch rebuild focused on a single, self-contained experience—plan or join a mission, sync the timer, and track rounds together.
Plan mission (/create) also offers AMQAP — as many quality rounds as possible. That is a continuous mobility flow (I1, 10 or 15 minutes), not a metabolic race. See AMQAP quality flows.
npm install
cp .env.example .env
# Fill in VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY in .env
npm run dev
The dev server runs at http://localhost:5173.
| Command | Description |
|---|---|
npm run build | Type-check and production build |
npm run lint | ESLint |
npm run typecheck | TypeScript project references build |
npm run test | Vitest (single run) |
npm run format | Prettier |
npm run seed:exercise-media | Manual: seed empty exercise-media/{id}/.keep folders in Supabase Storage |
npx tsx scripts/sync-exercise-media-folders.ts | Compare the library + AMQAP catalog to the bucket and seed only missing folders |
When you add exercises to src/data/exerciseLibrary.ts and want empty folders visible in the Supabase Storage dashboard before uploading real photos/video:
SUPABASE_SERVICE_ROLE_KEY in .env (never prefix with VITE_).npm run seed:exercise-media once from your machine.npm run seed:exercise-media reads EXERCISE_LIBRARY and upserts ${id}/.keep placeholders. Prefer npx tsx scripts/sync-exercise-media-folders.ts when you only want folders that are missing (it also walks AMQAP flows). Neither script is part of the app runtime or CI — re-run when new exercise ids appear.
Upload sequence stills as {exerciseId}/sequence.jpeg or {exerciseId}/sequence.png in the exercise-media bucket (Gemini → .jpeg, ChatGPT → .png). The library defaults to .jpeg; the info modal falls back across .jpeg / .png / .jpg if the first path 404s. AMQAP movements have folders in the bucket; stills are not required for How-to copy to ship.
AMQAP is a continuous mobility protocol, not a library category. Putting I1 recovery into WORKOUT_TEMPLATES would mix it into the race picker, show 5/20 “Soon” chips, and publish Astro movement pages for templates that are not in the metabolic catalog. The flows live in their own module and launch as a normal mission (existing clock and rounds). Time-in-Flow scoring and a live “move slowly” engine are not in this pass.
| Piece | Where |
|---|---|
| Science and execution rules | docs/workouts/mobility-amrap-scientific-investigation.md |
| Catalog (5 families × 10 and 15 min) | src/data/amqapFlows.ts |
| Plan mission picker | src/components/createMission/AmqapFlowPicker.tsx |
| How-to write-ups | src/data/exerciseLibrary.ts (ids such as pigeon-pose, 90-90-hip-transitions) |
| Scaling (prop / smaller range) | src/data/exerciseScaling.ts — MOBILITY_LADDER |
What ships today:
Intensity is I1. Launch still uses create_mission workout jsonb. These ids are not added to featuredWorkouts or the SEO content pages.
Rally point schema and RPCs live in supabase/migrations/. Apply with the Supabase CLI (supabase db push) or paste into the Supabase SQL editor. Use a service-role key only on your machine for admin tasks—never in the client or .env bundled with the app.
Manual RPC checks: supabase/scripts/verify_rally_point_rpc.sql.
CI runs lint, typecheck and tests — it never executes SQL, so a migration that does not parse reaches production unchallenged. To replay the whole history against a throwaway local Postgres before pushing:
service postgresql start && createdb awf_replayauth schema with a users table and a uid() function, the anon /
authenticated / service_role roles, pgcrypto in extensions, and a
storage schema.supabase/migrations/*.sql in filename order with
psql -v ON_ERROR_STOP=1.Two migrations fail a from-scratch replay for reasons unrelated to their SQL:
20260822110000_lobby_schema_review_fixes.sql drops a constraint that
rounds depends on, and 20260829140000_coach_exercise_media_owner_policies.sql
calls storage.foldername(), which only exists on hosted Supabase. Everything
after them replays clean.
Exercising an RPC afterwards needs a row in auth.users, a matching
athlete_profiles row (several columns are NOT NULL, and
perceived_classification is one of civilian / operator / special_ops),
then SET request.jwt.claim.sub = '<uuid>' so auth.uid() resolves.
Note that create_mission is overloaded such that a positional 3-argument call
is ambiguous. The client always sends all seven named parameters, so this never
bites in production, but a hand-written psql call has to use the 7-argument
form.
After linking the project (supabase link --project-ref <ref>):
supabase db push
supabase functions deploy submit-participant-result
submit-participant-result must be deployed or finishing a workout (partial reps / I EARNED THIS) fails with a CORS or network error. If claim-status RPCs 404, run supabase db push so repair migrations (e.g. get_participant_claim_status) are applied.
Enable Supabase Auth email provider and redirect URLs for your dev origin (e.g. http://localhost:5173). Sign-in is email + password by default.
Custom SMTP is configured: Resend, on a verified sending domain, with Supabase Auth's send limit at 30 emails/hour. That limit governs auth mail only (confirmation, magic link, password reset) — it does not apply to anything calling the Resend API directly. Both mail-dependent flags are therefore on in .env:
VITE_AUTH_MAGIC_LINK_ENABLED=true — magic-link sign-in in AuthModal.VITE_AUTH_PASSWORD_RESET_ENABLED=true — Forgot password? and /reset-password. Keep /reset-password in Auth → URL Configuration → Redirect URLs, or the emailed link lands on an error.Both default to false when unset, so a fresh clone stays safe. VITE_* flags bake in at build time — set them in Vercel as well, then redeploy.
Google OAuth (Continue with Google) stays off until VITE_AUTH_GOOGLE_ENABLED=true. Before enabling: create a Google Cloud OAuth 2.0 Web client with authorized redirect URI https://<project-ref>.supabase.co/auth/v1/callback, enable Google under Dashboard → Authentication → Providers, and keep Site URL / redirect allow-list covering production (https://www.amrapwithfriends.com/**), apex if used, and http://localhost:5173/**. VITE_* flags are bake-in at build time — set the Vercel env var, then redeploy.
Google HITL (after the flag is on):
/intake → email/password sign-in works.error query params are stripped from the URL.Hosted vs local auth settings: Local supabase/config.toml sets enable_confirmations = false and minimum_password_length = 6. The hosted dashboard may differ (Confirm email is often ON by default; password minimum may change). Before shipping to prod, check Dashboard → Authentication → Providers → Email and align AUTH_MIN_PASSWORD_LENGTH with the hosted minimum if needed.
After supabase db push for 20260822140000_auth_claim.sql:
Follow-up (out of scope): Resend confirmation email; confirm-password on Create account.
This project is a deliberate from-scratch rebuild of the AMRAP With Friends experience from the interval-timers monorepo. Several features from the reference app are intentionally excluded:
The app is fully standalone—not embeddable into another product. Supabase integration uses @supabase/supabase-js only (createClient); @supabase/ssr and cross-subdomain cookie auth are omitted until multi-subdomain auth is actually needed.