This shows you the differences between two versions of the page.
poo-ca-cd:teme:2025:b73f56dc-17a1-42ac-bd7e-d57f3caaf9fd:tema-2 [2025/10/02 09:31] valentin.carauleanu [Restricții] |
poo-ca-cd:teme:2025:b73f56dc-17a1-42ac-bd7e-d57f3caaf9fd:tema-2 [2025/10/02 12:07] (current) valentin.carauleanu [Customer Impact] |
||
---|---|---|---|
Line 103: | Line 103: | ||
<note tip> | <note tip> | ||
Câmpul **description** este opțional. </note> | Câmpul **description** este opțional. </note> | ||
+ | |||
+ | ==== Rezumat ==== | ||
+ | {{:poo-ca-cd:teme:2025:b73f56dc-17a1-42ac-bd7e-d57f3caaf9fd:types.png?800|}} | ||
+ | |||
+ | |||
==== 1. BUG ==== | ==== 1. BUG ==== | ||
Line 550: | Line 555: | ||
</code> | </code> | ||
</spoiler> | </spoiler> | ||
+ | \\ | ||
3. Un **Reporter** nu poate comenta dacă ticket-ul are status **CLOSED**. În cazul în care se încearcă comentarea unui ticket cu status **CLOSED**, comanda este respinsă: | 3. Un **Reporter** nu poate comenta dacă ticket-ul are status **CLOSED**. În cazul în care se încearcă comentarea unui ticket cu status **CLOSED**, comanda este respinsă: | ||
Line 563: | Line 569: | ||
</code> | </code> | ||
</spoiler> | </spoiler> | ||
+ | \\ | ||
4. Conținutul comentariului trebuie să aibă minim **10 caractere**. Dacă este mai mic, comanda este respinsă: | 4. Conținutul comentariului trebuie să aibă minim **10 caractere**. Dacă este mai mic, comanda este respinsă: | ||
Line 576: | Line 582: | ||
</code> | </code> | ||
</spoiler> | </spoiler> | ||
+ | \\ | ||
5. Un **Developer** poate comenta doar pe ticketele care îi sunt atribuite. Dacă un developer încearcă să comenteze un ticket care nu îi este atribuit, comanda este respinsă: | 5. Un **Developer** poate comenta doar pe ticketele care îi sunt atribuite. Dacă un developer încearcă să comenteze un ticket care nu îi este atribuit, comanda este respinsă: | ||
Line 589: | Line 595: | ||
</code> | </code> | ||
</spoiler> | </spoiler> | ||
+ | \\ | ||
6. Un **Reporter** poate comenta doar pe ticketele pe care le-a raportat. Dacă un reporter încearcă să comenteze un ticket pe care nu l-a raportat, comanda este respinsă: | 6. Un **Reporter** poate comenta doar pe ticketele pe care le-a raportat. Dacă un reporter încearcă să comenteze un ticket pe care nu l-a raportat, comanda este respinsă: | ||
+ | \\ | ||
<spoiler Output eroare> | <spoiler Output eroare> | ||
Line 943: | Line 950: | ||
* Sunt permise doar următoarele tranziții de status: **RESOLVED → IN_PROGRESS**, **CLOSED → RESOLVED**. Nu vor exista excepții în teste. | * Sunt permise doar următoarele tranziții de status: **RESOLVED → IN_PROGRESS**, **CLOSED → RESOLVED**. Nu vor exista excepții în teste. | ||
- | * Operația rămâne în istoric. Mai multe detalii în secțiunea [View Ticket History](#viewtickethistory). | + | * Operația rămâne în istoric. |
</note> | </note> | ||
Line 1019: | Line 1026: | ||
} </code> </spoiler> | } </code> </spoiler> | ||
+ | ===== viewTickets ===== | ||
+ | **Disponibilă pentru:** **Developer**, **Manager**, **Reporter** | ||
+ | |||
+ | **Descriere:** | ||
+ | Afișează ticketele din sistem în funcție de rolul utilizatorului curent. | ||
+ | |||
+ | ==== Restricții ==== | ||
+ | 1. **Developer**: vede toate ticketele cu status **OPEN** din milestone-urile la care este repartizat (indiferent dacă și le poate atribui). | ||
+ | | ||
+ | 2. **Manager**: vede toate ticketele din sistem. | ||
+ | |||
+ | 3. **Reporter**: vede doar ticketele raportate de el (ticketele anonime sunt excluse). | ||
+ | |||
+ | <note tip> | ||
+ | |||
+ | * Rezultatele sunt sortate după **createdAt** (de la cele mai vechi la cele mai noi), iar în caz de egalitate după **id** crescător. | ||
+ | |||
+ | </note> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Input:** <spoiler Exemplu input complet> <code json> | ||
+ | { | ||
+ | "command": "viewTickets", | ||
+ | "username": "manager_one", | ||
+ | "timestamp": "2025-09-25" | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Output:** <spoiler Exemplu output complet> <code json> | ||
+ | { | ||
+ | "command": "viewTickets", | ||
+ | "username": "dev_one", | ||
+ | "timestamp": "2025-09-25", | ||
+ | "tickets": [ | ||
+ | { | ||
+ | "id": 0, | ||
+ | "type": "BUG", | ||
+ | "title": "Crash on settings page", | ||
+ | "businessPriority": "HIGH", | ||
+ | "status": "IN_PROGRESS", | ||
+ | "createdAt": "2025-09-10", | ||
+ | "solvedAt": "", | ||
+ | "assignedAt": "2025-09-21", | ||
+ | "assignedTo": "dev_one", | ||
+ | "reportedBy": "cleopatra", | ||
+ | "comments": [ | ||
+ | { | ||
+ | "author": "dev_one", | ||
+ | "content": "I am looking into this issue.", | ||
+ | "createdAt": "2025-09-10" | ||
+ | }, | ||
+ | { | ||
+ | "author": "manager_gabriel", | ||
+ | "content": "Please prioritize this bug.", | ||
+ | "createdAt": "2025-09-11" | ||
+ | } | ||
+ | ] | ||
+ | }, | ||
+ | { | ||
+ | "id": 3, | ||
+ | "type": "BUG", | ||
+ | "title": "UI glitch on dashboard", | ||
+ | "businessPriority": "LOW", | ||
+ | "status": "OPEN", | ||
+ | "createdAt": "2025-09-20", | ||
+ | "solvedAt": "", | ||
+ | "reportedBy": "", | ||
+ | "comments": [] | ||
+ | } | ||
+ | ] | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | ===== viewMilestones ===== | ||
+ | |||
+ | **Disponibilă pentru:** **Manager**, **Developer** | ||
+ | |||
+ | **Descriere:** Afișează milestone-urile din sistem în funcție de rolul utilizatorului curent. | ||
+ | |||
+ | ==== Restricții ==== | ||
+ | 1. **Manager**: vede toate milestone-urile create de el. | ||
+ | |||
+ | 2. **Developer**: vede toate milestone-urile la care este atribuit. | ||
+ | |||
+ | |||
+ | <note tip> | ||
+ | * Milestone-urile sunt afișate crescător după **dueDate**, iar în caz de egalitate lexicografic crescător după `name`. | ||
+ | </note> | ||
+ | | ||
+ | <note warning> | ||
+ | * Când un milestone devine inactiv (ultimul ticket devine CLOSED), **overdueBy** și **daysUntilDue** rămân blocate. | ||
+ | |||
+ | * Exemplu: un milestone are **dueDate** pe 20 oct. Pe 18 oct ultimul ticket este închis. Comanda **viewMilestones** de pe 21 octombrie va afișa **daysUntilDue = 3** și **overdueBy = 0**. | ||
+ | </note> | ||
+ | |||
+ | <spoiler **completionPercentage**> | ||
+ | \\ | ||
+ | Calculat ca raportul dintre numărul de tickete **CLOSED** și numărul total de tickete din milestone. | ||
+ | Valoare de tip **Double**, afișată cu **2 zecimale**. | ||
+ | \\ | ||
+ | </spoiler> | ||
+ | |||
+ | <spoiler **daysUntilDue**> | ||
+ | \\ | ||
+ | Numărul de zile rămase până la **dueDate**. | ||
+ | Dacă **dueDate** este în trecut, valoarea este **0**. | ||
+ | **Formulă:** **dueDate - currentDay + 1** | ||
+ | \\ | ||
+ | </spoiler> | ||
+ | |||
+ | |||
+ | <spoiler **overdueBy**> | ||
+ | \\ | ||
+ | Numărul de zile cu care **dueDate** a fost depășit. | ||
+ | Dacă **dueDate** este în viitor, valoarea este **0**. | ||
+ | \\ | ||
+ | </spoiler> | ||
+ | |||
+ | |||
+ | <spoiler **repartition**> | ||
+ | \\ | ||
+ | Listă de obiecte ce conțin: | ||
+ | * numele developerilor responsabili pentru milestone | ||
+ | * ID-urile ticketelor atribuite fiecăruia | ||
+ | |||
+ | Lista este: | ||
+ | * sortată **descrescător** după numărul de tickete atribuite | ||
+ | * în caz de egalitate, după **username** (ordine alfabetică). | ||
+ | \\ | ||
+ | </spoiler> | ||
+ | |||
+ | <spoiler **status**> | ||
+ | \\ | ||
+ | Poate avea două valori: | ||
+ | * **ACTIVE** – dacă există tickete nerezolvate în milestone | ||
+ | * **COMPLETED** – dacă **toate** ticketele sunt **CLOSED** | ||
+ | \\ | ||
+ | </spoiler> | ||
+ | |||
+ | |||
+ | \\ | ||
+ | **Exemplu Input:** <spoiler Exemplu input complet> <code json> | ||
+ | { | ||
+ | "command": "viewMilestones", | ||
+ | "username": "username", | ||
+ | "timestamp": "2025-09-25" | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Output:** <spoiler Exemplu output complet> <code json> | ||
+ | { | ||
+ | "command": "viewMilestones", | ||
+ | "username": "pm_lead", | ||
+ | "timestamp": "2025-09-25", | ||
+ | "milestones": [ | ||
+ | { | ||
+ | "name": "v1.0", | ||
+ | "blockingFor": ["v2.0"], | ||
+ | "dueDate": "2025-10-01", | ||
+ | "createdAt": "2025-09-15", | ||
+ | "tickets": [0, 1, 2], | ||
+ | "assignedDevs": ["dev_one", "dev_two"], | ||
+ | "createdBy": "gabriel_manager", | ||
+ | "status": "ACTIVE", | ||
+ | "isBlocked": false, | ||
+ | "daysUntilDue": 6, | ||
+ | "overdueBy": 0, | ||
+ | "openTickets": [0, 1, 2], | ||
+ | "closedTickets": [], | ||
+ | "completionPercentage": 0.00, | ||
+ | "repartition": [ | ||
+ | { | ||
+ | "developer": "dev_one", | ||
+ | "assignedTickets": [1] | ||
+ | }, | ||
+ | { | ||
+ | "developer": "dev_two", | ||
+ | "assignedTickets": [2] | ||
+ | }, | ||
+ | { | ||
+ | "developer": "dev_three", | ||
+ | "assignedTickets": [] | ||
+ | } | ||
+ | ] | ||
+ | } | ||
+ | ] | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | ===== viewNotifications ===== | ||
+ | |||
+ | **Disponibilă pentru:** **Developer**, **Reporter** | ||
+ | |||
+ | **Descriere:** | ||
+ | Afișează toate notificările primite de utilizator. | ||
+ | |||
+ | ==== Restricții ==== | ||
+ | |||
+ | <note tip> | ||
+ | * Notificările sunt afișate în ordinea primirii (**cele mai vechi primele**). În caz de egalitate, în ordine lexicografică după conținut. | ||
+ | |||
+ | * După vizualizare, notificările sunt șterse din sistem. | ||
+ | </note> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Input:** <spoiler Exemplu input complet> <code json> | ||
+ | { | ||
+ | "command": "viewNotifications", | ||
+ | "username": "user_name", | ||
+ | "timestamp": "2025-09-25" | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Output:** <spoiler Exemplu output complet> <code json> | ||
+ | { | ||
+ | "command": "viewNotifications", | ||
+ | "username": "user_name", | ||
+ | "timestamp": "2025-09-25", | ||
+ | "notifications": [ | ||
+ | "<Notification 1>", | ||
+ | "<Notification 2>", | ||
+ | "<Notification 3>" | ||
+ | ] | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | \\ | ||
+ | |||
+ | ===== viewTicketHistory ===== | ||
+ | |||
+ | **Disponibilă pentru:** **Developer**, **Manager** | ||
+ | |||
+ | **Descriere:** Un user vede istoricul ticketelor. | ||
+ | |||
+ | |||
+ | ==== Restricții ==== | ||
+ | 1. Un **Developer** poate vedea istoricul ticketelor pe care le-a avut atribuite (inclusiv cele rezolvate) și parcursul lor (**status changes**, **comments**). | ||
+ | |||
+ | 2. Un **Manager** poate vedea istoricul ticketelor care au fost în milestone-urile pe care le-a creat, pentru toți developerii implicați. | ||
+ | |||
+ | <note tip> | ||
+ | * Rezultatele sunt sortate după data **createdAt**, cele mai vechi fiind afișate primele, iar în caz de egalitate după **id**. | ||
+ | * | ||
+ | * Acțiunile apar în ordinea în care au fost efectuate. | ||
+ | </note> | ||
+ | |||
+ | === Acțiuni posibile === | ||
+ | |||
+ | * **ASSIGNED** – ticket-ul a fost atribuit unui developer. | ||
+ | |||
+ | <spoiler Exemplu JSON> | ||
+ | <code json> | ||
+ | { | ||
+ | "action": "ASSIGNED", | ||
+ | "by": "developer_name", | ||
+ | "timestamp": "YYYY-MM-DD" | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | |||
+ | * **DE-ASSIGNED** – developer-ul a renunțat la ticket. | ||
+ | |||
+ | <spoiler Exemplu JSON> | ||
+ | <code json> | ||
+ | { | ||
+ | "action": "DE-ASSIGNED", | ||
+ | "by": "developer_name", | ||
+ | "timestamp": "YYYY-MM-DD" | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | |||
+ | * **STATUS_CHANGED** – status-ul ticket-ului a fost schimbat. | ||
+ | |||
+ | <spoiler Exemplu JSON> | ||
+ | <code json> | ||
+ | { | ||
+ | "action": "STATUS_CHANGED", | ||
+ | "from": "OLD_STATUS", | ||
+ | "to": "NEW_STATUS", | ||
+ | "by": "developer_name", | ||
+ | "timestamp": "YYYY-MM-DD" | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | |||
+ | * **ADDED_TO_MILESTONE** – ticket-ul a fost adăugat într-un milestone. | ||
+ | |||
+ | <spoiler Exemplu JSON> | ||
+ | <code json> | ||
+ | { | ||
+ | "action": "ADDED_TO_MILESTONE", | ||
+ | "milestone": "milestone_name", | ||
+ | "by": "manager_name", | ||
+ | "timestamp": "YYYY-MM-DD" | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | ==== ==== | ||
+ | \\ | ||
+ | **Exemplu Input:** <spoiler Exemplu input complet> <code json> | ||
+ | { | ||
+ | "command": "viewTicketHistory", | ||
+ | "username": "dev_one", | ||
+ | "timestamp": "2025-09-25" | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Output:** <spoiler Exemplu output complet> <code json> | ||
+ | { | ||
+ | "command": "viewTicketHistory", | ||
+ | "username": "dev_one", | ||
+ | "timestamp": "2025-09-25", | ||
+ | "ticketHistory": [ | ||
+ | { | ||
+ | "id": 0, | ||
+ | "title": "Ticket 1", | ||
+ | "status": "CLOSED", | ||
+ | "actions": [ | ||
+ | { | ||
+ | "action": "ASSIGNED", | ||
+ | "by": "dev_one", | ||
+ | "timestamp": "2025-09-15" | ||
+ | }, | ||
+ | { | ||
+ | "action": "STATUS_CHANGED", | ||
+ | "from": "OPEN", | ||
+ | "to": "IN_PROGRESS", | ||
+ | "by": "dev_one", | ||
+ | "timestamp": "2025-09-15" | ||
+ | }, | ||
+ | { | ||
+ | "action": "STATUS_CHANGED", | ||
+ | "from": "IN_PROGRESS", | ||
+ | "to": "RESOLVED", | ||
+ | "by": "dev_one", | ||
+ | "timestamp": "2025-09-18" | ||
+ | }, | ||
+ | { | ||
+ | "action": "STATUS_CHANGED", | ||
+ | "from": "RESOLVED", | ||
+ | "to": "CLOSED", | ||
+ | "by": "dev_one", | ||
+ | "timestamp": "2025-09-20" | ||
+ | } | ||
+ | ], | ||
+ | "comments": [ | ||
+ | { | ||
+ | "author": "dev_one", | ||
+ | "timestamp": "2025-09-20", | ||
+ | "message": "Fixed the issue." | ||
+ | } | ||
+ | ] | ||
+ | }, | ||
+ | { | ||
+ | "id": 1, | ||
+ | "title": "Ticket 2", | ||
+ | "status": "IN_PROGRESS", | ||
+ | "actions": [ | ||
+ | { | ||
+ | "action": "ASSIGNED", | ||
+ | "by": "dev_one", | ||
+ | "timestamp": "2025-09-22" | ||
+ | }, | ||
+ | { | ||
+ | "action": "STATUS_CHANGED", | ||
+ | "from": "OPEN", | ||
+ | "to": "IN_PROGRESS", | ||
+ | "by": "dev_one", | ||
+ | "timestamp": "2025-09-22" | ||
+ | }, | ||
+ | { | ||
+ | "action": "DE-ASSIGNED", | ||
+ | "by": "dev_one", | ||
+ | "timestamp": "2025-09-23" | ||
+ | } | ||
+ | ], | ||
+ | "comments": [] | ||
+ | } | ||
+ | ] | ||
+ | } </code> </spoiler> | ||
+ | \\ | ||
+ | |||
+ | ===== search ===== | ||
+ | |||
+ | |||
+ | **Disponibilă pentru:** **Developer**, **Manager** | ||
+ | |||
+ | **Descriere:** | ||
+ | Permite căutarea avansată a ticketelor (sau developerilor, în cazul managerilor) pe baza unor criterii de filtrare. | ||
+ | |||
+ | ==== Restricții ==== | ||
+ | |||
+ | 1. Dacă un filtru este invalid pentru rolul utilizatorului, comanda este respinsă: | ||
+ | |||
+ | <spoiler Output eroare> | ||
+ | <code json> | ||
+ | { | ||
+ | "command": "search", | ||
+ | "username": "user_name", | ||
+ | "timestamp": "YYYY-MM-DD", | ||
+ | "error": "Invalid filter <filter_name> for role <role>." | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | ==== Reguli generale ==== | ||
+ | * Rezultatele sunt sortate după createdAt (cele mai vechi primele), apoi după id | ||
+ | * Dacă un filtru nu este specificat → nu se aplică filtrare pe acel câmp | ||
+ | * Dacă nu este specificat niciun filtru → comanda este echivalentă cu viewTickets | ||
+ | * Dacă nu există rezultate → se returnează o listă goală | ||
+ | |||
+ | <note warning> | ||
+ | **Atenție!** | ||
+ | Dacă sunt introduse mai multe filtre invalide, comanda va eșua la **primul filtru invalid**. | ||
+ | </note> | ||
+ | |||
+ | ==== Filtre Developer ==== | ||
+ | * Poate căuta: **doar tickete cu status OPEN** din milestone-urile la care este repartizat | ||
+ | * Filtre disponibile: | ||
+ | * businessPriority | ||
+ | * type | ||
+ | * createdAt | ||
+ | * createdBefore | ||
+ | * createdAfter | ||
+ | * availableForAssignment | ||
+ | |||
+ | ==== Filtre manager ==== | ||
+ | * Poate căuta: **toate ticketele din sistem** și **developerii din subordine** | ||
+ | * Filtre disponibile: | ||
+ | * toate filtrele Developer | ||
+ | * keywords | ||
+ | * expertiseArea | ||
+ | * seniority | ||
+ | * performanceScoreAbove | ||
+ | * performanceScoreBelow | ||
+ | |||
+ | <note warning> | ||
+ | **Atenție!** | ||
+ | * keywords este case-insensitive și caută potrivirea parțială sau completă în câmpurile text. | ||
+ | |||
+ | * Nu se aplică pentru câmpuri cu valori predefinite (enums). | ||
+ | | ||
+ | * În output, **matchingWords** arată cuvintele cheie găsite ca potrivire pentru keywords | ||
+ | |||
+ | </note> | ||
+ | |||
+ | |||
+ | <note warning> | ||
+ | **Atenție!** Dacă **availableForAssignment** = **true**, comanda returnează doar ticketele ce pot fi repartizate developerului curent (în funcție de senioritate, expertiză și milestone) | ||
+ | </note> | ||
+ | |||
+ | |||
+ | <note tip> | ||
+ | **Tip:** | ||
+ | Implementarea căutării trebuie să urmeze **Open-Closed Principle**, permițând adăugarea de noi strategii de filtrare fără modificarea codului existent. </note> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Input – Developer:** <spoiler Exemplu input complet> <code json> | ||
+ | { | ||
+ | "command": "search", | ||
+ | "username": "dev_one", | ||
+ | "timestamp": "2025-09-26", | ||
+ | "filters": { | ||
+ | "searchType": "TICKET", | ||
+ | "businessPriority": "HIGH", | ||
+ | "type": "BUG", | ||
+ | "createdAfter": "2025-09-01", | ||
+ | "availableForAssignment": true | ||
+ | } | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Output – Developer:** <spoiler Exemplu output complet> <code json> | ||
+ | { | ||
+ | "command": "search", | ||
+ | "username": "dev_one", | ||
+ | "timestamp": "2025-09-26", | ||
+ | "searchType": "TICKET", | ||
+ | "results": [ | ||
+ | { | ||
+ | "id": 0, | ||
+ | "type": "BUG", | ||
+ | "title": "Crash on settings page", | ||
+ | "businessPriority": "HIGH", | ||
+ | "status": "OPEN", | ||
+ | "createdAt": "2025-09-10", | ||
+ | "solvedAt": "", | ||
+ | "reportedBy": "cleopatra" | ||
+ | }, | ||
+ | { | ||
+ | "id": 3, | ||
+ | "type": "BUG", | ||
+ | "title": "Data sync failure", | ||
+ | "businessPriority": "HIGH", | ||
+ | "status": "OPEN", | ||
+ | "createdAt": "2025-09-15", | ||
+ | "solvedAt": "", | ||
+ | "reportedBy": "" | ||
+ | } | ||
+ | ] | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Input – Manager (tickets):** <spoiler Exemplu input complet> <code json> | ||
+ | { | ||
+ | "command": "search", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-26", | ||
+ | "filters": { | ||
+ | "searchType": "TICKET", | ||
+ | "keywords": ["pay", "bug"], | ||
+ | "businessPriority": "HIGH", | ||
+ | "type": "BUG", | ||
+ | "createdAfter": "2025-09-01" | ||
+ | } | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Output – Manager (tickets):** <spoiler Exemplu output complet> <code json> | ||
+ | { | ||
+ | "command": "search", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-26", | ||
+ | "searchType": "TICKET", | ||
+ | "results": [ | ||
+ | { | ||
+ | "id": 5, | ||
+ | "type": "BUG", | ||
+ | "title": "Payment gateway error", | ||
+ | "businessPriority": "HIGH", | ||
+ | "status": "OPEN", | ||
+ | "createdAt": "2025-09-12", | ||
+ | "solvedAt": "", | ||
+ | "reportedBy": "user456", | ||
+ | "matchingWords": ["payment", "bug"] | ||
+ | } | ||
+ | ] | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Input – Manager (developers):** <spoiler Exemplu input complet> <code json> | ||
+ | { | ||
+ | "command": "search", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-26", | ||
+ | "filters": { | ||
+ | "searchType": "DEVELOPER", | ||
+ | "expertiseArea": "BACKEND", | ||
+ | "seniority": "MID", | ||
+ | "performanceScoreAbove": number | ||
+ | } | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Output – Manager (developers):** <spoiler Exemplu output complet> <code json> | ||
+ | { | ||
+ | "command": "search", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-26", | ||
+ | "searchType": "DEVELOPER", | ||
+ | "results": [ | ||
+ | { | ||
+ | "username": "dev_two", | ||
+ | "expertiseArea": "BACKEND", | ||
+ | "seniority": "MID", | ||
+ | "performanceScore": number, | ||
+ | "hireDate": "2024-05-10" | ||
+ | } | ||
+ | ] | ||
+ | } </code> </spoiler> | ||
+ | \\ | ||
+ | ===== generatePerformanceReport ===== | ||
+ | |||
+ | **Disponibilă pentru:** **Manager** | ||
+ | |||
+ | **Descriere:** Generează raportul lunar de performanță pentru toți developerii din subordinea managerului. În raport sunt incluse toate ticketele rezolvate (status **CLOSED**) în luna anterioară datei curente (preluată din **timestamp**). | ||
+ | |||
+ | ==== Calculare raport ==== | ||
+ | |||
+ | Scorul de performanță se calculează diferit pentru fiecare nivel de **seniority**. | ||
+ | |||
+ | <spoiler Bonusuri nivel de senioritate> | ||
+ | * **JUNIOR** → +5 | ||
+ | * **MID** → +15 | ||
+ | * **SENIOR** → +30 | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | |||
+ | === Junior Performance === | ||
+ | |||
+ | <spoiler Formula> | ||
+ | \\ | ||
+ | * juniorPerformance = max(0, 0.5 * closedTickets - ticketDiversityFactor) + seniorityBonus | ||
+ | \\ | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | Vom defini **ticketDiversityFactor** ca fiind coeficientul de variație dintre deviația standard și media aritmetică. | ||
+ | |||
+ | <spoiler Detalii calcul> | ||
+ | * **averageResolvedTicketType** | ||
+ | <code>(bugTickets + featureTickets + uiTickets) / 3</code> | ||
+ | * **standardDeviation** | ||
+ | <code>sqrt(((bugTickets - avg)^2 + (featureTickets - avg)^2 + (uiTickets - avg)^2) / 3)</code> | ||
+ | * **ticketDiversityFactor** | ||
+ | <code>standardDeviation / averageResolvedTicketType</code> | ||
+ | </spoiler> | ||
+ | |||
+ | |||
+ | |||
+ | === Mid Performance === | ||
+ | |||
+ | <spoiler Formula> | ||
+ | \\ | ||
+ | * midPerformance = max(0, 0.5 * closedTickets + 0.7 * highPriorityTickets - 0.3 * averageResolutionTime) + seniorityBonus | ||
+ | \\ | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | <spoiler Detalii calcul Mid Performance> | ||
+ | \\ | ||
+ | * closedTickets = numărul total de tickete rezolvate | ||
+ | * highPriorityTickets = numărul de tickete rezolvate cu prioritate HIGH sau CRITICAL | ||
+ | * averageResolutionTime = media timpilor de rezolvare (zile) | ||
+ | \\ | ||
+ | </spoiler> | ||
+ | |||
+ | |||
+ | === Senior Performance === | ||
+ | |||
+ | <spoiler Formula> | ||
+ | * seniorPerformance = max(0, 0.5 * closedTickets + 1.0 * highPriorityTickets - 0.5 * averageResolutionTime) + seniorityBonus | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | <spoiler Detalii calcul Senior Performance> | ||
+ | \\ | ||
+ | * closedTickets = numărul total de tickete rezolvate | ||
+ | * highPriorityTickets = numărul de tickete rezolvate cu prioritate HIGH sau CRITICAL | ||
+ | * averageResolutionTime = media timpilor de rezolvare (zile) | ||
+ | * Impactul ticketelor cu prioritate ridicată și timpul de rezolvare contează mai mult | ||
+ | * Formula penalizează timpi mari de rezolvare și răsplătește rezolvarea ticketelor importante | ||
+ | \\ | ||
+ | </spoiler> | ||
+ | |||
+ | |||
+ | === Metode utile === | ||
+ | Puteti folosi următoarele metode în soluția temei: | ||
+ | |||
+ | <spoiler Java code> | ||
+ | <code java> | ||
+ | public static double averageResolvedTicketType(int bug, int feature, int ui) { | ||
+ | return (bug + feature + ui) / 3.0; | ||
+ | } | ||
+ | |||
+ | public static double standardDeviation(int bug, int feature, int ui) { | ||
+ | double mean = averageResolvedTicketType(bug, feature, ui); | ||
+ | double variance = (Math.pow(bug - mean, 2) + Math.pow(feature - mean, 2) + Math.pow(ui - mean, 2)) / 3.0; | ||
+ | return Math.sqrt(variance); | ||
+ | } | ||
+ | |||
+ | public static double ticketDiversityFactor(int bug, int feature, int ui) { | ||
+ | double mean = averageResolvedTicketType(bug, feature, ui); | ||
+ | |||
+ | // dacă nu există tickete, diversitatea este 0 | ||
+ | if (mean == 0.0) { | ||
+ | return 0.0; | ||
+ | } | ||
+ | |||
+ | double std = standardDeviation(bug, feature, ui); | ||
+ | return std / mean; | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Input:** | ||
+ | <spoiler Exemplu input complet> | ||
+ | <code json> | ||
+ | { | ||
+ | "command": "generatePerformanceReport", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-01" | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Output:** | ||
+ | <spoiler Exemplu output complet> | ||
+ | <code json> | ||
+ | { | ||
+ | "command": "generatePerformanceReport", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-01", | ||
+ | "report": [ | ||
+ | { | ||
+ | "username": "dev_one", | ||
+ | "closedTickets": 5, | ||
+ | "averageResolutionTime": 4.2, | ||
+ | "ticketTypes": { | ||
+ | "BUG": 3, | ||
+ | "FEATURE_REQUEST": 1, | ||
+ | "UI_FEEDBACK": 1 | ||
+ | }, | ||
+ | "ticketPriorities": { | ||
+ | "LOW": 1, | ||
+ | "MEDIUM": 2, | ||
+ | "HIGH": 1, | ||
+ | "CRITICAL": 1 | ||
+ | }, | ||
+ | "performanceScore": 88.56, | ||
+ | "seniority": "SENIOR" | ||
+ | }, | ||
+ | { | ||
+ | "username": "dev_two", | ||
+ | "closedTickets": 3, | ||
+ | "averageResolutionTime": 5.0, | ||
+ | "ticketTypes": { | ||
+ | "BUG": 2, | ||
+ | "FEATURE_REQUEST": 1 | ||
+ | }, | ||
+ | "ticketPriorities": { | ||
+ | "LOW": 1, | ||
+ | "MEDIUM": 1, | ||
+ | "HIGH": 1 | ||
+ | }, | ||
+ | "performanceScore": 75.00, | ||
+ | "seniority": "MID" | ||
+ | } | ||
+ | ] | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | |||
+ | |||
+ | ===== Ticket Risk ===== | ||
+ | |||
+ | **Disponibilă pentru:** **Manager** | ||
+ | |||
+ | |||
+ | **Descriere:** Generează un raport pe baza metricii **ticket risk**. | ||
+ | |||
+ | **Comanda: generateTicketRiskReport** | ||
+ | |||
+ | <note tip> | ||
+ | Raportul este creat pe baza **tuturor** ticketelor **OPEN** si **IN_PROGRESS** din sistem, indiferent de managerul care a generat raportul. | ||
+ | </note> | ||
+ | |||
+ | **Calculare:** | ||
+ | \\ | ||
+ | <spoiler BUG> | ||
+ | **Formula:** | ||
+ | **frequency × severityFactor** | ||
+ | |||
+ | **Valoare maximă:** 12 | ||
+ | |||
+ | **Exemplu de calcul:** | ||
+ | <code> | ||
+ | frequency = ALWAYS (4) | ||
+ | severityFactor = SEVERE (3) | ||
+ | |||
+ | Risc brut = 4 × 3 = 12 | ||
+ | Risc final = (12 × 100) / 12 = 100.00 | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | <spoiler FEATURE_REQUEST> | ||
+ | **Formula:** | ||
+ | **businessValue + customerDemand** | ||
+ | |||
+ | **Valoare maximă:** 20 | ||
+ | |||
+ | **Exemplu de calcul:** | ||
+ | <code> | ||
+ | businessValue = XL (10) | ||
+ | customerDemand = HIGH (6) | ||
+ | |||
+ | Risc brut = 10 + 6 = 16 | ||
+ | Risc final = (16 × 100) / 20 = 80.00 | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | <spoiler UI_FEEDBACK> | ||
+ | **Formula:** | ||
+ | **(11 − usabilityScore) × businessValue** | ||
+ | |||
+ | **Valoare maximă:** 100 | ||
+ | |||
+ | **Exemplu de calcul:** | ||
+ | <code> | ||
+ | usabilityScore = 2 | ||
+ | businessValue = XL (10) | ||
+ | |||
+ | Risc brut = (11 − 2) × 10 = 90 | ||
+ | Risc final = (90 × 100) / 100 = 90.00 | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | \\ | ||
+ | În urma raportului, fiecare categorie va avea un **calificativ**: | ||
+ | \\ | ||
+ | <spoiler Calificative risc> | ||
+ | \\ | ||
+ | ^ Interval Risc ^ Calificativ ^ | ||
+ | | 0 – 24 | **NEGLIJABIL** | | ||
+ | | 25 – 49 | **MEDIU** | | ||
+ | | 50 – 74 | **SEMNIFICATIV** | | ||
+ | | 75 – 100 | **MAJOR** | | ||
+ | </spoiler> | ||
+ | |||
+ | ===== ===== | ||
+ | \\ | ||
+ | **Exemplu Input:** <spoiler Exemplu input complet> <code json> | ||
+ | { | ||
+ | "command": "generateTicketRiskReport", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-30" | ||
+ | } </code> </spoiler> | ||
+ | |||
+ | \\ | ||
+ | **Exemplu Output:** <spoiler Exemplu output complet> <code json> | ||
+ | { | ||
+ | "command": "generateTicketRiskReport", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-30", | ||
+ | "report": { | ||
+ | "totalTickets": 20, | ||
+ | "ticketsByType": { | ||
+ | "BUG": 10, | ||
+ | "FEATURE_REQUEST": 6, | ||
+ | "UI_FEEDBACK": 4 | ||
+ | }, | ||
+ | "ticketsByPriority": { | ||
+ | "LOW": 5, | ||
+ | "MEDIUM": 7, | ||
+ | "HIGH": 6, | ||
+ | "CRITICAL": 2 | ||
+ | }, | ||
+ | "riskByType": { | ||
+ | "BUG": "NEGLIJABIL", | ||
+ | "FEATURE_REQUEST": "MEDIU", | ||
+ | "UI_FEEDBACK": "SEMNIFICATIV" | ||
+ | } | ||
+ | } | ||
+ | } </code> </spoiler> | ||
+ | \\ | ||
+ | ===== Resolution Efficiency ===== | ||
+ | |||
+ | **Disponibilă pentru: Manager** | ||
+ | |||
+ | **Descriere:** Evaluează cât de eficientă este echipa în a rezolva tickete. Se vor considera doar tickete în stările **RESOLVED** și **CLOSED**. | ||
+ | |||
+ | **Comanda:**: **generateResolutionEfficiencyReport** | ||
+ | |||
+ | <note tip> | ||
+ | Raportul este creat pe baza **tuturor ticketelor** **CLOSED** si **RESOLVED** din sistem, indiferent de managerul care a generat raportul. | ||
+ | </note> | ||
+ | |||
+ | <spoiler BUG> | ||
+ | **Formula:** | ||
+ | |||
+ | (bugFrequency + severityFactor) × 10 / daysToResolve | ||
+ | |||
+ | |||
+ | **Valoare maximă:** 70 | ||
+ | |||
+ | **Exemplu de calcul:** | ||
+ | <code> | ||
+ | frequency = FREQUENT (3) | ||
+ | severityFactor = MODERATE (2) | ||
+ | daysToResolve = 2 | ||
+ | |||
+ | Scor eficiență = (3 + 2) × 10 / 2 = 25 | ||
+ | Eficiență finală = (25 × 100) / 70 = 35.71 | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | |||
+ | <spoiler FEATURE_REQUEST> | ||
+ | **Formula:** | ||
+ | |||
+ | (businessValue + customerDemand) / daysToResolve | ||
+ | |||
+ | |||
+ | **Valoare maximă:** 20 | ||
+ | |||
+ | **Exemplu de calcul:** | ||
+ | <code> | ||
+ | businessValue = L (6) | ||
+ | customerDemand = HIGH (6) | ||
+ | daysToResolve = 2 | ||
+ | |||
+ | Scor eficiență = (6 + 6) / 2 = 6.00 | ||
+ | Eficiență finală = (6 × 100) / 20 = 30.00 | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | |||
+ | <spoiler UI_FEEDBACK> | ||
+ | **Formula:** | ||
+ | |||
+ | (usabilityScore + businessValue) / 2 | ||
+ | |||
+ | |||
+ | **Valoare maximă:** 20 | ||
+ | |||
+ | **Exemplu de calcul:** | ||
+ | <code> | ||
+ | usabilityScore = 9 | ||
+ | businessValue = XL (10) | ||
+ | |||
+ | Scor eficiență = (9 + 10) / 2 = 9.5 | ||
+ | Eficiență finală = (9.5 × 100) / 20 = 47.50 | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | <note warning> | ||
+ | **Atenție!** | ||
+ | **daysToResolve** = numărul de zile dintre **assignedAt** și data la care ticket-ul a fost marcat ultima dată ca **RESOLVED** sau **CLOSED**. | ||
+ | </note> | ||
+ | |||
+ | ===== ===== | ||
+ | **Exemplu Input:** | ||
+ | <spoiler Exemplu input complet> | ||
+ | <code json> | ||
+ | { | ||
+ | "command": "generateResolutionEfficiencyReport", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-30" | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | |||
+ | **Exemplu Output:** | ||
+ | <spoiler Exemplu output complet> | ||
+ | <code json> | ||
+ | { | ||
+ | "command": "generateResolutionEfficiencyReport", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-30", | ||
+ | "report": { | ||
+ | "totalTickets": 20, | ||
+ | "ticketsByType": { | ||
+ | "BUG": 10, | ||
+ | "FEATURE_REQUEST": 6, | ||
+ | "UI_FEEDBACK": 4 | ||
+ | }, | ||
+ | "ticketsByPriority": { | ||
+ | "LOW": 5, | ||
+ | "MEDIUM": 7, | ||
+ | "HIGH": 6, | ||
+ | "CRITICAL": 2 | ||
+ | }, | ||
+ | "efficiencyByType": { | ||
+ | "BUG": 65.50, | ||
+ | "FEATURE_REQUEST": 55.30, | ||
+ | "UI_FEEDBACK": 40.25 | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | ===== Customer Impact ===== | ||
+ | |||
+ | **Disponibilă pentru: Manager** | ||
+ | |||
+ | **Descriere:** Estimează **impactul asupra clienților** al ticketelor. | ||
+ | |||
+ | **Comanda:** **generateCustomerImpactReport** | ||
+ | |||
+ | <note tip> | ||
+ | Raportul este creat pe baza **tuturor ticketelor** aflate în stările **OPEN** și **IN_PROGRESS**, indiferent de managerul care a generat raportul. | ||
+ | </note> | ||
+ | |||
+ | |||
+ | <spoiler BUG> | ||
+ | **Formula:** | ||
+ | |||
+ | frequency × businessPriority × severityFactor | ||
+ | |||
+ | **Valoare maximă:** 48 | ||
+ | |||
+ | **Exemplu de calcul:** | ||
+ | <code> | ||
+ | frequency = ALWAYS (4) | ||
+ | businessPriority = CRITICAL (4) | ||
+ | severityFactor = SEVERE (3) | ||
+ | |||
+ | Impact brut = 4 × 4 × 3 = 48 | ||
+ | Impact final = (48 × 100) / 48 = 100.00 | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | |||
+ | <spoiler FEATURE_REQUEST> | ||
+ | **Formula:** | ||
+ | |||
+ | businessValue × customerDemand | ||
+ | |||
+ | **Valoare maximă:** 100 | ||
+ | |||
+ | **Exemplu de calcul:** | ||
+ | <code> | ||
+ | businessValue = M (3) | ||
+ | customerDemand = HIGH (6) | ||
+ | |||
+ | Impact brut = 3 × 6 = 18 | ||
+ | Impact final = (18 × 100) / 100 = 18.00 | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | |||
+ | |||
+ | <spoiler UI_FEEDBACK> | ||
+ | **Formula:** | ||
+ | |||
+ | businessValue × usabilityScore | ||
+ | |||
+ | **Valoare maximă:** 100 | ||
+ | |||
+ | **Exemplu de calcul:** | ||
+ | <code> | ||
+ | businessValue = L (6) | ||
+ | usabilityScore = 9 | ||
+ | |||
+ | Impact brut = 6 × 9 = 54 | ||
+ | Impact final = (54 × 100) / 100 = 54.00 | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | |||
+ | ===== ===== | ||
+ | **Exemplu Input:** | ||
+ | <spoiler Exemplu input complet> | ||
+ | <code json> | ||
+ | { | ||
+ | "command": "generateCustomerImpactReport", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-30" | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | \\ | ||
+ | |||
+ | **Exemplu Output:** | ||
+ | <spoiler Exemplu output complet> | ||
+ | <code json> | ||
+ | { | ||
+ | "command": "generateCustomerImpactReport", | ||
+ | "username": "gabriel_manager", | ||
+ | "timestamp": "2025-09-30", | ||
+ | "report": { | ||
+ | "totalTickets": 20, | ||
+ | "ticketsByType": { | ||
+ | "BUG": 10, | ||
+ | "FEATURE_REQUEST": 6, | ||
+ | "UI_FEEDBACK": 4 | ||
+ | }, | ||
+ | "ticketsByPriority": { | ||
+ | "LOW": 5, | ||
+ | "MEDIUM": 7, | ||
+ | "HIGH": 6, | ||
+ | "CRITICAL": 2 | ||
+ | }, | ||
+ | "customerImpactByType": { | ||
+ | "BUG": 75.55, | ||
+ | "FEATURE_REQUEST": 60.05, | ||
+ | "UI_FEEDBACK": 45.02 | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | </spoiler> | ||
+ | \\ | ||