richardtekula c1657ac37b fix: Allow empty string for phone in contact validation
The Zod schema was rejecting empty strings sent from the frontend.
Changed from z.string().optional().nullable() to z.union pattern
to properly handle "", null, and undefined values.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 10:07:46 +01:00
2025-12-02 09:48:42 +01:00
2025-12-02 09:48:42 +01:00
2025-12-29 09:02:24 +01:00
2025-12-04 10:27:34 +01:00

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 10MB), 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: loginRateLimitervalidateBody(loginSchema) → controller zavolá authService.loginWithTempPassword (porovná temp/permanent heslo, nastaví lastLogin, vygeneruje tokeny) → audit logLoginAttempt (success/fail) → nastaví httpOnly cookies + response.
  • /set-password: authenticatesensitiveOperationLimitervalidateBody(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 5MB, 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)

RouteZod middleware (+ auth/role/rate-limit) → ControllerServiceDB (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.

Description
No description provided
Readme 5.5 MiB
Languages
JavaScript 92%
HTML 7.9%
Dockerfile 0.1%