Files
crm-server/README.md
richardtekula 51714c8edd update docs
2025-11-19 13:21:34 +01:00

995 lines
27 KiB
Markdown

# CRM Server API
Backend API pre email a kontaktný manažment s podporou viacerých JMAP účtov.
## Funkcie
### Autentifikácia
- **Login** - Session-based auth s JWT tokens (httpOnly cookies)
- **Onboarding** - 3-krokový flow (login → nastavenie hesla → pripojenie emailu)
- **Session management** - Automatický refresh tokenov
- **Role-based access** - Admin a Member
### Email účty (Multi-account)
- **Pridanie účtu** - Pripojenie viacerých JMAP účtov
- **Šifrovanie hesiel** - AES-256-GCM encryption pre JMAP heslá
- **Primárny účet** - Označenie hlavného účtu
- **Cascade delete** - Odstránenie účtu vymaže všetky jeho dáta
### JMAP Email integrácia
- **Sync emailov** - Stiahnutie emailov z Truemail.sk JMAP servera
- **Thread organizácia** - Emaily zoskupené do konverzácií
- **Full-text search** - Vyhľadávanie v predmete, tele, odosielateľovi
- **Posielanie odpovedí** - Odpoveď na emaily cez JMAP
- **Neprecítané správy** - Počítadlo per účet
### Kontakty
- **Objavovanie** - Automatické získanie odosielateľov z emailov
- **Auto-sync emailov** - Pri pridaní kontaktu sa stiahnu všetky jeho emaily
- **CRUD operácie** - Pridanie, úprava, odstránenie
- **Account filtering** - Kontakty izolované per email účet
### Správa používateľov (Admin)
- **Vytvorenie usera** - Auto-generovanie temporary hesla
- **Zmena rolí** - Admin/Member
- **Zoznam používateľov** - Len pre adminov
### Bezpečnosť
- **Password hashing** - Bcrypt (12 rounds)
- **Rate limiting** - Login, API, citlivé operácie
- **Helmet** - HTTP security headers (CSP, HSTS)
- **Input validation** - Zod schemas
- **SQL injection protection** - Drizzle ORM prepared statements
- **XSS protection** - Sanitizácia inputov
- **Audit logging** - Všetky dôležité akcie logované
## API Endpointy
### Autentifikácia `/api/auth`
- `POST /login` - Prihlásenie
- `POST /set-password` - Nastavenie hesla (onboarding)
- `POST /change-password` - Zmena hesla
- `POST /logout` - Odhlásenie
- `GET /session` - Získanie session info
- `GET /me` - Aktuálny používateľ
### Email účty `/api/email-accounts`
- `GET /` - Zoznam účtov
- `POST /` - Pridanie účtu
- `DELETE /:id` - Odstránenie účtu
- `PATCH /:id/primary` - Nastavenie primárneho
### Admin `/api/admin` (Admin only)
- `POST /users` - Vytvorenie používateľa
- `GET /users` - Zoznam používateľov
- `PATCH /users/:id/role` - Zmena role
- `DELETE /users/:id` - Zmazanie používateľa
### Kontakty `/api/contacts`
- `GET /` - Zoznam kontaktov (s accountId filtrom)
- `GET /discover` - Potenciálne kontakty z JMAP
- `POST /` - Pridať kontakt + auto-sync emailov
- `PATCH /:id` - Upraviť kontakt
- `DELETE /:id` - Odstrániť kontakt
### Emaily `/api/emails`
- `GET /` - Zoznam emailov (s accountId filtrom)
- `GET /search` - Vyhľadávanie v DB
- `GET /search-jmap` - JMAP full-text search
- `GET /thread/:id` - Thread konverzácie
- `POST /thread/:id/read` - Označiť thread ako prečítaný
- `POST /sync` - Manuálna synchronizácia
- `POST /reply` - Odpovedať na email
- `GET /unread-count` - Počet neprecítaných per účet
## Services
### auth.service.js
Správa autentifikácie a používateľov.
**Funkcie:**
- `getUserById(id)` - Získanie usera z DB podľa ID
- `getUserByUsername(username)` - Nájdenie usera podľa username
- `createUser(data)` - Vytvorenie nového usera s auto-generovaným temporary heslom
- `validatePassword(user, password)` - Validácia hesla (bcrypt compare s temp_password alebo password)
- `changePassword(userId, newPassword)` - Zmena hesla + audit log + update `changed_password = true`
- `updateLastLogin(userId)` - Update `last_login` timestamp
### email-account.service.js
Multi-account email management.
**Funkcie:**
- `getEmailAccounts(userId)` - Zoznam všetkých email účtov usera
- `addEmailAccount(userId, email, password)` - Pridanie JMAP účtu s validáciou credentials a šifrovaním hesla
- `getEmailAccountWithCredentials(accountId, userId)` - Účet s dešifrovaným heslom (pre JMAP operácie)
- `getPrimaryEmailAccount(userId)` - Vráti primárny účet usera
- `removeEmailAccount(accountId, userId)` - Odstránenie účtu + cascade delete kontaktov a emailov
- `setPrimaryAccount(accountId, userId)` - Nastavenie účtu ako primárneho (resetne ostatné)
- `verifyAccountOwnership(accountId, userId)` - Overenie že účet patrí userovi
### jmap.service.js
JMAP protokol integrácia s Truemail.sk.
**Core funkcie:**
- `jmapRequest(config, methodCalls)` - Low-level JMAP HTTP request (Basic Auth + JSON payload)
- `getJmapSession(config)` - Získanie JMAP session (capabilities, accountId, upload URL)
- `getJmapConfigFromAccount(accountId, userId)` - Vytvorenie JMAP config objektu z DB account
**Email operácie:**
- `syncEmailsFromJMAP(config, userId, accountId, filters)` - Stiahnutie emailov z JMAP a uloženie do DB
- `syncEmailsFromSender(config, userId, accountId, senderEmail, contactId)` - Sync všetkých emailov od konkrétneho odosielateľa
- `searchEmailsJMAP(config, query, limit, offset)` - Full-text search v JMAP serveri
- `sendEmail(config, emailAccountId, to, subject, body, inReplyTo)` - Vytvorenie a poslanie odpovede cez JMAP
- `markEmailAsRead(config, userId, jmapId, isRead)` - Update `$seen` keywordu na JMAP serveri
**Discovery:**
- `discoverContactsFromJMAP(config)` - Získanie všetkých unikátnych emailových adries z INBOX
**Helpers:**
- `parseJmapResponse(response)` - Parsovanie JMAP response a error handling
- `extractEmailAddress(emailObject)` - Extrahovanie email adresy z JMAP formátu `[{email: "..."}]`
### contact.service.js
Správa kontaktov s auto-sync funkciou.
**Funkcie:**
- `getUserContacts(userId, accountId?)` - Zoznam kontaktov usera (s voliteľným account filtrom)
- `getContactById(contactId, userId)` - Detail kontaktu s ownership validáciou
- `addContact(userId, accountId, email, name?, notes?)` - Pridanie kontaktu + **automatický sync emailov od tohto odosielateľa**
- `updateContact(contactId, userId, updates)` - Update mena alebo poznámok
- `removeContact(contactId, userId)` - Odstránenie kontaktu (emaily zostávajú, `contact_id = null`)
- `verifyContactOwnership(contactId, userId)` - Overenie ownership
### crm-email.service.js
Email CRUD operácie a thread management.
**Funkcie:**
- `getUserEmails(userId, accountId?, filters?)` - Zoznam emailov s pagination a filtrami (isRead, contactId, search)
- `getEmailById(emailId, userId)` - Detail emailu
- `getEmailThread(threadId, userId)` - Všetky emaily v konverzácii (sorted by date)
- `markThreadAsRead(threadId, userId, isRead)` - Označenie všetkých emailov v threade
- `searchEmails(userId, query, accountId?)` - DB full-text search (subject, body, from)
- `getUnreadCount(userId, accountId?)` - Počet neprecítaných emailov per účet
- `createEmail(data)` - Vytvorenie email záznamu v DB (používa jmap.service)
- `updateEmailReadStatus(emailId, userId, isRead)` - Update single email read status
### audit.service.js
Audit logging pre bezpečnostné účely.
**Funkcia:**
- `logAuditEvent(data)` - Zaloguje akciu do audit_logs tabuľky
```javascript
{
userId, action, resource, resourceId?,
oldValue?, newValue?, success,
errorMessage?, ipAddress?, userAgent?
}
```
**Tracked events:**
- Login (success/fail)
- Password changes
- User creation/deletion
- Email account add/remove
- Role changes
- Contact add/remove
### email.service.js
(Legacy?) Basic email operácie - možno deprecated v prospech crm-email.service.js
## Middlewares
### Autentifikácia
**authenticate.js**
- Validuje JWT access token z httpOnly cookie
- Načíta usera z DB a priradí k `req.user`
- Ak token expiroval, vráti 401 Unauthorized
- Ak token chýba, vráti 401 Unauthorized
**roleMiddleware.js**
`requireAdmin`
- Overí že user má `role = 'admin'`
- Používa sa pred admin-only endpointmi
- Vráti 403 Forbidden ak nie je admin
`requireOwnerOrAdmin`
- Overí že user je vlastník resource alebo admin
- Používa sa napr. pri úprave vlastného profilu
- Parameter: `resourceUserId` z req.params alebo req.body
### Bezpečnosť
**rateLimiter.js**
`loginRateLimiter`
- Limit: 5 pokusov / 15 minút
- Scope: Per IP adresa
- Používa sa na `/api/auth/login`
- Ochrana proti brute force útokom
`apiRateLimiter`
- Limit: 100 requestov / 15 min (production)
- Limit: 1000 requestov / 15 min (development)
- Scope: Per IP adresa
- Aplikuje sa na všetky `/api/*` routes
`sensitiveOperationLimiter`
- Limit: 3 pokusy / 15 minút
- Používa sa na password change, user delete, atď.
- Extra ochrana pre kritické operácie
**validateInput.js**
- XSS sanitizácia vstupných dát
- Používa `xss-clean` knižnicu
- Automaticky aplikované cez `xss-clean` middleware
### Validácia
**validateBody.js**
- Middleware factory pre Zod schema validáciu
- Použitie: `validateBody(schema)`
- Pri validačnej chybe vráti 400 s detailmi
**validateParams.js**
- Validácia URL parametrov (napr. `:id`)
- Zod schemas pre params
**Príklad použitia:**
```javascript
router.post(
'/login',
validateBody(loginSchema),
loginRateLimiter,
loginController
);
```
### Global
**errorHandler.js**
- Centrálne spracovanie všetkých errorov
- Rozpoznáva custom error classes (`BadRequestError`, `UnauthorizedError`, ...)
- Production: Skryje stack traces
- Development: Full error details
- Loguje errory cez Winston
**notFound.js**
- 404 handler pre neexistujúce routes
- Musí byť zaregistrovaný **pred** errorHandler
- Vráti: `{ success: false, error: 'Route not found' }`
## Database Schema
### users
- id, username, role (admin/member)
- password, temp_password (bcrypt hash)
- changed_password, last_login
- created_at, updated_at
### email_accounts
- id, user_id (FK → users)
- email, email_password (AES-256 encrypted)
- jmap_account_id
- is_primary, is_active
- created_at, updated_at
### contacts
- id, user_id (FK → users)
- email_account_id (FK → email_accounts)
- email, name, notes
- added_at, created_at, updated_at
### emails
- id, user_id (FK → users)
- email_account_id (FK → email_accounts)
- contact_id (FK → contacts)
- jmap_id, message_id, thread_id
- from, to, subject, body
- is_read, date
- created_at, updated_at
### audit_logs
- id, user_id (FK → users)
- action, resource, resource_id
- old_value, new_value (JSON)
- ip_address, user_agent
- success, error_message
- created_at
## Konfigurácia
### Environment Variables (.env)
```env
# Server Configuration
PORT=5000 # Port na ktorom beží Express server
NODE_ENV=development # development | production (ovplyvňuje rate limits, error handling)
# Database Configuration
DB_HOST=localhost # PostgreSQL host (docker-compose: 'postgres')
DB_PORT=5432 # PostgreSQL port
DB_USER=admin # DB username
DB_PASSWORD=heslo123 # DB password
DB_NAME=crm # Database name
# JWT Secrets (MUSIA byť dlhé a náhodné!)
JWT_SECRET=your-secret-key # Pre access token (min 32 znakov)
JWT_REFRESH_SECRET=your-refresh-secret # Pre refresh token (min 32 znakov)
JWT_EXPIRES_IN=1h # Access token expiration (1h = 1 hodina)
# JMAP Configuration
JMAP_SERVER=https://mail.truemail.sk/jmap/ # JMAP endpoint pre Truemail.sk
# Encryption (pre JMAP heslá)
ENCRYPTION_KEY=your-32-char-encryption-key # PRESNE 32 znakov pre AES-256
# CORS
CORS_ORIGIN=http://localhost:5173 # Frontend URL (React dev server)
# Optional
BCRYPT_ROUNDS=12 # Bcrypt cost factor (default: 12)
```
### Ako vygenerovať secrets
**JWT_SECRET a JWT_REFRESH_SECRET:**
```bash
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
```
**ENCRYPTION_KEY (presne 32 znakov):**
```bash
node -e "console.log(require('crypto').randomBytes(32).toString('base64').slice(0, 32))"
```
### Docker Compose
**docker-compose.yml** obsahuje len PostgreSQL databázu:
```yaml
services:
postgres:
image: postgres:16
container_name: postgres-db
restart: "no"
ports:
- "5432:5432"
volumes:
- ./postgres:/var/lib/postgresql/data
```
**Spustenie:**
```bash
docker-compose up -d postgres # Start databázy
docker-compose down # Stop databázy (data zostanú)
docker-compose down -v # Stop + vymazanie volumes (⚠️ stratíš dáta)
```
### Drizzle Configuration
**drizzle.config.js** - Konfigurácia pre Drizzle Kit (migrations tool):
```javascript
{
schema: './src/db/schema.js', // Kde je DB schema definovaná
out: './src/db/migrations', // Kam sa uložia migrračné SQL súbory
dialect: 'postgresql',
dbCredentials: { /* z .env */ },
verbose: true, // Loguje SQL queries
strict: true // Prísna validácia
}
```
**Používané príkazy:**
- `drizzle-kit generate` → vygeneruje SQL migrácie zo schémy
- `drizzle-kit push` → pushne schému priamo (skip migrations)
- `drizzle-kit studio` → otvorí DB GUI na http://localhost:4983
## Skripty
### NPM Skripty
```bash
# Development & Production
npm run dev # Spustí vývojový server s nodemon (hot reload)
npm start # Production server (bez reloadovania)
# Database management
npm run db:generate # Vygeneruje SQL migračné súbory z Drizzle schémy
npm run db:migrate # Aplikuje migrácie na databázu
npm run db:push # Pushne schému priamo (bez migračných súborov)
npm run db:studio # Otvorí Drizzle Studio - GUI pre databázu
# Seeding
npm run db:seed # Vytvorí admin účet s náhodným heslom
npm run db:seed:testuser # Vytvorí testovacieho usera (testuser/testuser123!)
# Testing
npm test # Spustí Jest testy
```
### Utility Skripty
**check-tables.js** - Zoznam všetkých tabuliek v databáze
```bash
node check-tables.js
```
**test-search.js** - Test JMAP search endpointu (vyžaduje TEST_COOKIE env)
```bash
TEST_COOKIE='session=xyz...' node test-search.js
```
**mark-email-read-jmap.js** - Označí konkrétny email ako prečítaný cez JMAP
```bash
node mark-email-read-jmap.js
```
**scripts/encrypt-password.js** - Zašifruje heslo pre manuálne vloženie do DB
```bash
node scripts/encrypt-password.js 'your-password'
```
## Spustenie
### Prvý setup
1. **Nainštaluj dependencies**
```bash
npm install
```
2. **Skopíruj a nastav .env**
```bash
cp .env.example .env
```
- Nastav `DB_*` credentials (default sú pre docker-compose)
- Vygeneruj silný `JWT_SECRET` a `JWT_REFRESH_SECRET`
- Vygeneruj 32-znakový `ENCRYPTION_KEY` (pre šifrovanie JMAP hesiel)
- Nastav `CORS_ORIGIN` pre frontend (default: http://localhost:5173)
3. **Spusti PostgreSQL databázu**
```bash
docker-compose up -d postgres
```
4. **Aplikuj databázové migrácie**
```bash
npm run db:migrate
```
5. **Vytvor admin účet**
```bash
npm run db:seed
```
⚠️ **DÔLEŽITÉ:** Skopíruj si vygenerované temporary heslo! Budeš ho potrebovať pri prvom prihlásení.
6. **Spusti server**
```bash
npm run dev
```
7. **API beží na** `http://localhost:5000`
- Health check: `GET /health`
- API docs: Všetky endpointy sú popísané v sekcii "API Endpointy"
### Každodenný development
```bash
# Spusti databázu (ak nie je spustená)
docker-compose up -d postgres
# Spusti dev server
npm run dev
# Otvor DB GUI (voliteľné)
npm run db:studio
```
## Ako to funguje
### Architektúra
Aplikácia používa **layered architecture** so separáciou zodpovedností:
```
Client Request
Routes (routing)
Middlewares (auth, validation, rate limiting)
Controllers (request handling, response formatting)
Services (business logic)
Database (Drizzle ORM)
```
### Flow autentifikácie a onboardingu
1. **Admin vytvorí nového usera**
- `POST /api/admin/users` s username, firstName, lastName, role
- Systém vygeneruje náhodné temporary heslo (16 znakov, mix uppercase/lowercase/numbers/symbols)
- Heslo sa hashuje bcryptom (12 rounds) a uloží do `temp_password`
- `changed_password = false`
2. **Prvé prihlásenie**
- User sa prihlási s temporary heslom: `POST /api/auth/login`
- Backend zistí že `changed_password = false` a vráti flag `mustChangePassword: true`
- Frontend redirectne na "set password" screen
3. **Nastavenie vlastného hesla**
- `POST /api/auth/set-password` s novým heslom
- Validácia: min 8 znakov, uppercase, lowercase, number, symbol
- Heslo sa hashuje a uloží do `password` fieldu
- `temp_password = null`, `changed_password = true`
4. **Session management**
- Pri login dostane user JWT access token (httpOnly cookie, 1h)
- Refresh token (httpOnly cookie, 7 dní)
- Pri expirácii access tokenu sa automaticky refreshne
### Email synchronizácia flow
1. **Pripojenie email účtu**
- User pridá JMAP účet: `POST /api/email-accounts`
- Backend overí JMAP credentials volaním `getJmapSession()`
- Heslo sa zašifruje AES-256-GCM a uloží do DB
- JMAP accountId sa uloží pre budúce requesty
2. **Prvý sync**
- Automaticky sa stiahnu emaily z INBOX
- `Email/query` + `Email/get` JMAP volania
- Emaily sa uložia do DB s `thread_id` pre organizáciu konverzácií
3. **Nepretržitý sync**
- Frontend pravidelne volá `GET /api/emails?accountId=X`
- Backend volá JMAP a stiahne nové emaily od posledného syncu
- Update-uje `is_read` status podľa JMAP
### Kontakty a auto-sync
1. **Discovery kontaktov**
- `GET /api/contacts/discover?accountId=X`
- Backend stiahne všetky emaily z JMAP
- Extrahuje unikátne email adresy z `from` a `to` polí
- Vráti zoznam emailov ktoré ešte nie sú v kontaktoch
2. **Pridanie kontaktu**
- `POST /api/contacts` s `email` a `emailAccountId`
- Backend uloží kontakt do DB
- **Auto-sync:** Automaticky vyhľadá všetky emaily od/pre tento kontakt cez JMAP
- Stiahnuť a uloží všetky nájdené emaily s linknutím na kontakt (`contact_id`)
3. **Email thread organizácia**
- Emaily sa zoskupujú podľa `thread_id` (z JMAP)
- `GET /api/emails/thread/:threadId` vráti chronologickú konverzáciu
- Mark as read označí všetky emaily v threade
### Bezpečnostné mechanizmy
**Rate Limiting:**
- Login: 5 pokusov / 15 min (brute force ochrana)
- API: 100 requestov / 15 min (1000 v dev mode)
- Sensitive operations: 3 pokusy / 15 min
**Password Security:**
- Bcrypt hashing s 12 rounds (2^12 = 4096 iterations)
- Temporary passwords: 16 znakov, vysoká entropia
- Validácia: min 8 znakov, mix typov znakov
**Data Encryption:**
- JMAP heslá: AES-256-GCM (symetrické šifrovanie)
- Format: `iv:authTag:encryptedText`
- Kľúč derivovaný z `ENCRYPTION_KEY` cez scrypt
**Session Security:**
- JWT tokeny v httpOnly cookies (XSS ochrana)
- SameSite=Strict (CSRF ochrana)
- Krátka platnosť access tokenu (1h)
- Refresh token rotation
**Input Validation:**
- Zod schemas pre všetky endpointy
- XSS sanitizácia cez xss-clean
- SQL injection ochrana cez Drizzle ORM prepared statements
**Audit Logging:**
- Všetky dôležité akcie (login, password change, user creation, email account add/remove)
- Ukladá user_id, action, resource, old/new values, IP, user-agent
- `GET /api/admin/audit-logs` pre adminov
### Database Cascade Deletes
**User Delete:**
- Cascade vymaže: email_accounts → contacts → emails → audit_logs
**Email Account Delete:**
- Cascade vymaže: contacts → emails (pre tento účet)
- User si môže pridať ďalší účet
**Contact Delete:**
- Emaily od tohto kontaktu zostávajú (len `contact_id = null`)
- Možnosť filtrovať "orphaned" emaily
### JMAP Operácie
**Supported operations:**
1. **Email/query** - Vyhľadávanie emailov
```javascript
{
filter: { inMailbox: 'inbox' },
sort: [{ property: 'receivedAt', isAscending: false }],
limit: 50
}
```
2. **Email/get** - Získanie detailov emailov
```javascript
{
ids: ['id1', 'id2'],
properties: ['from', 'to', 'subject', 'bodyValues', 'threadId', ...]
}
```
3. **Email/set** - Vytvorenie emailu (draft)
```javascript
{
create: {
draft1: {
mailboxIds: { drafts: true },
from: [...], to: [...],
subject: '...', bodyValues: { body: { value: '...' }}
}
}
}
```
4. **EmailSubmission/set** - Poslanie emailu
```javascript
{
create: {
sub1: {
emailId: 'draft1',
identityId: 'identity1'
}
}
}
```
5. **Email/changes** - Incremental sync (delta updates)
- Používa `sinceState` pre získanie len zmenených emailov
- Optimalizované pre veľké mailboxy
### Šifrovanie JMAP hesiel
**Encryption flow:**
```javascript
// Encryption (pri pridaní účtu)
1. Vygeneruj náhodný IV (16 bytes)
2. Vytvor cipher s AES-256-GCM, key, IV
3. Zašifruj heslo
4. Získaj auth tag
5. Ulož: `${iv}:${authTag}:${encrypted}`
// Decryption (pri JMAP operáciách)
1. Split stored value na [iv, authTag, encrypted]
2. Vytvor decipher s AES-256-GCM, key, IV
3. Nastav auth tag
4. Dešifruj heslo
5. Použij pre JMAP request
```
### Multi-Account Management
Každý user môže mať **viacero email účtov**:
- Jeden je označený ako **primárny** (`is_primary = true`)
- Kontakty a emaily sú **izolované per účet** (accountId filter)
- Frontend prepína medzi účtami cez accountId parameter
- Každý účet má vlastný JMAP session a credentials
### Error Handling
**Centrálny error handler middleware:**
- Všetky chyby idú cez `errorHandler.js`
- Custom error classes: `BadRequestError`, `UnauthorizedError`, `NotFoundError`, `ConflictError`
- Production mode: Skryje stack traces
- Development mode: Full error details + stack trace
- Všetky errory sa logujú cez Winston logger
## Systém rolí
**Admin**
- Všetko čo Member
- `/api/admin/*` endpointy
- Vytvorenie/zmazanie používateľov
- Zmena rolí
**Member**
- Vlastný profil a nastavenia
- Správa vlastných email účtov
- Vlastné kontakty a emaily
- Inbox
## JMAP Integrácia
### Provider: Truemail.sk
**JMAP Endpoint:** `https://mail.truemail.sk/jmap/`
**Autentifikácia:** Basic Auth
- Username: email adresa (napr. `user@slovensko.ai`)
- Password: email heslo (uložené encrypted v DB)
### JMAP Session
Každý JMAP request začína získaním session:
```javascript
GET https://mail.truemail.sk/jmap/session/
Authorization: Basic base64(email:password)
Response:
{
"capabilities": {
"urn:ietf:params:jmap:core": { maxObjectsInGet: 500, ... },
"urn:ietf:params:jmap:mail": { ... }
},
"accounts": {
"account-id": {
"name": "user@slovensko.ai",
"isPersonal": true,
"accountCapabilities": { ... }
}
},
"primaryAccounts": {
"urn:ietf:params:jmap:mail": "account-id"
}
}
```
`accountId` sa ukladá do DB (`jmap_account_id`) a používa pre všetky ďalšie requesty.
### Supported JMAP Methods
**1. Email/query** - Vyhľadávanie emailov
```javascript
[
"Email/query",
{
accountId: "account-id",
filter: {
inMailbox: "inbox", // alebo "sent", "drafts"
from: "email@domain.sk" // voliteľný filter
},
sort: [{ property: "receivedAt", isAscending: false }],
limit: 50,
position: 0
},
"call-id"
]
Response: { list: ["emailId1", "emailId2", ...], total: 156 }
```
**2. Email/get** - Získanie detailov
```javascript
[
"Email/get",
{
accountId: "account-id",
ids: ["emailId1", "emailId2"],
properties: [
"id", "threadId", "mailboxIds", "keywords",
"from", "to", "cc", "bcc",
"subject", "receivedAt", "bodyValues",
"textBody", "htmlBody"
],
bodyProperties: ["partId", "type", "value"]
},
"call-id"
]
Response: {
list: [{
id: "emailId1",
from: [{ email: "sender@domain.sk", name: "Sender Name" }],
subject: "Email subject",
bodyValues: { body: { value: "Email content..." } },
...
}]
}
```
**3. Email/set** - Vytvorenie/Update/Delete
```javascript
// Vytvorenie draft emailu
[
"Email/set",
{
accountId: "account-id",
create: {
"draft-1": {
mailboxIds: { "drafts-mailbox-id": true },
from: [{ email: "me@slovensko.ai" }],
to: [{ email: "recipient@domain.sk" }],
subject: "Reply subject",
bodyValues: {
body: {
value: "Email content",
type: "text/plain"
}
},
textBody: [{ partId: "body", type: "text/plain" }],
keywords: { "$draft": true }
}
}
},
"call-id"
]
// Update (napr. mark as read)
[
"Email/set",
{
accountId: "account-id",
update: {
"emailId1": {
"keywords/$seen": true // mark as read
}
}
},
"call-id"
]
```
**4. EmailSubmission/set** - Poslanie emailu
```javascript
[
"EmailSubmission/set",
{
accountId: "account-id",
create: {
"submission-1": {
emailId: "draft-1", // ID z Email/set create
identityId: "identity-id", // Z Identity/get
envelope: {
mailFrom: { email: "me@slovensko.ai" },
rcptTo: [{ email: "recipient@domain.sk" }]
}
}
}
},
"call-id"
]
```
**5. Mailbox/get** - Zoznam mailboxov (INBOX, Sent, Drafts, ...)
```javascript
[
"Mailbox/get",
{
accountId: "account-id",
ids: null // null = všetky
},
"call-id"
]
Response: {
list: [
{ id: "inbox-id", name: "Inbox", role: "inbox", ... },
{ id: "sent-id", name: "Sent", role: "sent", ... }
]
}
```
**6. Identity/get** - Email identity (pre sending)
```javascript
[
"Identity/get",
{
accountId: "account-id",
ids: null
},
"call-id"
]
Response: {
list: [{
id: "identity-id",
email: "me@slovensko.ai",
name: "My Name"
}]
}
```
**7. Email/changes** - Delta sync (incremental updates)
```javascript
[
"Email/changes",
{
accountId: "account-id",
sinceState: "previous-state-token",
maxChanges: 100
},
"call-id"
]
Response: {
oldState: "previous-state",
newState: "current-state",
hasMoreChanges: false,
created: ["emailId1"],
updated: ["emailId2"],
destroyed: ["emailId3"]
}
```
### JMAP Request Format
Všetky requesty používajú rovnaký formát:
```javascript
POST https://mail.truemail.sk/jmap/api/
Authorization: Basic base64(email:password)
Content-Type: application/json
{
"using": [
"urn:ietf:params:jmap:core",
"urn:ietf:params:jmap:mail"
],
"methodCalls": [
["Method/name", { params }, "call-id"],
...
]
}
```
### Error Handling
JMAP errory majú formát:
```javascript
{
"methodResponses": [
["error", {
"type": "invalidArguments",
"description": "Invalid filter"
}, "call-id"]
]
}
```
**Common error types:**
- `invalidArguments` - Zlé parametre
- `accountNotFound` - Neplatný accountId
- `notFound` - Email/mailbox nenájdený
- `forbidden` - Nedostatočné oprávnenia
- `serverFail` - Server error
### Optimalizácie
**Batching:**
- Jeden HTTP request môže obsahovať viacero method calls
- Príklad: Email/query + Email/get v jednom requeste
**Result References:**
- Výsledok jedného method callu môže byť použitý v ďalšom
- Príklad: Email/query → Email/get s `#ids` referenciou
**Incremental Sync:**
- Používaj `Email/changes` namiesto full Email/query
- Ukladaj `state` token pre ďalšie syncs
- Znižuje bandwidth a load
## Šifrovanie
**JMAP heslá** - AES-256-GCM
- Format: `iv:authTag:encryptedText`
- Kľúč: `ENCRYPTION_KEY` z .env (32 znakov)
- Funkcie: `encryptPassword()`, `decryptPassword()`
**User heslá** - Bcrypt
- 12 rounds (2^12 iterations)
- Funkcie: `hashPassword()`, `comparePassword()`