Files
PoleDanceApp/dancechamp-claude-code/CLAUDE.md
Dianaka123 789d2bf0a6 Full app rebuild: FastAPI backend + React Native mobile with auth, championships, admin
Backend (FastAPI + SQLAlchemy + SQLite):
- JWT auth with access/refresh tokens, bcrypt password hashing
- User model with member/organizer/admin roles, auto-approve members
- Championship, Registration, ParticipantList, Notification models
- Alembic async migrations, seed data with test users
- Registration endpoint returns tokens for members, pending for organizers
- /registrations/my returns championship title/date/location via eager loading
- Admin endpoints: list users, approve/reject organizers

Mobile (React Native + Expo + TypeScript):
- Zustand auth store, Axios client with token refresh interceptor
- Role-based registration (Member vs Organizer) with contextual form labels
- Tab navigation with Ionicons, safe area headers, admin tab for admin role
- Championships list with status badges, detail screen with registration progress
- My Registrations with championship title, progress bar, and tap-to-navigate
- Admin panel with pending/all filter, approve/reject with confirmation
- Profile screen with role badge, Ionicons info rows, sign out
- Password visibility toggle (Ionicons), keyboard flow hints (returnKeyType)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 22:46:50 +03:00

6.9 KiB

CLAUDE.md — DanceChamp

What is this project?

DanceChamp is a mobile platform for pole dance championships. Three apps, one database:

  • Member App (React Native / Expo) — Dancers discover championships, register, track their 10-step progress
  • Org App (React Native / Expo) — Championship organizers create events, manage members, review videos, confirm payments
  • Admin Panel (React + Vite, web) — Platform admin approves orgs, reviews championships from unverified orgs, manages users

Project Structure

/
├── CLAUDE.md                    ← You are here
├── apps/
│   ├── mobile/                  ← Expo app (Member + Org views, switched by role)
│   │   ├── src/
│   │   │   ├── screens/
│   │   │   │   ├── member/      ← Home, MyChamps, Search, Profile, ChampDetail, Progress
│   │   │   │   ├── org/         ← Dashboard, ChampDetail (tabbed), MemberDetail, Settings
│   │   │   │   └── auth/        ← SignIn, SignUp, Onboarding
│   │   │   ├── components/      ← Shared UI components
│   │   │   ├── navigation/      ← Tab + Stack navigators
│   │   │   ├── store/           ← Zustand stores
│   │   │   ├── lib/             ← Supabase client, helpers
│   │   │   └── theme/           ← Colors, fonts, spacing
│   │   └── app.json
│   └── admin/                   ← Vite React app
│       └── src/
│           ├── pages/           ← Dashboard, Orgs, Champs, Users
│           ├── components/
│           └── lib/
├── packages/
│   └── shared/                  ← Shared types, constants, validation
│       ├── types.ts             ← TypeScript interfaces (User, Championship, etc.)
│       └── constants.ts         ← Status enums, role enums
├── supabase/
│   ├── migrations/              ← SQL migration files
│   └── seed.sql                 ← Demo data
└── docs/
    ├── SPEC.md                  ← Full technical specification
    ├── PLAN.md                  ← Phase-by-phase dev plan with checkboxes
    ├── DATABASE.md              ← Complete database schema + RLS policies
    ├── DESIGN-SYSTEM.md         ← Colors, fonts, components, patterns
    └── SCREENS.md               ← Screen-by-screen reference for all 3 apps

Tech Stack

Layer Choice Notes
Mobile React Native (Expo) npx create-expo-app with TypeScript
Admin React + Vite Separate web app
Language TypeScript Everywhere
Navigation React Navigation Bottom tabs + stack
State Zustand Lightweight stores
Backend Supabase Auth, Postgres DB, Storage, Realtime, Edge Functions
Push Expo Notifications Via Supabase Edge Function triggers

Key Architecture Decisions

1. One mobile app, two views

Member and Org use the same Expo app. After login, the app checks user.role and shows the appropriate navigation:

  • role === "member" → Member tabs (Home, My Champs, Search, Profile)
  • role === "organization" → Org tabs (Dashboard, Settings)

2. Everything is scoped per-championship

Members, results, categories, rules, fees, judges — all belong to a specific championship. There is no "global members list" for an org. Each championship is self-contained.

3. Configurable tabs (Org)

Orgs don't fill a giant wizard. They quick-create a championship (name + date + location), then configure each section (Categories, Fees, Rules, Judges) at their own pace. Each section has a "✓ Mark as Done" button. Championship can only go live when all sections are done.

4. Approval flow

  • Verified orgs → "Go Live" sets status to live immediately (auto-approved)
  • Unverified orgs → "Go Live" sets status to pending_approval → admin must approve

5. Registration dates (not deadline)

Championships have: event_date, reg_start, reg_end. Registration close date must be before event date. No single "deadline" field.

6. Judges = People, Scoring = Rules

The "Judges" tab shows judge profiles (name, instagram, bio). Scoring criteria and penalties live in the "Rules" tab.

Conventions

Code Style

  • Functional components only, no class components
  • Use hooks: useState, useEffect, custom hooks for data fetching
  • Zustand for global state (auth, current user, championships cache)
  • Local state for UI-only state (modals, form inputs, filters)
  • TypeScript strict mode

Naming

  • Files: kebab-case.ts / kebab-case.tsx
  • Components: PascalCase
  • Hooks: useCamelCase
  • Zustand stores: use[Name]Store
  • DB tables: snake_case
  • DB columns: snake_case

Supabase Patterns

// Client init
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY)

// Fetching
const { data, error } = await supabase
  .from('championships')
  .select('*, disciplines(*), fees(*)')
  .eq('status', 'live')

// Realtime subscription
supabase.channel('registrations')
  .on('postgres_changes', { event: '*', schema: 'public', table: 'registrations' }, handler)
  .subscribe()

Navigation Pattern

// Member
const MemberTabs = () => (
  <Tab.Navigator>
    <Tab.Screen name="Home" component={HomeStack} />
    <Tab.Screen name="MyChamps" component={MyChampsStack} />
    <Tab.Screen name="Search" component={SearchStack} />
    <Tab.Screen name="Profile" component={ProfileStack} />
  </Tab.Navigator>
)

// Org
const OrgTabs = () => (
  <Tab.Navigator>
    <Tab.Screen name="Dashboard" component={DashboardStack} />
    <Tab.Screen name="Settings" component={SettingsStack} />
  </Tab.Navigator>
)

Important Docs

Before coding any feature, read the relevant doc:

Doc When to read
docs/SPEC.md Full feature spec — read first for any new feature
docs/PLAN.md Dev plan with phases — check what's next
docs/DATABASE.md Schema — read before any DB work
docs/DESIGN-SYSTEM.md UI — read before any screen work
docs/SCREENS.md Screen details — read before building specific screens

Quick Commands

# Start mobile app
cd apps/mobile && npx expo start

# Start admin panel
cd apps/admin && npm run dev

# Supabase local dev
npx supabase start
npx supabase db reset  # Reset + re-seed

# Generate types from Supabase
npx supabase gen types typescript --local > packages/shared/database.types.ts

Current Status

Prototypes completed (JSX files in /prototypes):

  • dance-champ-mvp.jsx — Member app prototype
  • dance-champ-org.jsx — Org app prototype
  • dance-champ-admin.jsx — Admin panel prototype

These are reference implementations showing the exact UI, data structure, and flows. Use them as visual guides — don't copy the code directly (they're single-file React prototypes, not production React Native).