# Frontend Implementation Notes

Based on analysis of compiled frontend in `/frontend` folder.

## Key Findings from Compiled Code

### Tech Stack (Confirmed)
- **SvelteKit** 2.x with adapter-static
- **TailwindCSS** + **DaisyUI** 4.x for styling
- **Leaflet** for map/canvas
- **Cloudflare Turnstile** for captcha/bot protection
- **No additional state libraries** - uses Svelte stores

### API Client Pattern
```javascript
// Found in chunks/1lh-LSvX.js
class ApiClient {
  async request(endpoint, options) {
    const response = await fetch(`${this.url}${endpoint}`, options);
    this.online = true;
    return response;
  }
}
```

**Endpoints found:**
- `/me` - GET user profile
- `/auth/logout` - POST logout
- `/me/update` - POST update profile
- `/alliance` - GET/POST alliance operations
- `/alliance/update-description` - POST
- `/alliance/update-headquarters` - POST
- `/alliance/invites` - GET
- `/alliance/give-admin` - POST
- `/alliance/ban` - POST
- `/alliance/unban` - POST
- `/purchase` - POST store purchases
- `/favorite-location` - POST
- `/favorite-location/update` - POST
- `/moderator/tickets` - GET
- `/moderator/severe-open-tickets-count` - GET
- `/me/profile-pictures` - GET
- `/otp/cooldown`, `/otp/send`, `/otp/verify` - OTP system (phone verification)

### Authentication
- **OAuth providers**: Google, Twitch
- Auth redirects to: `${API_URL}/auth/{provider}?token={turnstile_token}&r={redirect}`
- JWT stored in **`j` cookie** (HttpOnly)
- Turnstile captcha required before OAuth

### Global State (from chunks/1lh-LSvX.js)
```javascript
let globalState = {
  dropletsDialogOpen: false,
  muted: false,
  language: getLanguage(),  // 'en' or 'pt' detected from navigator
  captcha: undefined,       // Turnstile token
  now: Date.now(),         // Updates every 500ms
  turnstatileLoaded: false
};

setInterval(() => {
  globalState.now = Date.now()
}, 500);
```

### Cloudflare Turnstile
- Site key: `0x4AAAAAABpqJe8FO0N84q0F` (from constant `qt`)
- Script: `https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit`
- Required before login/OAuth

### Routes (from app.iDaujbEI.js dictionary)
```
/ - Main canvas (node 2)
/404 - 404 page (node 3)
/join - Join/onboarding (node 4)
/admin - Admin panel (node 5)
/offline - Offline page (node 6)
/payment/success - Payment success (node 7)
/profile-picture - Profile picture selector (node 8)
/terms/privacy - Privacy policy (node 9)
/terms/return - Return policy (node 10)
/terms/terms-of-service - Terms of service (node 11)
/moderation - Moderation panel (node 14)
```

### Styling Patterns
- **Base classes**: `bg-base-100`, `bg-base-200`, `text-base-content`
- **Buttons**: `btn`, `btn-ghost`, `btn-circle`, `btn-sm`, `btn-lg`, `btn-error`
- **Modals**: `modal`, `modal-box`, `modal-backdrop`
- **Tabs**: `tabs`, `tabs-border`, `tab`
- **Loading**: `loading loading-spinner loading-md`
- **Tooltips**: `tooltip tooltip-bottom`
- **Layout**: Uses Tailwind grid/flex extensively

### Report/Moderation System
**Report reasons** (from fZ59cmjx.js):
- `inappropriate-content` - "+18, inappropriate link, highly suggestive content"
- `hate-speech` - "Racism, homophobia, hate groups"
- `doxxing` - "Released personal information"
- `bot` - "Automated painting software"
- `griefing` - "Messed up artworks for no reason"
- `other` - "Other reason"

**Report form endpoint**: `${API_URL}/report-user`
**Timeout endpoint**: `${API_URL}/moderator/timeout-user`
**Ban endpoint**: `${API_URL}/admin/ban-user`

### Internationalization
- Supports English (`en`) and Portuguese (`pt`) minimum
- Language detection from `navigator.languages` or `navigator.language`
- Translation functions: `(params, {locale}) => locale === "en" ? englishText : portugueseText`

### Toast Notifications
- Global `W` object with `W.error()`, `W.info()` methods
- Aria-live region: `aria-label="Notifications alt+T"`

### PWA Features
- Service worker: `/service-worker.js`
- Install prompt: `window.pwaInstallPrompt`
- Manifest: `/site.webmanifest`

### CSP Header
```
script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval' https://challenges.cloudflare.com blob:
```

### Constants
- `Nt = "files"` - Files base path
- Season: Default `s1`
- Version displayed as span: `Version: 1759175263375`

## Implementation Priority

1. **Core Setup** (DONE)
   - [x] Package.json with DaisyUI + Tailwind
   - [x] Svelte config
   - [x] PostCSS/Tailwind config

2. **Next Steps**
   - [ ] API client (`src/lib/api/client.ts`)
   - [ ] Global stores (`src/lib/stores/`)
   - [ ] i18n utilities (`src/lib/i18n/`)
   - [ ] Toast notification system
   - [ ] Turnstile component
   - [ ] Layout components
   - [ ] Auth pages (login with OAuth)
   - [ ] Main canvas route
   - [ ] Admin/moderation routes

3. **File Structure**
```
src/
├── lib/
│   ├── api/
│   │   └── client.ts          # API client class
│   ├── stores/
│   │   ├── global.ts          # Global state (turnstile, language, etc.)
│   │   ├── user.ts            # Current user
│   │   ├── canvas.ts          # Canvas state
│   │   └── alliance.ts        # Alliance state
│   ├── i18n/
│   │   ├── index.ts           # Translation utilities
│   │   ├── en.ts              # English translations
│   │   └── pt.ts              # Portuguese translations
│   ├── components/
│   │   ├── common/
│   │   │   ├── Button.svelte
│   │   │   ├── Modal.svelte
│   │   │   └── Toast.svelte
│   │   ├── auth/
│   │   │   ├── LoginForm.svelte     # OAuth buttons + Turnstile
│   │   │   └── Turnstile.svelte     # Cloudflare Turnstile
│   │   ├── canvas/
│   │   │   └── LeafletMap.svelte
│   │   └── layout/
│   │       ├── Header.svelte
│   │       └── Logo.svelte
│   ├── constants/
│   │   ├── colors.ts          # Color palette
│   │   └── config.ts          # API URLs, etc.
│   └── utils/
│       ├── bitmap.ts          # Bitmap helpers
│       ├── charges.ts         # Charge calculation
│       └── level.ts           # Level calculation
├── routes/
│   ├── +layout.svelte         # Root layout
│   ├── +page.svelte           # Main canvas
│   ├── admin/
│   │   └── +page.svelte       # Admin dashboard
│   ├── moderation/
│   │   └── +page.svelte       # Moderation panel
│   └── join/
│       └── +page.svelte       # Login/onboarding
└── app.html                   # HTML template
```

## Notes
- Original frontend uses Svelte 5 runes syntax (`$state`, `$derived`)
- We can use Svelte 4 with traditional stores for simplicity
- No additional HTTP library needed - uses native `fetch`
- Leaflet needs `import 'leaflet/dist/leaflet.css'` in layout
