add many to one in todo, fix bugs, notification about todos
This commit is contained in:
375
DOKUMENTACIA.md
375
DOKUMENTACIA.md
@@ -561,10 +561,26 @@ getMonthlyStats(userId, year, month)
|
||||
- averagePerDay
|
||||
- byProject (čas per projekt)
|
||||
- byCompany (čas per firma)
|
||||
|
||||
generateMonthlyTimesheet(userId, year, month)
|
||||
→ Generate Excel (XLSX) report z time entries
|
||||
→ Fetch user info: username, firstName, lastName
|
||||
→ Fetch completed entries for month (LEFT JOIN projects, todos, companies)
|
||||
→ Filter: iba entries s endTime a duration
|
||||
→ Počíta: totalMinutes, dailyTotals (per day)
|
||||
→ Vytvára Excel workbook cez ExcelJS:
|
||||
- Header: Timesheet, Name, Period, Generated date
|
||||
- Table: Date, Project, Todo, Company, Description, Start, End, Duration
|
||||
- Summary: Daily totals + Overall total
|
||||
→ Save to: uploads/timesheets/{userId}/{year}/{month}/timesheet-{period}-{timestamp}.xlsx
|
||||
→ INSERT INTO timesheets (isGenerated = true)
|
||||
→ Vráti: { timesheet, filePath, entriesCount, totalMinutes, totalHours }
|
||||
```
|
||||
|
||||
**Volá:**
|
||||
- Databázu (timeEntries, projects, todos, companies)
|
||||
- Databázu (timeEntries, projects, todos, companies, users, timesheets)
|
||||
- ExcelJS library (workbook generation)
|
||||
- File system (fs/promises) - save XLSX file
|
||||
- `utils/errors.NotFoundError`
|
||||
- `utils/errors.BadRequestError`
|
||||
|
||||
@@ -609,10 +625,233 @@ logUserCreation(adminId, newUserId, username, role, ip, userAgent)
|
||||
|
||||
---
|
||||
|
||||
### 13. timesheet.controller.js
|
||||
**Účel:** File upload a správa timesheetov (PDF/Excel)
|
||||
|
||||
**Databáza:** `timesheets`, `users`
|
||||
|
||||
**Metódy:**
|
||||
```javascript
|
||||
uploadTimesheet(req, res)
|
||||
→ Validácia file type (PDF, Excel)
|
||||
→ Max 10MB limit
|
||||
→ Save to: uploads/timesheets/{userId}/{year}/{month}/
|
||||
→ INSERT INTO timesheets
|
||||
→ File stored on disk (not in DB)
|
||||
|
||||
getMyTimesheets(userId, filters)
|
||||
→ Filter: year, month (optional)
|
||||
→ SELECT * FROM timesheets WHERE userId
|
||||
→ ORDER BY uploadedAt DESC
|
||||
|
||||
getAllTimesheets(filters)
|
||||
→ Admin only!
|
||||
→ Filter: userId, year, month (all optional)
|
||||
→ LEFT JOIN users (get username, name)
|
||||
→ Vráti timesheets všetkých userov
|
||||
|
||||
downloadTimesheet(timesheetId, userId, userRole)
|
||||
→ Check permissions: owner alebo admin
|
||||
→ Validate file exists on disk
|
||||
→ res.download(filePath, fileName)
|
||||
|
||||
deleteTimesheet(timesheetId, userId, userRole)
|
||||
→ Check permissions: owner alebo admin
|
||||
→ Delete file from filesystem (fs.unlink)
|
||||
→ DELETE FROM timesheets
|
||||
→ Continue even if file deletion fails
|
||||
```
|
||||
|
||||
**Volá:**
|
||||
- Databázu (timesheets, users)
|
||||
- File system operations (fs/promises)
|
||||
- `utils/errors.NotFoundError, ForbiddenError, BadRequestError`
|
||||
|
||||
**File Storage Pattern:**
|
||||
```
|
||||
uploads/timesheets/
|
||||
└── {userId}/
|
||||
└── {year}/
|
||||
└── {month}/
|
||||
└── filename-timestamp-random.pdf
|
||||
```
|
||||
|
||||
**POZNÁMKA:** Timesheet service NEEXISTUJE - všetka logika je priamo v controlleri!
|
||||
|
||||
---
|
||||
|
||||
## VALIDATORS
|
||||
|
||||
### 1. auth.validators.js
|
||||
**Účel:** Zod schemas pre autentifikáciu a user management
|
||||
|
||||
**Schemas:**
|
||||
```javascript
|
||||
loginSchema
|
||||
→ username: 3-50 chars, required
|
||||
→ password: min 1 char, required
|
||||
|
||||
setPasswordSchema
|
||||
→ newPassword: min 8 chars, obsahuje a-z, A-Z, 0-9, špeciálny znak
|
||||
→ confirmPassword: musí sa zhodovať
|
||||
→ .refine() custom validation pre password match
|
||||
|
||||
linkEmailSchema
|
||||
→ email: valid email format, max 255 chars
|
||||
→ emailPassword: min 1 char
|
||||
|
||||
createUserSchema (admin only)
|
||||
→ username: 3-50 chars, iba [a-zA-Z0-9_-]
|
||||
→ email: optional (ak sa zadá, môže sa linknúť JMAP)
|
||||
→ emailPassword: optional (pre automatické linkovanie)
|
||||
→ firstName, lastName: optional, max 100 chars
|
||||
|
||||
updateUserSchema
|
||||
→ firstName, lastName, email: all optional
|
||||
|
||||
changeRoleSchema
|
||||
→ userId: UUID
|
||||
→ role: enum ['admin', 'member']
|
||||
```
|
||||
|
||||
**Použitie:**
|
||||
- Všetky `/api/auth/*` routes
|
||||
- Admin user management routes
|
||||
|
||||
---
|
||||
|
||||
### 2. crm.validators.js
|
||||
**Účel:** Zod schemas pre Company, Project, Todo, Note, Time Tracking
|
||||
|
||||
**Company Schemas:**
|
||||
```javascript
|
||||
createCompanySchema
|
||||
→ name: required, max 255 chars
|
||||
→ description: optional, max 1000 chars
|
||||
→ address, city, country: optional
|
||||
→ phone: optional, max 50 chars
|
||||
→ email: optional, valid email OR empty string
|
||||
→ website: optional, valid URL OR empty string
|
||||
|
||||
updateCompanySchema
|
||||
→ Všetky fields optional
|
||||
```
|
||||
|
||||
**Project Schemas:**
|
||||
```javascript
|
||||
createProjectSchema
|
||||
→ name: required, max 255 chars
|
||||
→ companyId: optional UUID OR empty string
|
||||
→ status: enum ['active', 'completed', 'on_hold', 'cancelled']
|
||||
→ startDate, endDate: optional strings OR empty
|
||||
|
||||
updateProjectSchema
|
||||
→ Všetky fields optional
|
||||
→ NULL support: .or(z.null())
|
||||
```
|
||||
|
||||
**Todo Schemas:**
|
||||
```javascript
|
||||
createTodoSchema
|
||||
→ title: required, max 255 chars
|
||||
→ projectId, companyId, assignedTo: optional UUID OR empty
|
||||
→ status: enum ['pending', 'in_progress', 'completed', 'cancelled']
|
||||
→ priority: enum ['low', 'medium', 'high', 'urgent']
|
||||
→ dueDate: optional string OR empty
|
||||
|
||||
updateTodoSchema
|
||||
→ Všetky fields optional + NULL support
|
||||
```
|
||||
|
||||
**Note Schemas:**
|
||||
```javascript
|
||||
createNoteSchema
|
||||
→ content: required, max 5000 chars
|
||||
→ title: optional, max 255 chars
|
||||
→ companyId, projectId, todoId, contactId: optional UUID OR empty
|
||||
→ reminderDate: optional string OR empty
|
||||
|
||||
updateNoteSchema
|
||||
→ Všetky fields optional + NULL support
|
||||
```
|
||||
|
||||
**Time Tracking Schemas:**
|
||||
```javascript
|
||||
startTimeEntrySchema
|
||||
→ projectId, todoId, companyId: optional UUID (preprocessed to null if empty)
|
||||
→ description: optional, max 1000 chars, trimmed, null if empty
|
||||
|
||||
stopTimeEntrySchema
|
||||
→ Same as start (používa sa pre update pri stop)
|
||||
|
||||
updateTimeEntrySchema
|
||||
→ startTime, endTime: optional ISO strings
|
||||
→ projectId, todoId, companyId, description: optional with preprocessing
|
||||
```
|
||||
|
||||
**Helper Functions:**
|
||||
```javascript
|
||||
optionalUuid(message)
|
||||
→ Preprocess: undefined, null, '' → null
|
||||
→ Validate: UUID format
|
||||
→ Used for optional foreign keys
|
||||
|
||||
optionalDescription
|
||||
→ Preprocess: trim whitespace, '' → null
|
||||
→ Validate: max 1000 chars
|
||||
→ Nullable
|
||||
```
|
||||
|
||||
**Pattern - Empty String Handling:**
|
||||
```javascript
|
||||
// Frontend môže poslať empty string namiesto null
|
||||
.or(z.literal('')) // Accept empty string
|
||||
.or(z.literal('').or(z.null())) // Update: accept empty OR null
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. email-account.validators.js
|
||||
**Účel:** Zod schemas pre email account management
|
||||
|
||||
**Schemas:**
|
||||
```javascript
|
||||
createEmailAccountSchema
|
||||
→ email: required, valid format, max 255 chars
|
||||
→ emailPassword: required, min 1 char
|
||||
|
||||
updateEmailAccountSchema
|
||||
→ emailPassword: optional, min 1 char
|
||||
→ isActive: optional boolean
|
||||
|
||||
setPrimaryAccountSchema
|
||||
→ accountId: UUID
|
||||
→ POZNÁMKA: NEVYUŽÍVA SA (endpoint má accountId v path params)
|
||||
```
|
||||
|
||||
**Použitie:**
|
||||
- `/api/email-accounts/*` routes
|
||||
- JMAP credential validation flow
|
||||
|
||||
---
|
||||
|
||||
## CONTROLLERS
|
||||
|
||||
**Účel:** Spracovanie HTTP requestov, volanie services, vracanie responses
|
||||
|
||||
### Zoznam Controllerov:
|
||||
1. **admin.controller.js** - User management (admin only)
|
||||
2. **auth.controller.js** - Autentifikácia a onboarding
|
||||
3. **company.controller.js** - Firmy CRUD + nested notes
|
||||
4. **contact.controller.js** - Email kontakty
|
||||
5. **crm-email.controller.js** - Email management (read status, search)
|
||||
6. **email-account.controller.js** - JMAP účty
|
||||
7. **note.controller.js** - Standalone poznámky (nevyužité)
|
||||
8. **project.controller.js** - Projekty CRUD + nested notes + team management
|
||||
9. **todo.controller.js** - Úlohy CRUD
|
||||
10. **time-tracking.controller.js** - Sledovanie času
|
||||
11. **timesheet.controller.js** - Upload a download timesheetov (bez service!)
|
||||
|
||||
### Štruktúra každého controllera:
|
||||
```javascript
|
||||
export const methodName = async (req, res) => {
|
||||
@@ -655,6 +894,19 @@ export const methodName = async (req, res) => {
|
||||
|
||||
**Účel:** Definícia endpointov, middleware, validácia
|
||||
|
||||
### Zoznam Route Files:
|
||||
1. **admin.routes.js** - User management (Auth + Admin role)
|
||||
2. **auth.routes.js** - Login, set password, link email (Mixed public/protected)
|
||||
3. **company.routes.js** - Firmy + nested notes (Auth only)
|
||||
4. **contact.routes.js** - Kontakty (Auth only)
|
||||
5. **crm-email.routes.js** - Emaily (Auth only)
|
||||
6. **email-account.routes.js** - JMAP účty (Auth only)
|
||||
7. **note.routes.js** - Standalone poznámky (Auth only, nevyužité)
|
||||
8. **project.routes.js** - Projekty + notes + team (Auth only)
|
||||
9. **todo.routes.js** - Úlohy (Auth only)
|
||||
10. **time-tracking.routes.js** - Time tracking (Auth only)
|
||||
11. **timesheet.routes.js** - Timesheets upload/download (Auth, admin for /all)
|
||||
|
||||
### Štruktúra route file:
|
||||
```javascript
|
||||
import express from 'express'
|
||||
@@ -697,6 +949,12 @@ export default router
|
||||
|
||||
## UTILS
|
||||
|
||||
### Zoznam Utility Files:
|
||||
1. **errors.js** - Custom error classes + formatting
|
||||
2. **jwt.js** - JWT token generation and validation
|
||||
3. **logger.js** - Colored console logging
|
||||
4. **password.js** - Password hashing, encryption, generation
|
||||
|
||||
### 1. errors.js
|
||||
**Účel:** Custom error classy a formatting
|
||||
|
||||
@@ -1500,14 +1758,40 @@ Order: DESC by startTime
|
||||
```
|
||||
Účel: Mesačný prehľad time entries
|
||||
Params: year (YYYY), month (1-12)
|
||||
Query: userId (optional, admin only – ak je zadaný, načítava sa daný používateľ)
|
||||
Auth: Áno
|
||||
Response: Array of entries pre daný mesiac
|
||||
```
|
||||
|
||||
#### POST /api/time-tracking/month/:year/:month/generate
|
||||
```
|
||||
Účel: Vygenerovať mesačný timesheet (Excel XLSX)
|
||||
Params: year (YYYY), month (1-12)
|
||||
Query: userId (optional, admin only - generate pre iného usera)
|
||||
Auth: Áno
|
||||
Body: {} (bez payloadu; posiela sa prázdny objekt)
|
||||
Response: {
|
||||
timesheet: { id, fileName, filePath, ... },
|
||||
filePath,
|
||||
entriesCount,
|
||||
totalMinutes,
|
||||
totalHours
|
||||
}
|
||||
Efekt:
|
||||
- Vytvorí Excel súbor s time entries pre daný mesiac
|
||||
- Obsahuje: denné záznamy, projekty, todos, descrip, duration
|
||||
- Summary: daily totals + overall total
|
||||
- Uloží do: uploads/timesheets/{userId}/{year}/{month}/
|
||||
- INSERT INTO timesheets (isGenerated = true)
|
||||
Volá: time-tracking.service.generateMonthlyTimesheet()
|
||||
Admin feature: Admin môže generovať timesheet pre iného usera (query param userId)
|
||||
```
|
||||
|
||||
#### GET /api/time-tracking/stats/monthly/:year/:month
|
||||
```
|
||||
Účel: Mesačné štatistiky
|
||||
Params: year (YYYY), month (1-12)
|
||||
Query: userId (optional, admin only – ak je zadaný, načítava sa daný používateľ)
|
||||
Auth: Áno
|
||||
Response: {
|
||||
totalMinutes,
|
||||
@@ -1566,39 +1850,70 @@ Validation:
|
||||
|
||||
#### POST /api/timesheets/upload
|
||||
```
|
||||
Účel: Upload timesheet file
|
||||
Účel: Upload timesheet file (manuálne nahraný PDF/Excel)
|
||||
Content-Type: multipart/form-data
|
||||
Form: file (PDF/Excel), year (YYYY), month (1-12)
|
||||
Auth: Áno
|
||||
Validation: Max 10MB
|
||||
Validation:
|
||||
- Max 10MB
|
||||
- Allowed types: PDF, Excel (xlsx, xls)
|
||||
Efekt:
|
||||
- Uloží file do: uploads/timesheets/{userId}/{year}/{month}/
|
||||
- Generate unique filename: {name}-{timestamp}-{random}.ext
|
||||
- INSERT INTO timesheets (isGenerated = false)
|
||||
Response: { timesheet object }
|
||||
```
|
||||
|
||||
#### GET /api/timesheets/my
|
||||
#### GET /api/timesheets/my?year=YYYY&month=M
|
||||
```
|
||||
Účel: Moje timesheets
|
||||
Účel: Moje timesheets (uploaded + generated)
|
||||
Query: year, month (both optional)
|
||||
Auth: Áno
|
||||
Response: { timesheets: [...], count }
|
||||
Order: DESC by uploadedAt
|
||||
```
|
||||
|
||||
#### GET /api/timesheets/all
|
||||
#### GET /api/timesheets/all?userId=uuid&year=YYYY&month=M
|
||||
```
|
||||
Účel: Všetky timesheets (admin)
|
||||
Účel: Všetky timesheets všetkých userov (admin)
|
||||
Query: userId, year, month (all optional)
|
||||
Auth: Áno (admin only)
|
||||
Response: { timesheets: [...with user info...], count }
|
||||
Includes: userId, username, firstName, lastName (LEFT JOIN users)
|
||||
Order: DESC by uploadedAt
|
||||
```
|
||||
|
||||
#### GET /api/timesheets/:timesheetId/download
|
||||
```
|
||||
Účel: Stiahnuť timesheet file
|
||||
Auth: Áno
|
||||
Response: File download
|
||||
Permissions: Owner OR admin
|
||||
Response: File download (res.download)
|
||||
Errors:
|
||||
- 404: Timesheet nenájdený alebo súbor neexistuje
|
||||
- 403: Nemáte oprávnenie (nie vlastník ani admin)
|
||||
```
|
||||
|
||||
#### DELETE /api/timesheets/:timesheetId
|
||||
```
|
||||
Účel: Zmazať timesheet
|
||||
Auth: Áno
|
||||
Efekt: Delete file + DB record
|
||||
Permissions: Owner OR admin
|
||||
Efekt:
|
||||
- Delete file from filesystem (fs.unlink)
|
||||
- DELETE FROM timesheets
|
||||
- Continue even if file deletion fails (log error)
|
||||
Errors:
|
||||
- 404: Timesheet nenájdený
|
||||
- 403: Nemáte oprávnenie
|
||||
```
|
||||
|
||||
**POZNÁMKA:**
|
||||
- Timesheets môžu byť **uploaded** (manuálne PDF/Excel) alebo **generated** (auto Excel z time entries)
|
||||
- Field `isGenerated` rozlišuje typ: `true` = auto-generated, `false` = manually uploaded
|
||||
- Obe typy sa ukladajú do rovnakej tabuľky `timesheets` a rovnakého adresára
|
||||
- Generated timesheets sa vytvárajú cez `POST /api/time-tracking/month/:year/:month/generate`
|
||||
|
||||
---
|
||||
|
||||
## VZŤAHY MEDZI SLUŽBAMI
|
||||
@@ -1978,7 +2293,41 @@ console.log('[DEBUG] JMAP validation:', valid);
|
||||
|
||||
---
|
||||
|
||||
**Vytvorené:** 2025-11-21
|
||||
**Posledná aktualizácia:** 2025-11-24
|
||||
**Autor:** CRM Server Team
|
||||
**Kontakt:** crm-server documentation
|
||||
**Vytvorené:** 2025-11-21
|
||||
**Posledná aktualizácia:** 2025-11-24
|
||||
**Autor:** CRM Server Team
|
||||
|
||||
---
|
||||
|
||||
## CHANGELOG
|
||||
|
||||
### 2025-11-24 - Additions
|
||||
**Pridané sekcie:**
|
||||
1. **VALIDATORS** - Kompletná dokumentácia všetkých Zod schemas
|
||||
- auth.validators.js (login, password, user creation)
|
||||
- crm.validators.js (company, project, todo, note, time tracking)
|
||||
- email-account.validators.js (JMAP accounts)
|
||||
|
||||
2. **SERVICES** - Doplnené chýbajúce metódy
|
||||
- time-tracking.service.generateMonthlyTimesheet() - Excel XLSX generation
|
||||
|
||||
3. **CONTROLLERS** - Pridaný chýbajúci controller
|
||||
- timesheet.controller.js - File upload/download (bez service layer)
|
||||
|
||||
4. **ROUTES** - Kompletný zoznam všetkých route files
|
||||
- 11 route files s uvedením middleware requirements
|
||||
|
||||
5. **API ROUTES** - Doplnené chýbajúce endpointy
|
||||
- POST /api/time-tracking/month/:year/:month/generate - Generate Excel timesheet
|
||||
- GET /api/timesheets/my - Detail s filters (year, month)
|
||||
- GET /api/timesheets/all - Admin endpoint s filters
|
||||
- DELETE /api/timesheets/:timesheetId - Permission checks
|
||||
|
||||
6. **UTILS** - Zoznam všetkých utility files (boli už zdokumentované)
|
||||
|
||||
**Upresnenia:**
|
||||
- Timesheet service NEEXISTUJE - logika priamo v controlleri
|
||||
- isGenerated flag rozlišuje uploaded vs generated timesheets
|
||||
- Admin môže generovať timesheet pre iného usera (query param userId)
|
||||
- Empty string handling vo validátoroch: `.or(z.literal(''))` pattern
|
||||
- Optional UUID preprocessing v time tracking schemas
|
||||
|
||||
Reference in New Issue
Block a user