managarten/apps-archived/mail/CLAUDE.md
Till-JS ace7fa8f7f chore: archive finance, mail, moodlit apps and rename voxel-lava
- Move finance, mail, moodlit to apps-archived for later development
- Rename games/voxel-lava to games/voxelava

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 13:13:15 +01:00

300 lines
10 KiB
Markdown

# Mail Project Guide
## Project Structure
```
apps/mail/
├── apps/
│ ├── backend/ # NestJS API server (@mail/backend) - Port 3017
│ ├── landing/ # Astro marketing landing page (@mail/landing)
│ ├── web/ # SvelteKit web application (@mail/web) - Port 5186
│ └── mobile/ # Expo/React Native mobile app (@mail/mobile)
├── packages/
│ └── shared/ # Shared types, utils, configs (@mail/shared)
└── package.json
```
## Commands
### Root Level (from monorepo root)
```bash
pnpm mail:dev # Run all mail apps
pnpm dev:mail:mobile # Start mobile app
pnpm dev:mail:web # Start web app
pnpm dev:mail:landing # Start landing page
pnpm dev:mail:backend # Start backend server
pnpm dev:mail:app # Start web + backend together
```
### Mobile App (apps/mail/apps/mobile)
```bash
pnpm dev # Start Expo dev server
pnpm ios # Run on iOS simulator
pnpm android # Run on Android emulator
```
### Backend (apps/mail/apps/backend)
```bash
pnpm dev # Start with hot reload
pnpm build # Build for production
pnpm start:prod # Start production server
pnpm db:push # Push schema to database
pnpm db:studio # Open Drizzle Studio
```
### Web App (apps/mail/apps/web)
```bash
pnpm dev # Start dev server
pnpm build # Build for production
pnpm preview # Preview production build
```
### Landing Page (apps/mail/apps/landing)
```bash
pnpm dev # Start dev server
pnpm build # Build for production
```
## Technology Stack
- **Mobile**: React Native 0.81 + Expo SDK 54, NativeWind, Expo Router, Zustand
- **Web**: SvelteKit 2.x, Svelte 5 (runes mode), Tailwind CSS
- **Landing**: Astro 5.x, Tailwind CSS
- **Backend**: NestJS 10, Drizzle ORM, PostgreSQL
- **Email**: ImapFlow, Nodemailer, Google APIs, Microsoft Graph
- **AI**: Google Gemini API
- **Types**: TypeScript 5.x
## Architecture
### Email Providers
| Provider | Protocol | Library |
|----------|----------|---------|
| IMAP/SMTP | Standard | imapflow, nodemailer |
| Gmail | OAuth 2.0 | googleapis |
| Outlook | OAuth 2.0 | @microsoft/microsoft-graph-client |
### Backend API Endpoints
#### Accounts
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/v1/accounts` | GET | List email accounts |
| `/api/v1/accounts` | POST | Add IMAP account |
| `/api/v1/accounts/:id` | GET | Get account details |
| `/api/v1/accounts/:id` | PATCH | Update account |
| `/api/v1/accounts/:id` | DELETE | Remove account |
| `/api/v1/accounts/:id/sync` | POST | Trigger sync |
| `/api/v1/accounts/:id/test` | POST | Test connection |
| `/api/v1/accounts/:id/default` | POST | Set as default |
#### OAuth
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/v1/oauth/google/init` | POST | Start Gmail OAuth |
| `/api/v1/oauth/google/callback` | GET | Gmail callback |
| `/api/v1/oauth/microsoft/init` | POST | Start Outlook OAuth |
| `/api/v1/oauth/microsoft/callback` | GET | Outlook callback |
#### Folders
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/v1/folders` | GET | List all folders |
| `/api/v1/folders` | POST | Create folder |
| `/api/v1/folders/:id` | GET | Get folder |
| `/api/v1/folders/:id` | PATCH | Update folder |
| `/api/v1/folders/:id` | DELETE | Delete folder |
| `/api/v1/folders/:id/hide` | POST | Toggle hide folder |
#### Emails
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/v1/emails` | GET | List emails |
| `/api/v1/emails/search` | GET | Search emails |
| `/api/v1/emails/:id` | GET | Get email |
| `/api/v1/emails/:id` | PATCH | Update flags |
| `/api/v1/emails/:id` | DELETE | Delete email |
| `/api/v1/emails/:id/move` | POST | Move to folder |
| `/api/v1/emails/batch` | POST | Batch operations |
| `/api/v1/emails/:id/thread` | GET | Get email thread |
#### Compose
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/v1/drafts` | GET | List drafts |
| `/api/v1/drafts` | POST | Create draft |
| `/api/v1/drafts/:id` | GET | Get draft |
| `/api/v1/drafts/:id` | PATCH | Update draft |
| `/api/v1/drafts/:id` | DELETE | Delete draft |
| `/api/v1/drafts/:id/send` | POST | Send draft |
| `/api/v1/send` | POST | Send directly |
| `/api/v1/emails/:id/reply` | POST | Create reply draft |
| `/api/v1/emails/:id/reply-all` | POST | Create reply-all draft |
| `/api/v1/emails/:id/forward` | POST | Create forward draft |
#### Attachments
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/v1/emails/:emailId/attachments` | GET | List email attachments |
| `/api/v1/attachments/:id` | GET | Get attachment |
| `/api/v1/attachments` | POST | Create attachment record |
| `/api/v1/attachments/:id` | DELETE | Delete attachment |
| `/api/v1/attachments/upload-url` | POST | Get presigned upload URL |
| `/api/v1/attachments/:id/download` | GET | Get download URL |
| `/api/v1/attachments/:id/complete` | POST | Mark upload complete |
#### Labels
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/v1/labels` | GET | List labels |
| `/api/v1/labels` | POST | Create label |
| `/api/v1/labels/:id` | GET | Get label |
| `/api/v1/labels/:id` | PATCH | Update label |
| `/api/v1/labels/:id` | DELETE | Delete label |
| `/api/v1/labels/email/:emailId` | GET | Get email labels |
| `/api/v1/labels/email/:emailId/add` | POST | Add labels to email |
| `/api/v1/labels/email/:emailId/remove` | POST | Remove labels from email |
| `/api/v1/labels/email/:emailId/set` | POST | Set email labels |
#### Sync
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/v1/sync/accounts/:accountId` | POST | Sync account |
| `/api/v1/sync/accounts/:accountId/folders/:folderId` | POST | Sync folder |
| `/api/v1/sync/emails/:emailId/fetch` | POST | Fetch full email |
#### AI
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/v1/emails/:id/summarize` | POST | AI summary |
| `/api/v1/emails/:id/suggest-replies` | POST | Smart reply |
| `/api/v1/emails/:id/categorize` | POST | Auto-categorize |
### Database Schema
**email_accounts** - Email account configurations
- `id` (UUID) - Primary key
- `user_id` (VARCHAR) - User reference
- `name`, `email` (VARCHAR) - Display name and email address
- `provider` (VARCHAR) - gmail, outlook, imap
- `imap_host`, `imap_port`, `smtp_host`, `smtp_port` - Server settings
- `encrypted_password` (TEXT) - Encrypted credentials
- `access_token`, `refresh_token` (TEXT) - OAuth tokens
- `sync_state` (JSONB) - Provider-specific sync state
- `created_at`, `updated_at` (TIMESTAMP)
**folders** - Email folders
- `id` (UUID) - Primary key
- `account_id` (UUID) - Account reference
- `name`, `type`, `path` (VARCHAR) - Folder info
- `unread_count`, `total_count` (INTEGER)
**emails** - Email messages
- `id` (UUID) - Primary key
- `account_id`, `folder_id`, `thread_id` (UUID) - References
- `message_id` (VARCHAR) - RFC 2822 Message-ID
- `subject`, `from_address`, `from_name` (VARCHAR/TEXT)
- `to_addresses`, `cc_addresses` (JSONB) - Recipients
- `body_plain`, `body_html` (TEXT) - Content
- `is_read`, `is_starred`, `has_attachments` (BOOLEAN)
- `ai_summary`, `ai_category`, `ai_priority` (VARCHAR/TEXT)
**attachments** - Email attachments
- `id` (UUID) - Primary key
- `email_id` (UUID) - Email reference
- `filename`, `mime_type`, `size` - File info
- `storage_key` (VARCHAR) - S3 storage key
**labels** - Custom labels
- `id` (UUID) - Primary key
- `name`, `color` (VARCHAR)
**drafts** - Email drafts
- `id` (UUID) - Primary key
- `account_id` (UUID) - Account reference
- `subject`, `body_html` (TEXT)
- `to_addresses`, `cc_addresses` (JSONB)
- `scheduled_at` (TIMESTAMP)
### Environment Variables
#### Backend (.env)
```env
NODE_ENV=development
PORT=3017
DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/mail
MANA_CORE_AUTH_URL=http://localhost:3001
CORS_ORIGINS=http://localhost:5173,http://localhost:5186,http://localhost:8081
# OAuth
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GOOGLE_REDIRECT_URI=http://localhost:3017/api/v1/oauth/google/callback
MICROSOFT_CLIENT_ID=
MICROSOFT_CLIENT_SECRET=
MICROSOFT_REDIRECT_URI=http://localhost:3017/api/v1/oauth/microsoft/callback
# AI
GOOGLE_GENAI_API_KEY=
# Encryption
ENCRYPTION_KEY=your-32-byte-encryption-key
# Queue (optional)
REDIS_URL=redis://localhost:6379
```
#### Mobile (.env)
```env
EXPO_PUBLIC_BACKEND_URL=http://localhost:3017
EXPO_PUBLIC_MANA_CORE_AUTH_URL=http://localhost:3001
```
#### Web (.env)
```env
PUBLIC_BACKEND_URL=http://localhost:3017
PUBLIC_MANA_CORE_AUTH_URL=http://localhost:3001
```
## AI Features
### Summarization
- 1-2 sentence email summary
- Focus on action items and key information
- Uses Google Gemini API
### Smart Reply
- 3 reply suggestions per email
- Different tones (positive, neutral, declining)
- Context-aware responses
### Auto-Categorization
Categories:
- `work` - Work-related emails
- `personal` - Personal communications
- `newsletter` - Newsletters/subscriptions
- `transactional` - Receipts, confirmations
- `promotional` - Marketing emails
## Code Style Guidelines
- **TypeScript**: Strict typing with interfaces
- **Mobile**: Functional components with hooks, Zustand for state
- **Web**: Svelte 5 runes mode (`$state`, `$derived`, `$effect`)
- **Styling**: Tailwind CSS / NativeWind
- **Formatting**: Prettier with project config
## Important Notes
1. **Authentication**: Uses Mana Core Auth (JWT in Authorization header)
2. **Database**: PostgreSQL with Drizzle ORM
3. **Port**: Backend runs on port 3017, Web on port 5186 by default
4. **Storage**: Uses MinIO/S3 for attachments via @manacore/shared-storage
5. **Encryption**: IMAP passwords are encrypted at rest
6. **Multi-Account**: Each user can have multiple email accounts