# CRM Server – Architektúra a flow Tento dokument popisuje, ako backend funguje: aká je štruktúra kódu, akou cestou prechádza požiadavka, aké služby spolu komunikujú a kde sa riešia bezpečnostné a chybové scenáre. Všetky cesty v kóde sú písané v ES modules. ## Základný stack - **Express 4** (ESM) + **Drizzle ORM** (PostgreSQL) - **JWT** pre prístupové/refresh tokeny (httpOnly cookies), **bcrypt** pre heslá - **Zod** na validačné schémy, **helmet**, **cors**, **express-rate-limit** - **JMAP** integrácia pre e-maily (Truemail) + AES-256-GCM šifrovanie hesiel k e-mail účtom ## Štruktúra priečinkov (hlavné časti) - `src/app.js` – skladá middleware pipeline a mountuje routes, pridáva notFound/error handler. - `src/index.js` – spúšťací bod servera. - `src/routes/` – deklarácie endpointov (1 súbor = 1 doména). Všetky používajú middlewares + volajú controller. - `src/controllers/` – spracovanie requestu, volanie service vrstvy, odoslanie odpovedí. Chyby posielajú cez `next(err)`. - `src/services/` – biznis logika a práca s DB/JMAP (bez Express závislosti). - `src/middlewares/` – auth (JWT + role), security (rate limiting, Zod validateInput), global (validateBody pattern check, 404, error handler). - `src/utils/` – `errors.js` (AppError a formátovanie), `jwt.js`, `password.js`, `logger.js`. - `src/validators/` – Zod schémy pre vstupy. - `src/db/` – Drizzle schéma a config. ## Životný cyklus požiadavky (pipeline) 1) **Logovanie**: `morgan('dev')` (len stdout). 2) **Bezpečnostné hlavičky**: `helmet` s CSP (self + inline styles) a HSTS (preload, subdomains). 3) **CORS**: povolený pôvod z `CORS_ORIGIN` (default `http://localhost:5173`), credentials povolené. 4) **Body parsers**: `express.json` a `express.urlencoded` (limit 10 MB), `cookieParser` pre JWT v cookies. 5) **Global validateBody**: rýchly regex-detektor podozrivých payloadov (loguje a vráti 400 pri matches). 6) **Rate limiting**: `apiRateLimiter` na `/api/*` (100 req/15 min v production, 1000 v dev). Špecifické limitery na login a citlivé operácie sa aplikujú v routes. 7) **Routes**: `auth`, `admin`, `contacts`, `emails` (CRM), `email-accounts`, `timesheets`, `companies`, `projects`, `todos`, `time-tracking`, `notes`. 8) **404**: `notFound` middleware nastaví 404 a pošle ďalej ako Error. 9) **Global error handler**: `errorHandler` loguje, zvolí status (`err.statusCode` > `res.statusCode` ≥400 > 500) a formátuje pomocou `formatErrorResponse`. Ak už sú hlavičky poslané, púšťa chybu ďalej. ## Validácia a bezpečnosť - **Zod validácia**: `validateBody/validateQuery/validateParams` (v `middlewares/security/validateInput.js`) na úrovni routes; nahrádzajú `req.body/query/params` validovanými dátami. - **Auth**: `authenticate` vytiahne JWT z Bearer header alebo cookie, overí cez `verifyAccessToken`, načíta usera (`auth.service.getUserById`) a uloží do `req.user` + `req.userId`. - **Role**: `requireRole` / `requireAdmin` / `requireOwnerOrAdmin` (role middleware) na autorizáciu. - **Rate limiting**: `loginRateLimiter` (default 5 pokusov/15 min, počíta len neúspechy), `sensitiveOperationLimiter` (10 prod / 50 dev za 15 min). - **Šifrovanie**: `password.encryptPassword` používa AES-256-GCM (kľúč zo `JWT_SECRET` + `ENCRYPTION_SALT`). Heslá v DB sú bcrypt hashované. - **Audit logy**: `audit.service` loguje login pokusy, zmeny hesla, role, tvorbu userov atď. do DB + konzoly. ## Error handling (kde a ako) - **Typy chýb**: `AppError` + podtriedy (ValidationError, AuthenticationError, ForbiddenError, NotFoundError, ConflictError, RateLimitError). - **Formát odpovede**: `formatErrorResponse` vracia `{ success:false, error:{ message, statusCode, details?, stack? } }`. Stack iba v NODE_ENV=development. - **Použitie**: Kontroléry nemajú lokálne try/catch formatovanie; pri chybe volajú `next(err)`. Auth middleware vracia 401 pri Auth chybách, inak púšťa ďalej do globálneho handlera. ## Doménové moduly – kto koho volá ### Autentifikácia (`routes/auth.routes.js`, `auth.controller.js`, `auth.service.js`) - **/login**: `loginRateLimiter` → `validateBody(loginSchema)` → controller zavolá `authService.loginWithTempPassword` (porovná temp/permanent heslo, nastaví lastLogin, vygeneruje tokeny) → audit `logLoginAttempt` (success/fail) → nastaví httpOnly cookies + response. - **/set-password**: `authenticate` → `sensitiveOperationLimiter` → `validateBody(setPasswordSchema)` → `authService.setNewPassword` (bcrypt, zmaže tempPassword) → audit `logPasswordChange`. - **/logout**, **/session**: vyžadujú `authenticate`; logout vyčistí cookies, session vráti `req.user`. - **Tokeny**: generované v `utils/jwt.js` (access + refresh); overenie hádže `AuthenticationError` pri expirácii/neplatnosti. ### Admin (`routes/admin.routes.js`, `admin.controller.js`) - `router.use(authenticate)` + `router.use(requireAdmin)` pre všetky admin-only akcie. - CRUD nad používateľmi: create (generuje temp heslo + voliteľné linknutie email účtu), get/list, change role, delete. Používa `email-account.service` pri zakladaní účtu, loguje audit udalosti. ### Email účty (`routes/email-account.routes.js`, `email-account.controller.js`, `email-account.service.js`) - Každá akcia vyžaduje `authenticate`. - **Create**: `sensitiveOperationLimiter` + Zod schéma → service overí JMAP credentials (`validateJmapCredentials` z `email.service.js`), šifruje heslo (AES-256-GCM), vytvorí účet a many-to-many link do `userEmailAccounts`. Ak účet existuje, vie ho len „nasdieliť“ po overení hesla. - **Set primary**: pre konkrétneho používateľa; transakčne zruší ostatné `isPrimary` a aktivuje účet. - **Delete**: odstráni link, a ak nikto iný účet nepoužíva, zmaže aj samotný účet. - **Get**: vracia účty používateľa; špeciálna funkcia `getEmailAccountWithCredentials` dešifruje heslo na JMAP operácie. ### CRM Emaily (`routes/crm-email.routes.js`, `crm-email.controller.js`, `crm-email.service.js`, `jmap.service.js`) - Všetky endpointy za `authenticate`. - **Listing/search**: DB filter + fulltext (subject/body/from), alebo JMAP full-text (`/search-jmap`). Filtrovanie podľa účtu, kontaktu, stavu prečítania. - **Threads**: `/thread/:threadId` načíta konverzáciu; `/thread/:threadId/read` označí všetky maily v threade. - **Sync**: `/sync` spustí fetch z JMAP pre daného používateľa/účet. - **Mark contact read**: `/contact/:contactId/read` označí všetky maily od kontaktu ako prečítané. - **Reply**: `/reply` cez JMAP; používa dešifrované heslo z email-account service. - **Unread count**: `/unread-count` agreguje per účet. ### Kontakty (`routes/contact.routes.js`, `contact.controller.js`, `contact.service.js`) - Všetko za `authenticate`. - **Get/Discover**: zoznam kontaktov (voliteľný filter `accountId`), discover číta unikátnych odosielateľov z JMAP. - **Create**: validácia + uloženie, následne auto-sync všetkých emailov od tohto odosielateľa. - **Update/Delete**: meno/poznámky, prípadne zmazanie; pri delete ostávajú emaily, len sa odpojí contact_id. - **Link/Unlink company** a **create company from contact** využívajú company service. ### Companies (`routes/company.routes.js`, `company.controller.js`, `company.service.js`, `company-email.service.js`, `company-reminder.service.js`) - `authenticate` povinné. - **CRUD firmy**, plus **email threads** pre firmu (agregácia emailov naprieč účtami používateľa). - **Unread counts** per firma (agreguje emaily podľa kontaktov a účtov). - **Notes** (vnořené /:companyId/notes) používajú `note.service`. - **Reminders**: CRUD + summary/endpoints na prehľad (upcoming, counts, summary). Všetko cez `company-reminder.service`. ### Projekty (`routes/project.routes.js`, `project.controller.js`, `project.service.js`) - `authenticate` povinné. - CRUD projektov, správa členov projektu (assign/update role/remove), projektové poznámky (vrátane `reminderAt`). ### Todos (`routes/todo.routes.js`, `todo.controller.js`, `todo.service.js`) - `authenticate`; CRUD + toggle completed. ### Poznámky (`routes/note.routes.js`, `note.controller.js`, `note.service.js`) - `authenticate`; všeobecné poznámky s filtrom na company/project/todo/contact; CRUD operácie. ### Time Tracking (`routes/time-tracking.routes.js`, `time-tracking.controller.js`, `time-tracking.service.js`) - `authenticate`; Zod validácia na start/stop/update. - **Start/Stop**: vytvára/uzatvára bežiaci záznam (oprávnenie viazané na `req.userId`). - **Bežiace položky**: `/running` (aktuálne pre usera), `/running-all` (všetkých userov – dashboard). - **Listing/Filters**: všeobecný listing, mesačné výpisy a štatistiky, detail/relations. - **Generate timesheet**: vytvorí XLSX výstup za mesiac (využíva `exceljs`). ### Timesheets upload (`routes/timesheet.routes.js`, `timesheet.controller.js`, `timesheet.service.js`) - `authenticate`; Multer s **memory storage** a limit 5 MB, whitelist MIME (PDF, XLSX, XLS). Admin môže nahrávať za iných, inak len za seba. Ukladá súbory do `uploads/timesheets`. ### Admin (už popísané vyššie) ### Audit (`audit.service.js`) - Jednotné logovanie udalostí do DB + konzoly (tag `[AUDIT]`). Použité v auth flow a user managemente; možno rozšíriť na ďalšie služby. ## Pomocné utility - `utils/errors.js` – definícia AppError podtried + `formatErrorResponse`. - `utils/jwt.js` – generovanie/verifikácia access/refresh tokenov. - `utils/password.js` – bcrypt hash/compare, generovanie temp hesla, AES-256-GCM encrypt/decrypt pre email heslá. - `utils/logger.js` – farebný stdout logger (info/success/warn/error/debug/audit). ## Request → DB/JMAP tok (v skratke) `Route` → `Zod middleware` (+ auth/role/rate-limit) → `Controller` → `Service` → `DB (Drizzle)` alebo `JMAP` → späť do controller → JSON response. Chyby: buď AppError (očakávané, neseká stack v prod), alebo neočakávané → global `errorHandler`. ## Dôležité závislosti medzi modulmi - **authMiddleware** závisí na `utils/jwt` a `auth.service` (pre user fetch). Bez prístupu k DB nie je možné overiť token. - **crm-email.service** používa `jmap.service` + `email-account.service` (pre dešifrované heslo) + DB schémy. - **contact.service** pri vytvorení kontaktu volá `crm-email.service` na sync emailov od odosielateľa. - **company.controller** používa `company-email.service` (agregácia email threadov) a `note.service` / `company-reminder.service`. - **time-tracking.service** používa Drizzle schémy `timeEntries`, `projects`, `todos`, `companies`, `users` na joiny a agregácie. - **timesheet.controller**/routes využívajú Multer; uloženie súboru/metadata robí `timesheet.service`. ## Ako rozširovať - Nový endpoint: pridaj Zod schému do `validators`, zapoj `validateBody/Params/Query`, použi `authenticate`/`requireAdmin` podľa potreby, v controllery volaj service a pri chybe `next(err)`. - Nová logika: implementuj v `services` (bez Express závislosti), AppError pri očakávaných stavoch. - Error/response shape je centrálne daný `errorHandler` + `formatErrorResponse` – nechaj ho pracovať. ## Environment a spustenie (stručne) - Env vars: `PORT`, `CORS_ORIGIN`, `JWT_SECRET`, `JWT_REFRESH_SECRET`, `ENCRYPTION_SALT`, `RATE_LIMIT_*`, DB credentials atď. (pozri `.env.example` ak existuje / README bezpečnostný checklist). - Skripty: `npm run dev` (nodemon), `npm start`, `npm test` (Jest), drizzle migrácie `db:generate/push/studio`. Tento README má slúžiť ako rýchla mapa: čo kde je, čo koho volá a kde hľadať validačné/bezpečnostné háky alebo biznis logiku.