# SmoothSchedule Frontend Development Guide ## Project Overview This is the React frontend for SmoothSchedule, a multi-tenant scheduling platform. **See also:** `/home/poduck/Desktop/smoothschedule2/smoothschedule/CLAUDE.md` for backend documentation. ## Key Paths ``` /home/poduck/Desktop/smoothschedule2/ ├── frontend/ # This React frontend │ ├── src/ │ │ ├── api/client.ts # Axios API client │ │ ├── components/ # Reusable components │ │ ├── hooks/ # React Query hooks (useResources, useAuth, etc.) │ │ ├── pages/ # Page components │ │ ├── types.ts # TypeScript interfaces │ │ ├── i18n/locales/en.json # English translations │ │ └── utils/cookies.ts # Cookie utilities │ ├── .env.development # Frontend env vars │ └── vite.config.ts # Vite configuration │ └── smoothschedule/ # Django backend (runs in Docker!) ├── docker-compose.local.yml # Docker config ├── .envs/.local/ # Backend env vars ├── config/settings/ # Django settings └── smoothschedule/ ├── schedule/ # Core scheduling app └── users/ # User management ``` ## Local Development Domain Setup ### Why lvh.me instead of localhost? This project uses **lvh.me** for local development instead of `localhost` due to cookie domain restrictions in RFC 6265. **The Problem with localhost:** - Browsers reject cookies with `domain=.localhost` for security reasons - `localhost` is treated as a special-use domain where domain cookies don't work - Cannot share cookies across subdomains like `platform.localhost` and `business.localhost` **The Solution - lvh.me:** - `lvh.me` is a public DNS service that resolves all `*.lvh.me` domains to `127.0.0.1` - Browsers allow setting cookies with `domain=.lvh.me` - Cookies are accessible across all subdomains (platform.lvh.me, business1.lvh.me, etc.) - No /etc/hosts configuration needed - it just works! ### Development URLs Use these URLs for local development: - **Base domain:** `http://lvh.me:5173` - **Platform dashboard:** `http://platform.lvh.me:5173` - **Business subdomains:** `http://{subdomain}.lvh.me:5173` ### Multi-Tenant Architecture The application uses subdomain-based multi-tenancy: 1. **Platform Users** (superuser, platform_manager, platform_support) - Access the app at `http://platform.lvh.me:5173` - See platform dashboard and administrative features 2. **Business Users** (owner, manager, staff, resource) - Access the app at `http://{business_subdomain}.lvh.me:5173` - See business-specific dashboard and features ### Cookie-Based Authentication Tokens are stored in cookies with `domain=.lvh.me` to enable cross-subdomain access: ```typescript // Set cookie accessible across all *.lvh.me subdomains setCookie('access_token', token, 7); // domain=.lvh.me // Cookie is accessible on: // - platform.lvh.me:5173 // - business1.lvh.me:5173 // - business2.lvh.me:5173 // etc. ``` **Key Files:** - `/src/utils/cookies.ts` - Cookie utilities with cross-subdomain support - `/src/hooks/useAuth.ts` - Authentication hooks using cookies - `/src/api/client.ts` - API client with cookie-based auth ### Login Flow 1. User navigates to `http://platform.lvh.me:5173` 2. If not authenticated, shows login page 3. User enters credentials and submits 4. Backend validates and returns JWT tokens + user data 5. Tokens stored in cookies with `domain=.lvh.me` 6. User data stored in React Query cache 7. App checks user role: - Platform users: Stay on platform.lvh.me - Business users: Redirect to {business_subdomain}.lvh.me 8. Cookies accessible on target subdomain - user sees dashboard ### Testing with Playwright Tests use lvh.me for proper subdomain testing: ```typescript // Start on platform subdomain await page.goto('http://platform.lvh.me:5173'); // Login sets cookies with domain=.lvh.me await page.getByPlaceholder(/username/i).fill('poduck'); await page.getByPlaceholder(/password/i).fill('starry12'); await page.getByRole('button', { name: /sign in/i }).click(); // Cookies accessible, dashboard loads await expect(page.getByRole('heading', { name: /platform dashboard/i })).toBeVisible(); ``` ### Running the Development Server ```bash # Install dependencies npm install # Start dev server npm run dev # Access at http://platform.lvh.me:5173 ``` ### Running Tests ```bash # Run all tests npm test # Run E2E tests npx playwright test # Run specific test file npx playwright test login-flow.spec.ts # Run with UI npx playwright test --ui ``` ## Production Deployment In production, replace `lvh.me` with your actual domain: 1. Update `src/utils/cookies.ts`: ```typescript const domain = window.location.hostname.includes('yourdomain.com') ? '.yourdomain.com' : window.location.hostname; ``` 2. Configure DNS: - `platform.yourdomain.com` → Your server IP - `*.yourdomain.com` → Your server IP (wildcard for business subdomains) 3. SSL certificates: - Get wildcard certificate for `*.yourdomain.com` - Or use Let's Encrypt with wildcard support ## Troubleshooting ### Cookies not working? - Make sure you're using `lvh.me`, not `localhost` - Check browser DevTools → Application → Cookies - Verify `domain=.lvh.me` is set on cookies - Clear cookies and try again ### Redirect issues? - Check `/src/pages/LoginPage.tsx` redirect logic - Verify user role and business_subdomain in response - Check browser console for navigation errors ### Can't access lvh.me? - Verify internet connection (lvh.me requires DNS lookup) - Try `ping lvh.me` - should resolve to `127.0.0.1` - Alternative: Use `127.0.0.1.nip.io` (similar service) ## References - [RFC 6265 - HTTP State Management Mechanism](https://datatracker.ietf.org/doc/html/rfc6265) - [lvh.me DNS service](http://lvh.me) - [Cookie Domain Attribute Rules](https://stackoverflow.com/questions/1062963/how-do-browser-cookie-domains-work)