📘 JavaStackEdu

Ghid Didactic Complet: De la Junior la Mid-Level

Acest dashboard interactiv este conceput pentru a te pregăti pentru interviurile tehnice și pentru provocările reale din producție. Vom explora arhitectura REST, ecosistemul Spring Boot, optimizarea bazelor de date și integrarea cu React.

📦 Spring Boot 3+ ⚛️ React 18+ 🐘 PostgreSQL 🐳 Docker
Modulul 1

Arhitectură Software & Design

Fluxul Datelor (Request Flow)

Client React
Browser / Axios
JSON Request
Controller
API Layer
Validare DTO
Service
Business Logic
@Transactional
Repository
Data Access
Hibernate / JPA
PostgreSQL
Database
Persistență
Modulul 2

Spring Boot Core & Clean Code

Analiză detaliată a codului. Comentariile explică conceptele de "Inversion of Control", "Dependency Injection" și "Transaction Management".

// 1. @RestController: Spune framework-ului că acest bean gestionează cereri HTTP
//    și că răspunsul metodelor va fi automat serializat în JSON (via Jackson).
@RestController
// 2. @RequestMapping: Prefixul comun pentru toate endpoint-urile din clasă.
@RequestMapping("/api/orders")
public class OrderController {
    
    // Folosim 'final' pentru a garanta imutabilitatea referinței după construcție.
    private final OrderService service;

    // 3. Constructor Injection: Modul preferat de Dependency Injection.
    //    Beneficii: Testabilitate ușoară (poți da un mock în teste unitare),
    //    asigură că bean-ul nu este creat într-o stare invalidă (fără dependențe).
    public OrderController(OrderService service) { 
        this.service = service; 
    }

    // 4. ResponseEntity<?>: Wrapper HTTP complet (Status, Headers, Body).
    @PostMapping
    public ResponseEntity<OrderResponse> create(
            // 5. @Valid: Declanșează validarea Bean Validation (Hibernate Validator)
            //    înainte ca metoda să fie executată. Dacă DTO-ul e invalid, 
            //    Spring aruncă automat MethodArgumentNotValidException -> 400 Bad Request.
            @Valid @RequestBody OrderRequest req) {
        
        OrderResponse response = service.placeOrder(req);
        // Returnăm 200 OK (sau 201 Created) explicit.
        return ResponseEntity.ok(response);
    }
}

2 Concepte Fundamentale: HTTP & Spring Boot

Înțelegerea protocolului HTTP și a containerului IoC (Inversion of Control) din Spring este obligatorie. Mai jos sunt comparații interactive esențiale.

HTTP: PUT vs PATCH

Selectează o metodă pentru a vedea cum afectează resursa de mai jos.

Resursă Originală (ID: 1):
{ "nume": "Ion", "varsta": 25, "oras": "Cluj" }
Apasă un buton...

Spring: @Component (Component Scanning)

🧩
Ce face @Component?

@Component se pune pe clasele tale și permite Spring să le descopere automat prin Component Scanning.

🔍
Specializări

@Service, @Repository, @Controller sunt specializări semantice ale @Component (doar semantică + funcționalitate suplimentară).

@Service
public class UserService {
    private final UserRepository repo;

    public UserService(UserRepository repo) {
        this.repo = repo;
    }
}
                
🎯
Când îl folosești?

Când ai cod propriu și instanțiere simplă, fără logică specială de configurare.

Spring: @Bean (Configurare explicită)

⚙️
Ce face @Bean?

@Bean se pune pe metode într-o clasă @Configuration și oferă control total asupra instanțierii.

📦
Caz frecvent

Folosit des pentru librării externe (unde nu poți adăuga @Component) sau pentru obiecte cu configurare complexă.

@Bean
public ObjectMapper objectMapper() {
    return new ObjectMapper();
}
                
🧠
Nuanță importantă

@Bean poate fi folosit și pentru clasele tale, dacă ai nevoie de logică specială la creare.

@Bean
public UserService userService(UserRepository repo) {
    return new UserService(repo);
}
                
🎯
Regula de aur

Diferența nu este dacă obiectul e intern sau extern, ci cine controlează instanțierea.

Spring: De ce @Service și @Repository sunt Bean-uri?

🧩
Component Scanning

@Service și @Repository sunt specializări ale @Component. Spring le detectează automat și le înregistrează în context.

@Service
public class UserService {}

@Repository
public class UserRepository {}
                
Confuzie frecventă

Bean-urile NU sunt doar obiecte din librării externe. Clasele tale sunt Bean-uri pentru că Spring le gestionează, nu pentru că ar fi externe.

🚫
Ce NU este un Bean

Un obiect creat manual cu new sau o clasă fără adnotări Spring NU este un Bean.

public class UserDto {} // ❌ nu e Bean

UserService s = new UserService(); // ❌ nu e Bean
                
🎯
Răspuns de interviu

„Un Spring Bean este orice obiect gestionat de Spring Container. @Service și @Repository sunt Bean-uri prin Component Scanning, iar @Bean este doar o altă metodă de definire.”

Spring: Ce este un Bean (dincolo de adnotări)

🫘
Ce înseamnă „gestionat de Spring”?

Un Spring Bean nu este doar un obiect creat de Spring, ci un obiect asupra căruia Spring aplică injection, lifecycle, proxy-uri și cross-cutting concerns.

🔧
Ce face Spring cu un Bean?
  • rezolvă dependențe (Dependency Injection)
  • controlează ciclul de viață (init / destroy)
  • aplică proxy-uri (@Transactional, @Async)
  • respectă scope-ul (singleton, request etc.)
🧪
Exemplu concret

Doar pentru că această clasă este Bean, Spring poate injecta automat dependențe și gestiona tranzacții:

@Service
public class OrderService {

    private final OrderRepository repo;

    public OrderService(OrderRepository repo) {
        this.repo = repo;
    }

    @Transactional
    public void placeOrder() {
        repo.save(...);
    }
}
                
🚫
Ce se întâmplă dacă NU e Bean?

Un obiect creat cu new nu beneficiază de niciuna dintre facilitățile Spring (injectare, tranzacții, proxy-uri).

OrderService service = new OrderService(repo);
// ❌ @Transactional nu funcționează
                
🎯
Ideea-cheie

Bean-ul este unitatea de bază a Spring. Adnotările precum @Component sau @Bean sunt doar moduri diferite de a spune: „Spring, te rog gestionează acest obiect”.

Spring & Lombok: @AllArgsConstructor vs @RequiredArgsConstructor

⚠️
@AllArgsConstructor (problematic)

Generează constructor cu toate câmpurile. Dacă ai câmpuri care nu sunt Bean-uri Spring (ex: String), aplicația va eșua la runtime.

@AllArgsConstructor
@Service
public class UserService {
    private UserRepository repo;
    private String name; // ❌ nu e Bean
}
                
@RequiredArgsConstructor (recomandat)

Generează constructor doar pentru câmpurile final. Spring face automat constructor injection dacă există un singur constructor.

@Service
@RequiredArgsConstructor
public class UserService {

    private final UserRepository repo;

    @Value("${user.name}")
    private final String name;
}
                

Spring: @Autowired pe Field vs Constructor

🚫
@Autowired pe atribut (Field Injection)

Ușor de scris, dar nerecomandat. Ascunde dependențele, nu permite câmpuri final și este greu de testat.

@Service
public class UserService {

    @Autowired
    private UserRepository repo;
}
                
🏆
Constructor Injection (Best Practice)

Dependențele sunt clare, clasa este imutabilă și ușor de testat. @Autowired nu este necesar dacă există un singur constructor.

@Service
public class UserService {

    private final UserRepository repo;

    public UserService(UserRepository repo) {
        this.repo = repo;
    }
}
                

HTTP Status Codes Cheat Sheet

200 OK
Succes standard
201 Created
După POST
400 Bad Req
Validare eșuată
401 Unauth
Lipsește Token
403 Forbidden
Token valid, rol greșit
404 Not Found
Resursa nu există
500 Server Err
Bug în codul tău
503 Unavailable
Server overload
Modulul 3

Securitate: JWT & Stateless

Concepte Cheie

Securitatea într-un REST API modern se bazează pe principiul Stateless. Nu folosim `HttpSession` pe server.

  • JWT (JSON Web Token): "Biletul" de acces. Conține ID-ul userului și Rolurile, semnate criptografic.
  • BCrypt: Algoritm de hashing pentru parole. Include "Salt" automat pentru a preveni atacurile Rainbow Table.
  • CORS: Mecanism prin care backend-ul permite frontend-ului (de pe alt domeniu/port) să acceseze resursele.

Auth Flow

  1. Client trimite POST /login.
  2. Server verifică parola hash-uită.
  3. Server generează Token-ul (valabil 15 min).
  4. Client primește Token-ul și îl salvează (ex: localStorage).
  5. Client trimite headerul Authorization: Bearer xyz... la fiecare request.
Modulul 4

Data, Optimizare & Performanță

Scalability Curve: "The Knee"

Observație: Până la "Punctul de Saturație" (genunchiul curbei), throughput-ul crește liniar și latența e stabilă. După saturație, latența explodează exponențial (cozi de așteptare), iar throughput-ul se plafonează sau scade.

🐘

Database Indexing

B-Tree: Standard pentru egalitate/range.
Partial Index: WHERE active = true (Index mic și rapid).

SQL vs NoSQL

PostgreSQL (SQL) Relațional, ACID, Schema strictă. Ideal pentru date financiare, relații complexe (JOINs).
MongoDB / Firebase (NoSQL) Document-based, Schema flexibilă. Ideal pentru cataloage de produse, date nestructurate, rapid prototyping.

Caching (Redis)

@Cacheable: Cache-aside pattern. Dacă datele sunt în Redis, le returnează instant. Dacă nu, execută metoda și salvează în Redis.

Redis GET user:1 0.5ms ⚡
Postgres SELECT 15.0ms 🐢
Modulul 5

React, Modern Stack & DevOps Essentials

Concepte esențiale pentru frontend, DevOps și baze de date moderne, cu exemple de cod și întrebări tip interviu.

🧭

React Router (SPA)

Client-side routing: navigare fără reload. SPA (Single Page Application).

<Routes>
  <Route path="/home" element={<Home />} />
  <Route path="/admin" element={<Admin />} />
</Routes>
            

Tip interviu: explică nested routes, protected routes și lazy loading pentru performanță.

Întrebare: „Cum previi re-render inutil în React Router?” Răspuns: folosește React.memo, React.lazy și Suspense pentru componente mari.

🧩

Props vs State

  • Props: Imutabile, date primite de la componenta părinte.
  • State: Memoria internă a componentei, schimbarea declanșează re-render.
  • Exemplu:
    function Counter({ initial }) {
      const [count, setCount] = useState(initial);
      return <button onClick={() => setCount(count + 1)>{count}</button>;
    }
    
  • Întrebare interviu: „De ce props sunt read-only și când ai folosi lifting state up?” Răspuns: Pentru a sincroniza state între componente părinte și copil, eviti duplicarea datelor.

Hooks: useState & useEffect

  • useState: starea locală
    const [text, setText] = useState("");
    
  • useEffect: lifecycle în componente funcționale
    useEffect(() => {
      console.log("Component mounted");
      return () => console.log("Cleanup on unmount");
    }, []);
    
  • Interviu: „Ce se întâmplă dacă uiți array-ul de dependențe?” → loop infinit, memory leak
🔒

React + Axios + JWT

  • JWT Stateless Authentication → backend nu ține session
  • Axios Interceptors → injectare token automat
    axios.interceptors.request.use(config => {
      config.headers.Authorization = `Bearer ${token}`;
      return config;
    });
    
  • Întrebare interviu: „Cum securizezi refresh token-urile și accesul la API?” Răspuns: stochezi refresh token server-side, access token expiră rapid.
🐳

Docker & DevOps

  • Containerizare → izolarea aplicațiilor
    docker build -t my-app .
    docker run -p 8080:8080 my-app
    
  • docker-compose pentru backend + DB + Redis
    version: '3.8'
    services:
      backend:
        build: ./backend
        ports: - "8080:8080"
      postgres:
        image: postgres:15
        environment: POSTGRES_PASSWORD=secret
      redis:
        image: redis:7
    
  • Întrebare interviu: „Cum scalezi servicii multiple cu Docker?” Răspuns: folosești multiple replicas + load balancer sau Kubernetes.
🟢

PostgreSQL Essentials

  • ACID → Atomicitate, Consistență, Izolare, Durabilitate
  • JSONB → stocare rapidă și indexabilă
    SELECT data->>'name' FROM products WHERE data @> '{"category":"electronics"}';
    
  • Partial Index
    CREATE INDEX idx_active_products ON products(id)
    WHERE active = true;
    
  • Full Text Search → tsvector + GIN pentru căutări eficiente
  • Întrebare interviu: „De ce PostgreSQL vs MySQL?” Răspuns: extensii, JSONB, Partial Index, ACID garantat, tipuri complexe.
📊

PostgreSQL Indexing & Transactions

  • B-Tree → egalitate și sortare scalară
  • GIN → arrays, JSONB, full text search
  • BRIN → mari volume de date, range scan optimizat
  • Transactions → BEGIN / COMMIT / ROLLBACK
    BEGIN;
    UPDATE accounts SET balance = balance - 100 WHERE id = 1;
    UPDATE accounts SET balance = balance + 100 WHERE id = 2;
    COMMIT;
    
  • Întrebare interviu: „Cum eviți deadlocks în PostgreSQL?” Răspuns: tranzacții scurte, indexuri corecte, ordine constantă de UPDATE, folosirea EXPLAIN ANALYZE pentru optimizare.
Modulul 6

Structuri de Date (Deep Dive)

Analiză comparativă pentru interviurile tehnice.

Structură Implementare Internă Complexitate (Search/Add) Când să folosești?
ArrayList Array redimensionabil (crește cu 50% când e plin). Get: O(1) / Add: O(1)* Acces rapid prin index. Iterare frecventă. Ștergeri lente.
LinkedList Noduri dublu înlănțuite (pointeri prev/next). Get: O(n) / Add: O(1) Inserări/Ștergeri frecvente la capete (Queue/Deque).
HashMap Buckets Array. Coliziuni rezolvate prin LinkedList -> Red-Black Tree (Java 8+). Avg: O(1) / Worst: O(log n) Key-Value lookup. Nu păstrează ordinea.
TreeMap Red-Black Tree (Arbore binar echilibrat). All: O(log n) Chei sortate natural. Range queries.
HashSet Folosește un HashMap intern unde valoarea e o constantă. Avg: O(1) Elemente unice. Verificare rapidă de apartenență.
Modulul 7

Algoritmică & Interviu Coding

7 Tipuri de probleme esențiale. Soluțiile sunt în dropdown.

1. Reverse Polish Notation (RPN)

Stack • O(n)

Se dă o expresie aritmetică în Reverse Polish Notation, reprezentată ca un array de string-uri, cu numere întregi și operatorii +, -, *, /. Scopul este să evaluezi expresia și să returnezi rezultatul numeric. Exemplu: ["2", "1", "+", "3", "*"] corespunde expresiei infix (2 + 1) * 3 și rezultatul este 9. Evaluează expresia: `["2", "1", "+", "3", "*"]` -> `(2+1)*3` = 9.

Vezi Soluția
public int evalRPN(String[] tokens) {
    Stack<Integer> stack = new Stack<>();
    for (String t : tokens) {
        if ("+-*/".contains(t)) {
            int b = stack.pop(), a = stack.pop();
            switch (t) {
                case "+" -> stack.push(a + b);
                case "-" -> stack.push(a - b);
                // ...
            }
        } else stack.push(Integer.parseInt(t));
    }
    return stack.pop();
}

2. Longest Increasing Subsequence (LIS)

DP & Binary Search

Se dă un array de numere întregi. Trebuie să găsești lungimea celui mai lung subșir strict crescător. Elementele subșirului nu trebuie să fie consecutive în array, dar ordinea trebuie păstrată. Exemplu: [10, 9, 2, 5, 3, 7, 101, 18] → cel mai lung subșir crescător este [2, 3, 7, 101] și lungimea sa este 4.

Soluție 1: Dynamic Programming O(n²)
public int lengthOfLIS(int[] nums) {
    int[] dp = new int[nums.length];
    Arrays.fill(dp, 1);
    int max = 1;
    for(int i=1; i<nums.length; i++) {
        for(int j=0; j<i; j++) {
            if(nums[i] > nums[j]) dp[i] = Math.max(dp[i], dp[j]+1);
        }
        max = Math.max(max, dp[i]);
    }
    return max;
}
Soluție 2: Binary Search O(n log n)
public int lengthOfLIS(int[] nums) {
    int[] tails = new int[nums.length];
    int size = 0;
    for (int x : nums) {
        int i = 0, j = size;
        while (i != j) {
            int m = (i + j) / 2;
            if (tails[m] < x) i = m + 1;
            else j = m;
        }
        tails[i] = x;
        if (i == size) ++size;
    }
    return size;
}

3. Longest Substring Without Repeating Characters

Sliding Window • O(n)

Se dă un string. Trebuie să găsești lungimea maximă a unui substring care conține doar caractere unice. Exemplu: "abcabcbb" → cel mai lung substring fără caractere repetate este "abc" și lungimea sa este 3.

Vezi Soluția
public int lengthOfLongestSubstring(String s) {
    int max = 0, left = 0;
    Map<Character, Integer> map = new HashMap<>();
    
    for (int right = 0; right < s.length(); right++) {
        char c = s.charAt(right);
        if (map.containsKey(c)) {
            left = Math.max(left, map.get(c) + 1);
        }
        map.put(c, right);
        max = Math.max(max, right - left + 1);
    }
    return max;
}

4. Number of Islands

Grid DFS • O(m*n)

Se dă un grid 2D format din caractere '1' (pământ) și '0' (apă). Trebuie să numeri câte insule există în grid. O insulă este o grupare de celule cu '1' conectate orizontal sau vertical.Exemplu:

                    grid = [
                      ["1","1","0","0","0"],
                      ["1","1","0","0","0"],
                      ["0","0","1","0","0"],
                      ["0","0","0","1","1"]
                    ]
                    
Rezultat: 3 insule.

Vezi Soluția
public int numIslands(char[][] grid) {
    int count = 0;
    for (int i = 0; i < grid.length; i++) {
        for (int j = 0; j < grid[0].length; j++) {
            if (grid[i][j] == '1') {
                dfs(grid, i, j);
                count++;
            }
        }
    }
    return count;
}
private void dfs(char[][] grid, int i, int j) {
    if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] != '1') return;
    grid[i][j] = '0'; // Mark as visited
    dfs(grid, i+1, j); dfs(grid, i-1, j);
    dfs(grid, i, j+1); dfs(grid, i, j-1);
}

5. Merge Intervals

Sorting • O(n log n)

Se dă un array de intervale [start, end]. Trebuie să combini toate intervalele care se suprapun și să returnezi un array cu intervalele unite. Exemplu:

                    intervals = [[1,3],[2,6],[8,10],[15,18]]
                    Rezultat: [[1,6],[8,10],[15,18]]
                    
Explicație: Intervalele [1,3] și [2,6] se suprapun, deci se combină în [1,6].

Soluție
public int[][] merge(int[][] intervals) {
    Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));
    LinkedList<int[]> merged = new LinkedList<>();
    for (int[] interval : intervals) {
        if (merged.isEmpty() || merged.getLast()[1] < interval[0])
            merged.add(interval);
        else
            merged.getLast()[1] = Math.max(merged.getLast()[1], interval[1]);
    }
    return merged.toArray(new int[merged.size()][]);
}

6. Invert Binary Tree

Recursion • O(n)

Se dă un arbore binar. Trebuie să inversezi toate nodurile, astfel încât subarborele stâng să devină drept și subarborele drept să devină stâng la fiecare nod. Exemplu:

                    Input:       4
                               /   \
                              2     7
                             / \   / \
                            1   3 6   9

                    Output:      4
                               /   \
                              7     2
                             / \   / \
                            9   6 3   1
                    
Toate nodurile stânga/dreapta sunt inversate recursiv.

Soluție
public TreeNode invertTree(TreeNode root) {
    if (root == null) return null;
    TreeNode temp = root.left;
    root.left = invertTree(root.right);
    root.right = invertTree(temp);
    return root;
}

7. Top K Frequent Elements

Heap • O(n log k)

Se dă un array de numere și un număr k. Trebuie să găsești cele k elemente cu cea mai mare frecvență din array. Exemplu:

                    nums = [1,1,1,2,2,3], k = 2
                    Rezultat: [1,2]
                    
Explicație: 1 apare de 3 ori, 2 apare de 2 ori, iar 3 apare o singură dată. Cele mai frecvente 2 elemente sunt [1,2].

Soluție
public int[] topKFrequent(int[] nums, int k) {
    Map<Integer, Integer> count = new HashMap<>();
    for (int n : nums) count.put(n, count.getOrDefault(n, 0) + 1);
    
    PriorityQueue<Integer> heap = new PriorityQueue<>((a, b) -> count.get(a) - count.get(b));
    for (int n : count.keySet()) {
        heap.add(n);
        if (heap.size() > k) heap.poll();
    }
    return heap.stream().mapToInt(i -> i).toArray();
}
Modulul 8

Simulator Interviu (50+)

Modulul 9

Soft Skills & Cariera

Cum să treci de interviul HR și tehnic și să vinzi eficient skill-urile tale.

Cum prezinți Proiectul?

Nu spune doar "am făcut un magazin". Folosește structura clară: Problema – Soluția – Tehnologii – Arhitectură. Exemplu concret pentru un proiect Fullstack:

  • 1. Problema: "Am vrut să construiesc un magazin online scalabil, cu mii de produse și chat realtime între clienți și suport."
  • 2. Soluția: "Am dezvoltat o aplicație Cloud-Native cu arhitectură modulară monolitică, separând clar frontend, backend și caching."
  • 3. Tehnologii: "Backend Spring Boot cu JWT Stateless Security, PostgreSQL pe Neon, Redis pe Upstash, React pe Netlify, Firestore pentru chat realtime, Docker pentru containere, Swagger pentru documentație API."
  • 4. Arhitectură: "Am aplicat Clean Code, principii SOLID, N-Tier Architecture. Modul monolitic modular pentru scalabilitate, testabilitate și mentenanță ușoară."
  • 5. Rezultate / Impact: "Cache-ul Redis a redus timpul de răspuns cu 30%, Partial Index în PostgreSQL a accelerat interogările cu 40%, chat-ul Firestore a permis interacțiune realtime fără blocaje."

Acest exemplu arată clar impactul tehnic și valoarea adusă. Este un punct esențial pentru interviu.

Structura CV-ului Tehnic și Branding Personal

  • Adaptează CV-ul tău în funcție de poziția și firma pentru care aplici. E.g. Dacă aplici pentru o poziție de Java cu React prioritizează proiectele și skillurile relevante. Nu-ți începe CV în acest caz cu un proiect de Arduino, Embedded sau Grafică. Primul proiect din CV trebuie să fie cel mai relevant, urmat de celelalte în ordine descrescătoare.
  • Header: Nume complet, poza profesională, GitHub, LinkedIn, email profesional (ex: prenume.nume@email.com).
  • Skills: Grupează: Languages (Java, JavaScript), Frameworks (Spring, React), Tools (Docker, Git, AWS/Cloud), Databases (Postgres, Firestore, Redis).
  • Proiecte (CRUCIAL):
    "E-Shop Full Stack | Java, Spring, React, PostgreSQL, Redis, Firestore, Docker, Netlify, JWT Security"
    - JWT Stateless Authentication & Role-Based Access Control.
    - Optimizări SQL cu Partial Index (viteză +40%).
    - Redis Cache pentru reducerea load-ului pe DB.
    - Firestore pentru chat realtime între utilizatori.
    - Swagger pentru documentația API.
    - Deploy complet pe Render & Netlify.
  • Educație / Certificări: Include relevante (Java, Spring, Cloud, Docker).
  • Tehnici de vânzare personală:
    • La HR: arată cum soft skills și teamwork contribuie la echipă.
    • La tech: explică cum skill-urile tale aduc valoare concretă în firmă.
    • Exemplu întrebare pentru branding personal: "Cum ați vedea că experiența mea fullstack poate accelera livrarea proiectelor în echipa voastră?"
  • Social & Contact: LinkedIn cu profil complet, GitHub activ, email profesionist. Evită nickname-uri sau cuvinte amuzante (ex: spiderman123).

Întrebări frecvente HR

  • Spune-ne despre tine: Prezintă proiectul Fullstack, focus pe impact și tehnologii.
  • De ce vrei să lucrezi aici? Leagă-ți skill-urile de specificul companiei și de proiectele lor, ideal de o pasiune pe care o ai în zona domeniului lor de activitate.
  • Cum te descurci cu deadline-uri strânse? Exemplu concret din proiectul magazinului online (deploy rapid, testing automat).
  • Alocă timp înainte de fiecare interviu pentru a studia firma la care aplici și domeniul ei de activitate.

Întrebări frecvente tehnice

  • Explică arhitectura modul monolith + N-Tier și avantajele sale.
  • Cum ai folosit Redis și PostgreSQL împreună pentru performanță?
  • JWT vs session-based authentication, de ce ai ales Stateless în Spring Boot?
  • Descrie modul de deploy: Netlify pentru frontend, Render pentru backend.
  • Explică integrarea Firestore realtime chat și cum ai gestionat securitatea datelor.