# FELADAT: CORS + Manuális DI Container + Email Notification

## 🎯 Cél

Fejlett backend fejlesztési technikák elsajátítása Node.js-ben **Clean Architecture** és **CQRS** mintával:
- **CORS biztonságos konfiguráció** whitelist alapú origin ellenőrzéssel
- **Saját Dependency Injection (DI) container** különböző lifecycle-okkal (singleton, transient, scoped)
- **Email küldés** Nodemailer + Handlebars template alapú értesítésekkel

**Amit már kész kaptál:**
- ✅ **Clean Architecture** struktúra (api, application, domain, infrastructure)
- ✅ **CQRS Pattern** (Commands/Handlers, Queries/Handlers)
- ✅ **Prisma ORM** PostgreSQL adatbáziskezeléssel
- ✅ **Cookie-based JWT autentikáció** (regisztráció, login, logout, védett endpointok)
- ✅ **bcrypt** jelszó hashelés
- ✅ **Repository Pattern** (Domain interfaces + Infrastructure implementations)
- ✅ **JwtService** (cookie-based token management)
- ✅ **Jest** testing framework

---

## 📐 Architektúra

Ez a projekt **Clean Architecture** mintát követi **CQRS** (Command Query Responsibility Segregation) pattern-nel:

### 🏛️ Layer Struktúra

```
src/
├── api/                          # Presentation Layer
│   ├── controllers/              # HTTP request handlers
│   ├── middlewares/              # Express middlewares (auth, cors, scope)
│   ├── routers/                  # Route definitions
│   └── server.js                 # Express app setup + DI configuration
│
├── application/                  # Application Layer
│   ├── auth/commands/            # Authentication commands & handlers
│   ├── user/                     # User commands & queries
│   │   ├── commands/             # Write operations
│   │   └── queries/              # Read operations
│   ├── services/                 # Application services
│   │   ├── JwtService.js         ✅ KÉSZ (Cookie-based JWT)
│   │   └── EmailService.js       ❌ TODO (FELADAT 3)
│   └── Container.js              ❌ TODO (FELADAT 1)
│
├── domain/                       # Domain Layer
│   ├── models/                   # Business entities
│   │   └── User.js               ✅ KÉSZ (Domain model)
│   └── irepositories/            # Repository interfaces
│       └── IUserRepository.js    ✅ KÉSZ
│
└── infrastructure/               # Infrastructure Layer
    ├── db/                       # Database connection
    │   └── DatabaseConnection.js ✅ KÉSZ (Prisma wrapper)
    └── repositories/             # Repository implementations
        └── UserRepository.js     ✅ KÉSZ (Prisma-based)
```

**Key Concepts:**
- **Domain**: Üzleti entitások és szabályok (User model, IUserRepository interface)
- **Application**: Business logic (Commands, Queries, Services, DI Container)
- **Infrastructure**: Külső rendszerekhez kapcsolódás (Prisma, Database)
- **API**: HTTP layer (controllers, routes, middlewares)

---

## 🚀 Projekt Indítása

### 1. Függőségek telepítése
```bash
npm install
```

### 2. Környezeti változók konfigurálása
Másold le a `.env.example` fájlt `.env` néven:
```bash
cp .env.example .env
```

Állítsd be az `.env` fájlban:
```env
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/cors_di_app?schema=public"
JWT_SECRET="titkos-kulcs-jwt-hez-változtasd-meg"
JWT_EXPIRES_IN="7d"
PORT=3000
NODE_ENV=development

# Ethereal Email (test SMTP)
ETHEREAL_USER=your-ethereal-user@ethereal.email
ETHEREAL_PASS=your-ethereal-password

# CORS (comma-separated origins)
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:5173
```

### 3. Docker indítása (PostgreSQL)
```bash
npm run docker:up
```

### 4. Prisma migrációk futtatása
```bash
npm run prisma:migrate
npm run prisma:generate
```

### 5. Szerver indítása
```bash
npm run dev
```

A szerver elindul: `http://localhost:3000`

---

## 🔐 Kész API Endpoints (Teszteléshez)

### ⚠️ FONTOS: Cookie-Based Authentication

Ez a projekt **cookie-based JWT autentikációt** használ (nem localStorage!):
- JWT token **httpOnly cookie-ban** tárolódik
- Authorization header **nem szükséges**
- Böngésző **automatikusan** küldi a cookie-t

### Publikus endpointok (JWT nem kell)

#### 1. Regisztráció (Cookie-t ad vissza)
```bash
POST http://localhost:3000/api/auth/register
Content-Type: application/json

{
  "name": "John Doe",
  "email": "john@example.com",
  "password": "securePassword123"
}
```

**Válasz:**
```http
HTTP/1.1 201 Created
Set-Cookie: auth_token=<JWT>; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=604800

{
  "message": "User registered successfully",
  "data": {
    "user": {
      "id": 1,
      "name": "John Doe",
      "email": "john@example.com",
      "createdAt": "2026-03-04T10:00:00.000Z",
      "updatedAt": "2026-03-04T10:00:00.000Z"
    }
  }
}
```

**Figyelem:** Token **nincs** a response body-ban, csak cookie-ban!

#### 2. Bejelentkezés (Cookie-t ad vissza)
```bash
POST http://localhost:3000/api/auth/login
Content-Type: application/json

{
  "email": "john@example.com",
  "password": "securePassword123"
}
```

**Válasz:**
```http
HTTP/1.1 200 OK
Set-Cookie: auth_token=<JWT>; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=604800

{
  "message": "Login successful",
  "data": {
    "user": {
      "id": 1,
      "name": "John Doe",
      "email": "john@example.com"
    }
  }
}
```

#### 3. Kijelentkezés (Cookie törlése)
```bash
POST http://localhost:3000/api/auth/logout
Cookie: auth_token=<JWT>
```

**Válasz:**
```http
HTTP/1.1 200 OK
Set-Cookie: auth_token=; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=0

{
  "message": "Logout successful"
}
```

### Védett endpointok (JWT cookie szükséges!)

A böngésző **automatikusan** küldi a cookie-t. cURL-nél használd a `-b` és `-c` flageket.

#### 4. Aktuális felhasználó lekérdezése
```bash
# cURL
curl -b cookies.txt http://localhost:3000/api/users/me

# JavaScript (fetch)
fetch('http://localhost:3000/api/users/me', {
  credentials: 'include' // Cookie automatikusan küldődik
})
```

#### 5. Aktuális felhasználó frissítése
```bash
PUT http://localhost:3000/api/users/me
Cookie: auth_token=<JWT>
Content-Type: application/json

{
  "name": "John Updated"
}
```

#### 6. Összes felhasználó lekérdezése
```bash
GET http://localhost:3000/api/users
Cookie: auth_token=<JWT>
```

#### 7. Egy felhasználó lekérdezése ID alapján
```bash
GET http://localhost:3000/api/users/2
Cookie: auth_token=<JWT>
```

---

## 📋 MIT KELL IMPLEMENTÁLNI - 3 FELADAT

### ⚙️ FELADAT 1: DI Container (src/application/Container.js)
### ⚙️ FELADAT 1: DI Container (src/application/Container.js)

**Cél:** Dependency Injection konténer implementálása különböző lifecycle-okkal

**⚠️ FONTOS:** A Container.js fájl **src/application/** mappában van (nem core-ban)!

A Container három lifecycle típust támogat:
- **Singleton**: Egyszer jön létre, osztva van minden request között
- **Transient**: Minden resolve()-nál új példány jön létre
- **Scoped**: Request szinten megosztott a példány (req.scope-on keresztül)

**Implementálandó metódusok:**

```javascript
/**
 * Dependency Injection Container
 * src/application/Container.js
 */
class Container {
  constructor() {
    // TODO 1: Inicializáld a services Map-et (singleton instance-ok tárolása)
    // TODO 2: Inicializáld a factories Map-et (factory függvények tárolása)
    // TODO 3: Inicializáld a lifetimes Map-et (lifecycle típusok tárolása)
    
    // Példa inicializálás:
    // this.services = new Map();
    // this.factories = new Map();
    // this.lifetimes = new Map();
  }

  register(name, factory, lifetime = 'singleton') {
    // TODO 4: Tárold el a factory függvényt (this.factories.set(name, factory))
    // TODO 5: Tárold el a lifetime típust (this.lifetimes.set(name, lifetime))
    // TODO 6: Ha a lifetime === 'singleton', azonnal példányosítsd:
    //         - Hívd meg a factory-t: const instance = factory();
    //         - Tárold el: this.services.set(name, instance);
  }

  resolve(name, scope = null) {
    // TODO 7: Ha a service regisztrálva van mint 'scoped' ÉS van scope paraméter:
    //         - Ellenőrizd: if (scope && scope.has(name)) return scope.get(name);
    //         - Ha nincs még a scope-ban, példányosítsd és tárold: 
    //           const instance = this.factories.get(name)();
    //           scope.set(name, instance);
    //           return instance;
    
    // TODO 8: Ha singleton, add vissza a services-ből:
    //         if (this.lifetimes.get(name) === 'singleton') {
    //           return this.services.get(name);
    //         }
    
    // TODO 9: Ha transient, minden alkalommal hívj egy új factory-t:
    //         if (this.lifetimes.get(name) === 'transient') {
    //           return this.factories.get(name)();
    //         }
    
    // TODO 10: Ha nem regisztrált a service, dobj hibát:
    //          throw new Error(`Service '${name}' is not registered`);
  }

  createScope() {
    // TODO 11: Hozz létre egy új Map-et az scoped instance-oknak
    // TODO 12: Térj vissza egy objektummal ami tartalmaz egy resolve metódust:
    //          const scopeMap = new Map();
    //          return {
    //            resolve: (name) => this.resolve(name, scopeMap)
    //          };
  }
}

module.exports = Container;
```

**Tesztelés:**
A `src/api/server.js` már használja a Container-t:

```javascript
const container = new Container();

// Singleton regisztráció
container.register('PrismaClient', () => {
  return databaseConnection.getClient();
}, 'singleton');

// Használat
const prisma = container.resolve('PrismaClient');
```

Indítsd el a szervert és nézd meg, hogy működik-e a DI:
```bash
npm run dev
# ✅ DI Container configured (CQRS pattern)
```

**Részletes segítség:** Nézd meg a `SEGÍTSÉG.md` fájlt teljes megoldással!

---

### 🌐 FELADAT 2: CORS Middleware (src/api/middlewares/corsMiddleware.js)

**Cél:** Whitelist alapú CORS konfiguráció implementálása

A CORS middleware csak bizonyos origin-ekről engedélyezi a hozzáférést.

```javascript
const cors = require('cors');

// Engedélyezett origin-ek whitelist-je (környezeti változóból vagy default)
const allowedOrigins = process.env.ALLOWED_ORIGINS?.split(',') || [
  'http://localhost:3000',
  'http://localhost:5173'
];

const corsOptions = {
  origin: function (origin, callback) {
    // TODO 1: Ha nincs origin (pl. backend-to-backend, Postman, curl):
    //         if (!origin) {
    //           return callback(null, true);
    //         }
    
    // TODO 2: Ha az origin benne van az allowedOrigins listában:
    //         if (allowedOrigins.includes(origin)) {
    //           return callback(null, true);
    //         }
    
    // TODO 3: Egyébként tiltsd le CORS hibával:
    //         callback(new Error('Not allowed by CORS'));
  },
  credentials: true, // Cookie és Authorization header engedélyezése
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
  allowedHeaders: ['Content-Type', 'Authorization']
};

module.exports = cors(corsOptions);
```

**.env beállítás:**
```env
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:5173,https://myfrontend.com
```

**Aktiválás a server.js-ben:**

Uncomment this line in `src/api/server.js`:
```javascript
// A middleware chain-ben (körülbelül 130. sor)
app.use(cookieParser());
app.use(corsMiddleware);  // <-- UNCOMMENT THIS LINE!
```

**Tesztelés cURL-lel:**
```bash
# Engedélyezett origin - SIKERES
curl -H "Origin: http://localhost:3000" http://localhost:3000/api/users
# Access-Control-Allow-Origin: http://localhost:3000

# Tiltott origin - HIBA
curl -H "Origin: http://malicious-site.com" http://localhost:3000/api/users
# Error: Not allowed by CORS
```

**Frontend tesztelés (React/Vue):**
```javascript
fetch('http://localhost:3000/api/auth/login', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  credentials: 'include', // FONTOS: Cookie küldés/fogadás engedélyezése
  body: JSON.stringify({ email, password })
})
.then(res => res.json())
.then(data => console.log('Login sikeres:', data))
.catch(err => console.error('CORS hiba:', err));
```

**Részletes segítség:** Nézd meg a `SEGÍTSÉG.md` fájlt teljes megoldással!

---

### 📧 FELADAT 3: Email Service (src/application/services/EmailService.js)

**Cél:** Nodemailer + Handlebars template alapú email küldés implementálása

Az EmailService welcome emailt küld regisztráció után.

**⚠️ FONTOS:** Az EmailService **src/application/services/** mappában van!

```javascript
const nodemailer = require('nodemailer');
const handlebars = require('handlebars');
const fs = require('fs');
const path = require('path');

class EmailService {
  constructor() {
    // TODO 1: Hozz létre Nodemailer transportot Ethereal tesztelő SMTP-vel
    //         this.transporter = nodemailer.createTransport({
    //           host: 'smtp.ethereal.email',
    //           port: 587,
    //           secure: false, // TLS
    //           auth: {
    //             user: process.env.ETHEREAL_USER || 'your-test-email@ethereal.email',
    //             pass: process.env.ETHEREAL_PASS || 'your-test-password'
    //           }
    //         });
    
    console.log('📧 EmailService initialized');
  }

  async sendWelcomeEmail(userEmail, userName) {
    try {
      // TODO 2: Olvasd be a welcome.hbs template fájlt
      //         const templatePath = path.join(__dirname, 'templates', 'welcome.hbs');
      //         const templateSource = fs.readFileSync(templatePath, 'utf-8');
      
      // TODO 3: Compile-old a template-et Handlebars-szal
      //         const template = handlebars.compile(templateSource);
      
      // TODO 4: Generáld a HTML-t a felhasználói adatokkal
      //         const html = template({ 
      //           name: userName,
      //           date: new Date().toLocaleDateString('hu-HU')
      //         });
      
      // TODO 5: Küld el az emailt
      //         const info = await this.transporter.sendMail({
      //           from: '"Clean Architecture App" <noreply@cleanarch.com>',
      //           to: userEmail,
      //           subject: 'Üdvözlünk az alkalmazásban!',
      //           html: html
      //         });
      
      // TODO 6: Logold ki az Ethereal preview URL-t
      //         const previewUrl = nodemailer.getTestMessageUrl(info);
      //         console.log('📧 Email elküldve:', previewUrl);
      
      return true;
    } catch (error) {
      console.error('❌ Email küldési hiba:', error.message);
      return false;
    }
  }
}

module.exports = EmailService;
```

**Email Template létrehozása:**

Hozd létre: `src/application/services/templates/welcome.hbs`

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <style>
    body { font-family: Arial, sans-serif; background-color: #f4f4f4; padding: 20px; }
    .container { background: white; padding: 30px; border-radius: 10px; max-width: 600px; margin: 0 auto; }
    h1 { color: #333; }
    .footer { margin-top: 30px; font-size: 12px; color: #999; }
  </style>
</head>
<body>
  <div class="container">
    <h1>🎉 Üdvözlünk, {{name}}!</h1>
    <p>Sikeres regisztráció az alkalmazásunkban!</p>
    <p>Regisztráció dátuma: <strong>{{date}}</strong></p>
    <p>Mostantól hozzáférsz az összes funkciónkhoz.</p>
    <div class="footer">
      <p>Ez egy automatikus üzenet, kérjük ne válaszolj rá.</p>
    </div>
  </div>
</body>
</html>
```

**.env konfigurálás Ethereal SMTP-vel:**

1. Menj a https://ethereal.email oldalra
2. Kattints a "Create Ethereal Account" gombra
3. Másold ki a kapott user és password értékeket
4. Állítsd be a `.env` fájlban:

```env
ETHEREAL_USER=your-generated-user@ethereal.email
ETHEREAL_PASS=your-generated-password
```

**Tesztelés:**

Regisztrálj egy új felhasználót:
```bash
curl -X POST http://localhost:3000/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Test User",
    "email": "test@example.com",
    "password": "password123"
  }'
```

**Console output:**
```
📧 Email elküldve: https://ethereal.email/message/XXXXXX
```

Nyisd meg a böngészőben a linket és látni fogod az elküldött emailt!

**Részletes segítség:** Nézd meg a `SEGÍTSÉG.md` fájlt teljes megoldással és példákkal!

---

## 📁 Projekt Struktúra (Frissített)

```
src/
├── api/                          # Presentation Layer
│   ├── controllers/
│   │   ├── AuthController.js     ✅ KÉSZ (Cookie-based JWT)
│   │   └── UserController.js     ✅ KÉSZ (CQRS queries/commands)
│   ├── middlewares/
│   │   ├── authMiddleware.js     ✅ KÉSZ (Cookie-based auth)
│   │   ├── corsMiddleware.js     ❌ TODO (FELADAT 2)
│   │   └── scopeMiddleware.js    📚 Opcionális
│   ├── routers/
│   │   ├── authRoutes.js         ✅ KÉSZ (register, login, logout)
│   │   └── userRoutes.js         ✅ KÉSZ (protected endpoints)
│   └── server.js                 ✅ KÉSZ (Express + DI setup)
│
├── application/                  # Application Layer
│   ├── auth/commands/            ✅ KÉSZ (CQRS)
│   │   ├── RegisterUserCommand.js
│   │   ├── RegisterUserCommandHandler.js
│   │   ├── LoginUserCommand.js
│   │   └── LoginUserCommandHandler.js
│   ├── user/                     ✅ KÉSZ (CQRS)
│   │   ├── commands/             # Write operations
│   │   └── queries/              # Read operations
│   ├── services/
│   │   ├── JwtService.js         ✅ KÉSZ (Cookie-based JWT)
│   │   ├── EmailService.js       ❌ TODO (FELADAT 3)
│   │   └── templates/
│   │       └── welcome.hbs       ❌ TODO (Email template)
│   └── Container.js              ❌ TODO (FELADAT 1)
│
├── domain/                       # Domain Layer
│   ├── models/
│   │   └── User.js               ✅ KÉSZ (Domain entity)
│   └── irepositories/
│       └── IUserRepository.js    ✅ KÉSZ (Repository interface)
│
├── infrastructure/               # Infrastructure Layer
│   ├── db/
│   │   └── DatabaseConnection.js ✅ KÉSZ (Prisma wrapper)
│   └── repositories/
│       └── UserRepository.js     ✅ KÉSZ (Prisma implementation)
│
├── prisma/
│   ├── schema.prisma             ✅ KÉSZ (User model)
│   └── migrations/               ✅ KÉSZ
│
└── tests/                        # Testing
    └── unit/
        ├── commands/             ✅ KÉSZ (Command handler tests)
        ├── queries/              ✅ KÉSZ (Query handler tests)
        ├── controllers/          ✅ KÉSZ (Controller tests)
        ├── middlewares/          ✅ KÉSZ (Middleware tests)
        └── services/             ✅ KÉSZ (JwtService tests)
```

---

## 🎯 Tanulási Célok

### CORS (Cross-Origin Resource Sharing)
- ✅ Origin alapú hozzáférés-vezérlés implementálása
- ✅ Whitelist konfiguráció production környezetben
- ✅ Preflight request-ek kezelése (OPTIONS)
- ✅ Credential (cookie, auth header) kezelés

### DI Container (Dependency Injection)
- ✅ Lifecycle management (Singleton, Transient, Scoped)
- ✅ Loose coupling az alkalmazásban
- ✅ Tesztelhetőség javítása (dependency injection)
- ✅ Service registry pattern

### Email Notification
- ✅ SMTP konfiguráció (Ethereal Email)
- ✅ Template-alapú email generálás (Handlebars)
- ✅ Async email küldés (nem blokkolja a request-et)
- ✅ Test email preview Ethereal-lel

### Clean Architecture + CQRS
- ✅ Layer separation (Domain, Application, Infrastructure, API)
- ✅ CQRS Pattern (Commands for writes, Queries for reads)
- ✅ Repository Pattern (interface + implementation)
- ✅ Cookie-based JWT authentication (httpOnly, secure, sameSite)

---

## 🧪 Teljes Tesztelési Flow

### 1. Szerver indítása
```bash
npm run dev
```

**Expected output:**
```
✅ Prisma connected to PostgreSQL
✅ DI Container configured (CQRS pattern)
🚀 Server running on http://localhost:3000
📧 Email Service configured (implement EmailService!)
🔐 JWT Authentication enabled (cookie-based)
🍪 Cookies: httpOnly, secure (production), sameSite=strict

📍 Endpoints:
   POST   /api/auth/register
   POST   /api/auth/login
   POST   /api/auth/logout
   GET    /api/users/me (protected)
   PUT    /api/users/me (protected)
   GET    /api/users (protected)
   GET    /api/users/:id (protected)
```

### 2. Regisztráció (cURL cookie példa)
```bash
curl -c cookies.txt -X POST http://localhost:3000/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Test User",
    "email": "test@example.com",
    "password": "password123"
  }'
```

**Kimenet:**
- ✅ JWT token cookie-ban (Set-Cookie header)
- ✅ bcrypt-tel hashelt jelszó az adatbázisban
- ✅ Email elküldve (ha implementáltad a FELADAT 3-at)
- ✅ Cookie mentve a `cookies.txt` fájlba

### 3. Bejelentkezés
```bash
curl -c cookies.txt -X POST http://localhost:3000/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "test@example.com",
    "password": "password123"
  }'
```

**Kimenet:**
- ✅ JWT token cookie-ban
- ✅ bcrypt.compare jelszó ellenőrzés

### 4. Védett endpoint hívása (Cookie-val)
```bash
curl -b cookies.txt http://localhost:3000/api/users/me
```

**Kimenet:**
- ✅ authMiddleware ellenőrzi a JWT token-t cookie-ból
- ✅ req.user.userId beállítva
- ✅ GetMeQueryHandler lekéri az aktuális user-t Prisma-val

### 5. Kijelentkezés
```bash
curl -b cookies.txt -c cookies.txt -X POST http://localhost:3000/api/auth/logout
```

**Kimenet:**
- ✅ Cookie törlése (Max-Age=0)
- ✅ Következő request-nél 401 Unauthorized

---

## 🧪 Unit Testing

**Futtatás:**
```bash
npm test                # Összes teszt + coverage
npm run test:watch      # Watch mode
npm run test:unit       # Csak unit tesztek
```

**Expected output:**
```
PASS  tests/unit/commands/RegisterUserCommandHandler.test.js
PASS  tests/unit/commands/LoginUserCommandHandler.test.js
PASS  tests/unit/queries/GetMeQueryHandler.test.js
PASS  tests/unit/controllers/AuthController.test.js
PASS  tests/unit/middlewares/authMiddleware.test.js
PASS  tests/unit/services/JwtService.test.js

Test Suites: 10 passed, 10 total
Tests:       75 passed, 75 total
```

---

## ❌ Hibaelhárítás

### Docker PostgreSQL nem indul
```bash
docker-compose down
docker-compose up -d
docker-compose logs postgres
```

### Prisma migration hiba
```bash
npm run prisma:migrate:reset
npm run prisma:migrate
npm run prisma:generate
```

### JWT token invalid hiba (Cookie-based)
- ✅ Ellenőrizd, hogy a `.env` fájlban van-e `JWT_SECRET`
- ✅ cURL-nél használd a `-b cookies.txt` flag-et
- ✅ Frontend-en használd a `credentials: 'include'` opciót

### Email nem megy ki
- ✅ Ellenőrizd az Ethereal SMTP credentials-t (`.env`)
- ✅ Nézd meg a console-t az Ethereal preview URL-ért
- ✅ Hozd létre a `templates/welcome.hbs` fájlt
- ✅ Ellenőrizd, hogy implementáltad-e az EmailService-t

### CORS hiba frontend-ből
- ✅ Add meg a frontend origin-t az `.env` fájlban: `ALLOWED_ORIGINS=http://localhost:5173`
- ✅ Uncomment a `app.use(corsMiddleware);` sort a `server.js`-ben
- ✅ Implementáld a CORS middleware-t (FELADAT 2)

---

## 📊 Értékelési Szempontok

### Funkcionális követelmények:
- ✅ DI Container működik (register, resolve, createScope)
- ✅ Singleton, Transient, Scoped lifecycle-ok implementálva
- ✅ CORS whitelist működik (engedélyezett és tiltott origin-ek)
- ✅ Email küldés funkcionális (Handlebars template + Ethereal SMTP)
- ✅ Template fájl létrehozva és használva

### Kód minőség:
- ✅ Kód tisztaság és SOLID elvek követése
- ✅ Hibakezelés (try-catch, validation)
- ✅ Environment változók használata (.env)
- ✅ Kommentek és dokumentáció
- ✅ Clean Architecture layering betartása

### Testing:
- ✅ Unit tesztek írása (Container, CORS, EmailService)
- ✅ Tesztek lefutnak és zöldek
- ✅ Megfelelő coverage (>70%)

---

## 📚 Hasznos Források

- 📖 [SEGÍTSÉG.md](SEGÍTSÉG.md) - Részletes példakódok és megoldások
- 📖 [ARCHITECTURE.md](ARCHITECTURE.md) - Clean Architecture dokumentáció
- 📖 [COOKIE_AUTH_MIGRATION.md](COOKIE_AUTH_MIGRATION.md) - Cookie-based JWT migration guide
- 🌐 [Ethereal Email](https://ethereal.email) - Test SMTP service
- 🌐 [Handlebars](https://handlebarsjs.com/) - Template engine
- 🌐 [Prisma Docs](https://www.prisma.io/docs) - ORM documentation

---

**Sok sikert a feladatokhoz! 🚀**

Ha elakadtál, nézd meg a `SEGÍTSÉG.md` fájlt teljes megoldásokkal és magyarázatokkal!

**Cél:** Dependency Injection konténer implementálása különböző lifecycle-okkal

A Container három lifecycle típust támogat:
- **Singleton**: Egyszer jön létre, osztva van minden request között
- **Transient**: Minden resolve()-nál új példány jön létre
- **Scoped**: Request szinten megosztott a példány (req.scope-on keresztül)

```javascript
class Container {
  constructor() {
    // TODO 1: Inicializáld a services Map-et (singleton instance-ok tárolása)
    // TODO 2: Inicializáld a factories Map-et (factory függvények tárolása)
    // TODO 3: Inicializáld a lifetimes Map-et (lifecycle típusok tárolása)
    
    // Példa inicializálás:
    // this.services = new Map();
    // this.factories = new Map();
    // this.lifetimes = new Map();
  }

  register(name, factory, lifetime = 'singleton') {
    // TODO 4: Tárold el a factory függvényt (this.factories.set(name, factory))
    // TODO 5: Tárold el a lifetime típust (this.lifetimes.set(name, lifetime))
    // TODO 6: Ha a lifetime === 'singleton', azonnal példányosítsd:
    //         - Hívd meg a factory-t: const instance = factory();
    //         - Tárold el: this.services.set(name, instance);
  }

  resolve(name, scope = null) {
    // TODO 7: Ha a service regisztrálva van mint 'scoped' ÉS van scope paraméter:
    //         - Ellenőrizd: if (scope && scope.has(name)) return scope.get(name);
    //         - Ha nincs még a scope-ban, példányosítsd és tárold: 
    //           const instance = this.factories.get(name)();
    //           scope.set(name, instance);
    //           return instance;
    
    // TODO 8: Ha singleton, add vissza a services-ből:
    //         if (this.lifetimes.get(name) === 'singleton') {
    //           return this.services.get(name);
    //         }
    
    // TODO 9: Ha transient, minden alkalommal hívj egy új factory-t:
    //         if (this.lifetimes.get(name) === 'transient') {
    //           return this.factories.get(name)();
    //         }
    
    // TODO 10: Ha nem regisztrált a service, dobj hibát:
    //          throw new Error(`Service ''${name}'' is not registered`);
  }

  createScope() {
    // TODO 11: Hozz létre egy új Map-et az scoped instance-oknak
    // TODO 12: Térj vissza egy objektummal ami tartalmaz egy resolve metódust:
    //          const scopeMap = new Map();
    //          return {
    //            resolve: (name) => this.resolve(name, scopeMap)
    //          };
  }
}

module.exports = Container;
```

**Tesztelés:**
A `src/api/server.js` már használja a Container-t. Indítsd el a szervert és nézd meg, hogy működik-e a DI.

---

###  FELADAT 2: CORS Middleware (src/api/middlewares/corsMiddleware.js)

**Cél:** Whitelist alapú CORS konfiguráció implementálása

A CORS middleware csak bizonyos origin-ekről engedélyezi a hozzáférést.

```javascript
const cors = require(''cors'');

// Engedélyezett origin-ek whitelist-je (környezeti változóból vagy default)
const allowedOrigins = process.env.ALLOWED_ORIGINS?.split('','') || [
  ''http://localhost:3000'',
  ''http://localhost:5173''
];

const corsOptions = {
  origin: function (origin, callback) {
    // TODO 1: Ha nincs origin (pl. backend-to-backend, Postman, curl):
    //         if (!origin) {
    //           return callback(null, true);
    //         }
    
    // TODO 2: Ha az origin benne van az allowedOrigins listában:
    //         if (allowedOrigins.includes(origin)) {
    //           return callback(null, true);
    //         }
    
    // TODO 3: Egyébként tiltsd le CORS hibával:
    //         callback(new Error(''Not allowed by CORS''));
  },
  credentials: true, // Cookie és Authorization header engedélyezése
  methods: [''GET'', ''POST'', ''PUT'', ''DELETE'', ''OPTIONS''],
  allowedHeaders: [''Content-Type'', ''Authorization'']
};

module.exports = cors(corsOptions);
```

**.env beállítás:**
```env
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:5173,https://myfrontend.com
```

**Tesztelés:**
```bash
curl -H "Origin: http://localhost:3000" http://localhost:3000/api/users
# Sikeres - engedélyezett origin

curl -H "Origin: http://malicious-site.com" http://localhost:3000/api/users  
# Hiba - tiltott origin
```

**Aktiválás a server.js-ben:**
```javascript
// src/api/server.js
const corsMiddleware = require(''./middlewares/corsMiddleware'');

app.use(corsMiddleware);  // <-- Uncomment this line!
```

---

###  FELADAT 3: Email Service (src/core/EmailService.js)

**Cél:** Nodemailer + Handlebars template alapú email küldés implementálása

Az EmailService welcome emailt küld regisztráció után.

```javascript
const nodemailer = require(''nodemailer'');
const handlebars = require(''handlebars'');
const fs = require(''fs'');
const path = require(''path'');

class EmailService {
  constructor() {
    // TODO 1: Hozz létre Nodemailer transportot Ethereal tesztelő SMTP-vel
    //         this.transporter = nodemailer.createTransport({
    //           host: ''smtp.ethereal.email'',
    //           port: 587,
    //           secure: false, // TLS
    //           auth: {
    //             user: process.env.ETHEREAL_USER || ''your-test-email@ethereal.email'',
    //             pass: process.env.ETHEREAL_PASS || ''your-test-password''
    //           }
    //         });
    
    console.log('' EmailService initialized'');
  }

  async sendWelcomeEmail(userEmail, userName) {
    try {
      // TODO 2: Olvasd be a welcome.hbs template fájlt
      //         const templatePath = path.join(__dirname, ''templates'', ''welcome.hbs'');
      //         const templateSource = fs.readFileSync(templatePath, ''utf-8'');
      
      // TODO 3: Compile-old a template-et Handlebars-szal
      //         const template = handlebars.compile(templateSource);
      
      // TODO 4: Generáld a HTML-t a felhasználói adatokkal
      //         const html = template({ 
      //           name: userName,
      //           date: new Date().toLocaleDateString(''hu-HU'')
      //         });
      
      // TODO 5: Küld el az emailt
      //         const info = await this.transporter.sendMail({
      //           from: ''"Clean Architecture App" <noreply@cleanarch.com>'',
      //           to: userEmail,
      //           subject: ''Üdvözlünk az alkalmazásban!'',
      //           html: html
      //         });
      
      // TODO 6: Logold ki az Ethereal preview URL-t
      //         const previewUrl = nodemailer.getTestMessageUrl(info);
      //         console.log('' Email elküldve:'', previewUrl);
      
    } catch (error) {
      console.error('' Email küldési hiba:'', error.message);
    }
  }
}

module.exports = EmailService;
```

**Email Template (src/core/templates/welcome.hbs):**
```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <style>
    body { font-family: Arial, sans-serif; background-color: #f4f4f4; padding: 20px; }
    .container { background: white; padding: 30px; border-radius: 10px; max-width: 600px; margin: 0 auto; }
    h1 { color: #333; }
    .footer { margin-top: 30px; font-size: 12px; color: #999; }
  </style>
</head>
<body>
  <div class="container">
    <h1>Üdvözlünk, {{name}}! </h1>
    <p>Sikeres regisztráció az alkalmazásunkban!</p>
    <p>Regisztráció dátuma: <strong>{{date}}</strong></p>
    <p>Mostantól hozzáférsz az összes funkciónkhoz.</p>
    <div class="footer">
      <p>Ez egy automatikus üzenet, kérjük ne válaszolj rá.</p>
    </div>
  </div>
</body>
</html>
```

**.env konfigurálás Ethereal SMTP-vel:**
1. Menj a https://ethereal.email oldalra
2. Kattints a "Create Ethereal Account" gombra
3. Másold ki a kapott user és password értékeket
4. Állítsd be a `.env` fájlban:
```env
ETHEREAL_USER=your-generated-user@ethereal.email
ETHEREAL_PASS=your-generated-password
```

**Tesztelés:**
Regisztrálj egy új felhasználót:
```bash
POST http://localhost:3000/api/auth/register
{
  "name": "Test User",
  "email": "test@example.com",
  "password": "password123"
}
```

Nézd meg a console-ban az Ethereal preview URL-t, ami így níz ki:
```
 Email elküldve: https://ethereal.email/message/XXXXXX
```

Nyísd meg a böngészőben és látni fogod az elküldött emailt!

---

##  Projekt Struktúra

```
src/
 api/
    controllers/
       AuthController.js        Kész (regisztráció, login)
       UserController.js        Kész (védett user endpointok)
    middlewares/
       authMiddleware.js        Kész (JWT token validálás)
       corsMiddleware.js        TODO - FELADAT 2
       scopeMiddleware.js       Opcionális
    routers/
       authRoutes.js            Kész (publikus auth endpointok)
       userRoutes.js            Kész (JWT védett user endpointok)
    server.js                    Kész (Express + DI setup)
 application/
    auth/
       AuthService.js           Kész (bcrypt + JWT)
    user/
        UserService.js           Kész (Prisma CRUD)
 core/
    Container.js                 TODO - FELADAT 1
    EmailService.js              TODO - FELADAT 3
    JwtUtil.js                   Kész (JWT utility)
    templates/
        welcome.hbs             Welcome email template
 domain/
    (Prisma modellekkel helyettesítve)
 infrastructure/
    (Prisma ORM kezeli)
 prisma/
     schema.prisma                Kész (User model)
```

---

##  Tanulási Célok

### CORS (Cross-Origin Resource Sharing)
- Origin alapú hozzáférés-vezérlés implementálása
- Whitelist konfiguráció production környezetben
- Preflight request-ek kezelése (OPTIONS)
- Credential (cookie, auth header) kezelés

### DI Container (Dependency Injection)
- Lifecycle management (Singleton, Transient, Scoped)
- Loose coupling az alkalmazásban
- Tesztelhetőség javítása (dependency injection)
- Service registry pattern

### Email Notification
- SMTP konfiguráció (Ethereal Email)
- Template-alapú email generálás (Handlebars)
- Async email küldés (nem blokkolja a request-et)
- Test email preview Ethereal-lel

---

##  Teljes Tesztelési Flow

### 1. Szerver indítása
```bash
npm run dev
```

### 2. Regisztráció
```bash
POST http://localhost:3000/api/auth/register
{
  "name": "Test User",
  "email": "test@example.com",
  "password": "password123"
}
```

**Kimenet:**
-  JWT token válaszban
-  bcrypt-tel hashelt jelszó az adatbázisban
-  Email elküldve (ha implementáltad a FELADAT 3-at)

### 3. Bejelentkezés
```bash
POST http://localhost:3000/api/auth/login
{
  "email": "test@example.com",
  "password": "password123"
}
```

**Kimenet:**
-  JWT token válaszban
-  bcrypt.compare jelszó ellenőrzés

### 4. Védett endpoint hívása
```bash
GET http://localhost:3000/api/users/me
Authorization: Bearer <token>
```

**Kimenet:**
-  authMiddleware ellenőrzi a JWT token-t
-  req.user.userId beállítva
-  UserService lekéri az aktuális user-t Prisma-val

---

##  Hibaelhárítás

### Docker PostgreSQL nem indul
```bash
docker-compose down
docker-compose up -d
docker-compose logs postgres
```

### Prisma migration hiba
```bash
npm run prisma:migrate:reset
npm run prisma:migrate
npm run prisma:generate
```

### JWT token invalid hiba
- Ellenőrizd, hogy a `.env` fájlban van-e `JWT_SECRET`
- Ellenőrizd, hogy a token `Authorization: Bearer <token>` formátumban van-e

### Email nem megy ki
- Ellenőrizd az Ethereal SMTP credentials-t (`.env`)
- Nézd meg a console-t az Ethereal preview URL-ért
- Ellenőrizd, hogy implementáltad-e az EmailService-t

---

##  Értékelési Szempontok

-  DI Container működik (register, resolve, createScope)
-  CORS whitelist működik (engedélyezett és tiltott origin-ek)
-  Email külső funkcionális (Handlebars template + Ethereal SMTP)
-  Kód tisztaság és SOLID elvek követése
-  Hibakezelés (try-catch, validation)
-  Environment változók használata (.env)

Sok sikert! 