add many to one in todo, fix bugs, notification about todos

This commit is contained in:
richardtekula
2025-11-24 11:30:25 +01:00
parent 8fd8f991e8
commit 125e30338a
5 changed files with 381 additions and 24 deletions

View File

@@ -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 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