5ade261cb20863bf602de7fa7fbfcd596e7e00bb
- Fix timesheet filename to use firstName-lastName format with username fallback - Remove auto-assign creator to todos (user must manually select assignees) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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ú ceznext(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)
- Logovanie:
morgan('dev')(len stdout). - Bezpečnostné hlavičky:
helmets CSP (self + inline styles) a HSTS (preload, subdomains). - CORS: povolený pôvod z
CORS_ORIGIN(defaulthttp://localhost:5173), credentials povolené. - Body parsers:
express.jsonaexpress.urlencoded(limit 10 MB),cookieParserpre JWT v cookies. - Global validateBody: rýchly regex-detektor podozrivých payloadov (loguje a vráti 400 pri matches).
- Rate limiting:
apiRateLimiterna/api/*(100 req/15 min v production, 1000 v dev). Špecifické limitery na login a citlivé operácie sa aplikujú v routes. - Routes:
auth,admin,contacts,emails(CRM),email-accounts,timesheets,companies,projects,todos,time-tracking,notes. - 404:
notFoundmiddleware nastaví 404 a pošle ďalej ako Error. - Global error handler:
errorHandlerloguje, zvolí status (err.statusCode>res.statusCode≥400 > 500) a formátuje pomocouformatErrorResponse. Ak už sú hlavičky poslané, púšťa chybu ďalej.
Validácia a bezpečnosť
- Zod validácia:
validateBody/validateQuery/validateParams(vmiddlewares/security/validateInput.js) na úrovni routes; nahrádzajúreq.body/query/paramsvalidovanými dátami. - Auth:
authenticatevytiahne JWT z Bearer header alebo cookie, overí cezverifyAccessToken, načíta usera (auth.service.getUserById) a uloží doreq.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.encryptPasswordpoužíva AES-256-GCM (kľúč zoJWT_SECRET+ENCRYPTION_SALT). Heslá v DB sú bcrypt hashované. - Audit logy:
audit.serviceloguje 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:
formatErrorResponsevracia{ 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) → auditlogLoginAttempt(success/fail) → nastaví httpOnly cookies + response. - /set-password:
authenticate→sensitiveOperationLimiter→validateBody(setPasswordSchema)→authService.setNewPassword(bcrypt, zmaže tempPassword) → auditlogPasswordChange. - /logout, /session: vyžadujú
authenticate; logout vyčistí cookies, session vrátireq.user. - Tokeny: generované v
utils/jwt.js(access + refresh); overenie hádžeAuthenticationErrorpri 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.servicepri 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 (validateJmapCredentialszemail.service.js), šifruje heslo (AES-256-GCM), vytvorí účet a many-to-many link douserEmailAccounts. Ak účet existuje, vie ho len „nasdieliť“ po overení hesla. - Set primary: pre konkrétneho používateľa; transakčne zruší ostatné
isPrimarya 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
getEmailAccountWithCredentialsdeš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/:threadIdnačíta konverzáciu;/thread/:threadId/readoznačí všetky maily v threade. - Sync:
/syncspustí fetch z JMAP pre daného používateľa/účet. - Mark contact read:
/contact/:contactId/readoznačí všetky maily od kontaktu ako prečítané. - Reply:
/replycez JMAP; používa dešifrované heslo z email-account service. - Unread count:
/unread-countagreguje 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)
authenticatepovinné.- 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)
authenticatepovinné.- 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 douploads/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/jwtaauth.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.servicena sync emailov od odosielateľa. - company.controller používa
company-email.service(agregácia email threadov) anote.service/company-reminder.service. - time-tracking.service používa Drizzle schémy
timeEntries,projects,todos,companies,usersna 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, zapojvalidateBody/Params/Query, použiauthenticate/requireAdminpodľa potreby, v controllery volaj service a pri chybenext(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.exampleak existuje / README bezpečnostný checklist). - Skripty:
npm run dev(nodemon),npm start,npm test(Jest), drizzle migráciedb: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
Languages
JavaScript
92%
HTML
7.9%
Dockerfile
0.1%