Initial commit: SmoothSchedule multi-tenant scheduling platform
This commit includes: - Django backend with multi-tenancy (django-tenants) - React + TypeScript frontend with Vite - Platform administration API with role-based access control - Authentication system with token-based auth - Quick login dev tools for testing different user roles - CORS and CSRF configuration for local development - Docker development environment setup 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
159
legacy_reference/frontend/CLAUDE.md
Normal file
159
legacy_reference/frontend/CLAUDE.md
Normal file
@@ -0,0 +1,159 @@
|
||||
# SmoothSchedule Frontend Development Guide
|
||||
|
||||
## 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)
|
||||
Reference in New Issue
Block a user