From 51714c8edd0c2bb049abb22c107f459a023e128a Mon Sep 17 00:00:00 2001 From: richardtekula Date: Wed, 19 Nov 2025 13:21:34 +0100 Subject: [PATCH] update docs --- README.md | 885 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 804 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index 3611ab7..a23f6df 100644 --- a/README.md +++ b/README.md @@ -85,61 +85,180 @@ Backend API pre email a kontaktný manažment s podporou viacerých JMAP účtov ## Services ### auth.service.js -- `getUserById()` - Získanie usera z DB -- `createUser()` - Vytvorenie nového usera s temp heslom -- `validatePassword()` - Validácia hesla (bcrypt compare) -- `changePassword()` - Zmena hesla s auditom +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 -- `getEmailAccounts()` - Zoznam účtov pre usera -- `addEmailAccount()` - Pridanie JMAP účtu (šifrovanie hesla) -- `getEmailAccountWithCredentials()` - Účet s dešifrovaným heslom -- `getPrimaryEmailAccount()` - Primárny účet -- `removeEmailAccount()` - Odstránenie s cascade delete -- `setPrimaryAccount()` - Nastavenie primárneho +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 -- `jmapRequest()` - HTTP request na JMAP server -- `getJmapSession()` - Získanie JMAP session -- `getJmapConfigFromAccount()` - Config z email účtu -- `syncEmailsFromSender()` - Sync emailov od kontaktu -- `searchEmailsJMAP()` - Full-text search v JMAP -- `sendEmail()` - Poslanie odpovede cez JMAP -- `discoverContactsFromJMAP()` - Objavenie odosielateľov +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 -- `getUserContacts()` - Kontakty usera (s accountId filtrom) -- `addContact()` - Pridanie + auto-sync emailov -- `updateContact()` - Úprava kontaktu -- `removeContact()` - Odstránenie + cascade delete +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 -- `getUserEmails()` - Emaily usera (s accountId filtrom) -- `getEmailThread()` - Thread konverzácia -- `markThreadAsRead()` - Označenie threadu -- `searchEmails()` - DB vyhľadávanie -- `getUnreadCount()` - Počet neprecítaných per účet +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 -- `logAuditEvent()` - Zaloguje akciu s IP, user-agent, timestamp +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` - Validácia JWT tokenu, načítanie usera -- `requireAdmin` - Overenie admin role -- `requireOwnerOrAdmin` - Vlastník alebo admin + +**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ť -- `loginRateLimiter` - 5 pokusov / 15 min -- `apiRateLimiter` - 100 requestov / 15 min (dev: 1000) -- `sensitiveOperationLimiter` - 3 pokusy / 15 min -- `validateBody` - Zod schema validácia -- `validateParams` - Zod params validácia + +**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` - Centrálne error handling -- `notFound` - 404 handler + +**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 @@ -181,56 +300,404 @@ Backend API pre email a kontaktný manažment s podporou viacerých JMAP účtov ## Konfigurácia -**.env** +### Environment Variables (.env) + ```env -# Server -PORT=5000 -NODE_ENV=development +# Server Configuration +PORT=5000 # Port na ktorom beží Express server +NODE_ENV=development # development | production (ovplyvňuje rate limits, error handling) -# Database -DB_HOST=localhost -DB_PORT=5432 -DB_USER=postgres -DB_PASSWORD=password -DB_NAME=crm +# 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 -JWT_SECRET=your-secret-key -JWT_REFRESH_SECRET=your-refresh-secret -JWT_EXPIRES_IN=1h +# 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 -JMAP_SERVER=https://mail.truemail.sk/jmap/ +# JMAP Configuration +JMAP_SERVER=https://mail.truemail.sk/jmap/ # JMAP endpoint pre Truemail.sk -# Encryption -ENCRYPTION_KEY=your-32-char-encryption-key +# Encryption (pre JMAP heslá) +ENCRYPTION_KEY=your-32-char-encryption-key # PRESNE 32 znakov pre AES-256 # CORS -CORS_ORIGIN=http://localhost:5173 +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 -npm run dev # Dev server s nodemon -npm start # Production server -npm run db:generate # Generovanie Drizzle migrácií -npm run db:migrate # Aplikovanie migrácií -npm run db:push # Push schema (bez migrácií) -npm run db:studio # Drizzle Studio (DB GUI) -npm run db:seed # Seed admin account -npm test # Spustenie testov +# 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 -1. Nainštaluj dependencies: `npm install` -2. Nastav `.env` s DB credentials a secrets -3. Spusti PostgreSQL: `docker-compose up -d postgres` -4. Aplikuj migrácie: `npm run db:migrate` -5. Seed admin: `npm run db:seed` (uložíš si temp password!) -6. Spusti server: `npm run dev` -7. API beží na `http://localhost:5000` +### 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í @@ -248,16 +715,272 @@ npm test # Spustenie testov ## JMAP Integrácia -- **Provider:** Truemail.sk -- **Endpoint:** https://mail.truemail.sk/jmap/ -- **Auth:** Basic Auth (email + heslo) -- **Operácie:** - - Email/query - Vyhľadávanie emailov - - Email/get - Získanie detailov - - Email/set - Vytvorenie emailu - - EmailSubmission/set - Poslanie emailu - - Mailbox/get - Zoznam mailboxov - - Identity/get - Email identity +### 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