Skip to content

Latest commit

 

History

History
662 lines (535 loc) · 13.5 KB

File metadata and controls

662 lines (535 loc) · 13.5 KB

📚 API Documentation - Employee Assessment System

Backend API cho hệ thống đánh giá nhân viên


📋 Table of Contents


🌐 Base URL

http://localhost:4000

Tip:n Trong production, thay bằng domain thật của bạn


🔐 Authentication

Hầu hết các endpoints yêu cầu JWT token trong header:

Authorization: Bearer <your_jwt_token>

🎫 Test Accounts

Role Username Password Permissions
👔 Supervisor manager 123456 Xem employees, tạo/xem assessments
👤 Employee sarah.johnson 123456 Xem assessments của mình

🚀 API Endpoints

1. 🔑 Authentication APIs

1.1. Login

🎯 Mục đích: Đăng nhập và nhận JWT token

Endpoint:

POST /api/auth/login

Request Body:

{
  "username": "manager",
  "password": "123456"
}

Response Success (200):

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "id": "507f1f77bcf86cd799439011",
    "username": "manager",
    "fullName": "Quản lý Hệ thống",
    "email": "manager@company.com",
    "department": "Engineering",
    "position": "Engineering Manager",
    "role": "supervisor"
  }
}

Response Error (400):

{
  "message": "Invalid credentials"
}

Ví dụ Frontend:

const response = await fetch("http://localhost:4000/api/auth/login", {
  method: "POST",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    username: "manager",
    password: "123456"
  })
});

const data = await response.json();
if (data.token) {
  localStorage.setItem("token", data.token);
  localStorage.setItem("user", JSON.stringify(data.user));
}

2. 👥 Employee APIs

2.1. Get All Employees

🎯 Mục đích: Lấy danh sách tất cả nhân viên

🔒 Quyền: Chỉ Supervisor

Endpoint:

GET /api/employees

Headers:

Authorization: Bearer <supervisor_token>

Response Success (200):

[
  {
    "_id": "507f1f77bcf86cd799439011",
    "username": "sarah.johnson",
    "fullName": "Sarah Johnson",
    "email": "sarah.johnson@company.com",
    "department": "Engineering",
    "position": "Senior Software Engineer",
    "role": "employee",
    "createdAt": "2024-11-05T08:30:15.123Z",
    "updatedAt": "2024-11-05T08:30:15.123Z"
  }
]

Response Error (401):

{
  "message": "No token"
}

Response Error (403):

{
  "message": "Forbidden"
}

Ví dụ Frontend:

const token = localStorage.getItem("token");

const response = await fetch("http://localhost:4000/api/employees", {
  headers: {
    "Authorization": `Bearer ${token}`
  }
});

const employees = await response.json();

2.2. Create Employee

🎯 Mục đích: Tạo nhân viên mới

🔒 Quyền: Chỉ Supervisor

⚠️ Status: Chưa implement

Endpoint:

POST /api/employees

Headers:

Authorization: Bearer <supervisor_token>

Response (501):

{
  "message": "Implement create employee later"
}

3. 📊 Assessment APIs

3.1. Create Assessment

🎯 Mục đích: Tạo đánh giá mới cho nhân viên

🔒 Quyền: Chỉ Supervisor

Endpoint:

POST /api/assessments

Headers:

Authorization: Bearer <supervisor_token>
Content-Type: application/json

Request Body:

{
  "employee": "507f1f77bcf86cd799439011",
  "period": "quarterly",
  "cycleLabel": "Q4 2024",
  "criteria": [
    {
      "key": "technical",
      "label": "Kỹ năng chuyên môn",
      "score": 4
    },
    {
      "key": "communication",
      "label": "Kỹ năng giao tiếp",
      "score": 5
    },
    {
      "key": "teamwork",
      "label": "Làm việc nhóm",
      "score": 4
    }
  ],
  "comment": "Nhân viên làm việc tốt, có tinh thần trách nhiệm cao.",
  "nextGoals": "Học thêm về microservices architecture",
  "overall": 4.3
}

Field Descriptions:

  • employee (required): ID của nhân viên được đánh giá
  • period (required): Chu kỳ đánh giá - enum: "biweekly", "monthly", "quarterly", "yearly"
  • cycleLabel (required): Nhãn chu kỳ (ví dụ: "Q4 2024", "January 2025")
  • criteria (optional): Mảng các tiêu chí đánh giá
    • key: Mã tiêu chí
    • label: Tên hiển thị
    • score: Điểm từ 0-5
  • comment (optional): Nhận xét chi tiết
  • nextGoals (optional): Mục tiêu cho kỳ tiếp theo
  • overall (optional): Điểm tổng thể từ 0-5

Response Success (201):

{
  "_id": "507f191e810c19729de860ea",
  "employee": "507f1f77bcf86cd799439011",
  "supervisor": "507f1f77bcf86cd799439012",
  "period": "quarterly",
  "cycleLabel": "Q4 2024",
  "criteria": [
    {
      "key": "technical",
      "label": "Kỹ năng chuyên môn",
      "score": 4
    }
  ],
  "comment": "Nhân viên làm việc tốt...",
  "nextGoals": "Học thêm về microservices...",
  "overall": 4.3,
  "createdAt": "2024-11-05T08:30:15.123Z",
  "updatedAt": "2024-11-05T08:30:15.123Z"
}

Response Error (401/403):

{
  "message": "Unauthorized" // hoặc "Forbidden"
}

Ví dụ Frontend:

const token = localStorage.getItem("token");

const response = await fetch("http://localhost:4000/api/assessments", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${token}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    employee: "507f1f77bcf86cd799439011",
    period: "quarterly",
    cycleLabel: "Q4 2024",
    criteria: [
      { key: "technical", label: "Kỹ năng chuyên môn", score: 4 },
      { key: "communication", label: "Kỹ năng giao tiếp", score: 5 }
    ],
    comment: "Làm việc tốt",
    nextGoals: "Học thêm về microservices",
    overall: 4.5
  })
});

const assessment = await response.json();

3.2. Get My Assessments

🎯 Mục đích: Lấy tất cả đánh giá của chính mình

🔒 Quyền: Chỉ Employee

Endpoint:

GET /api/assessments/me

Headers:

Authorization: Bearer <employee_token>

Response Success (200):

[
  {
    "_id": "507f191e810c19729de860ea",
    "employee": "507f1f77bcf86cd799439011",
    "supervisor": "507f1f77bcf86cd799439012",
    "period": "quarterly",
    "cycleLabel": "Q4 2024",
    "criteria": [
      {
        "key": "technical",
        "label": "Kỹ năng chuyên môn",
        "score": 4
      }
    ],
    "comment": "Nhân viên làm việc tốt...",
    "nextGoals": "Học thêm về microservices...",
    "overall": 4.3,
    "createdAt": "2024-11-05T08:30:15.123Z",
    "updatedAt": "2024-11-05T08:30:15.123Z"
  }
]

Response Error (401/403):

{
  "message": "Unauthorized" // hoặc "Forbidden"
}

Ví dụ Frontend:

const token = localStorage.getItem("token");

const response = await fetch("http://localhost:4000/api/assessments/me", {
  headers: {
    "Authorization": `Bearer ${token}`
  }
});

const myAssessments = await response.json();

3.3. Get Employee's Assessments

Lấy tất cả đánh giá của một nhân viên (chỉ supervisor).

Endpoint: GET /api/assessments/employee/:id

URL Parameters:

  • id: ID của nhân viên

Headers:

Authorization: Bearer <supervisor_token>

Response Success (200):

[
  {
    "_id": "507f191e810c19729de860ea",
    "employee": "507f1f77bcf86cd799439011",
    "supervisor": "507f1f77bcf86cd799439012",
    "period": "quarterly",
    "cycleLabel": "Q4 2024",
    "criteria": [...],
    "comment": "...",
    "nextGoals": "...",
    "overall": 4.3,
    "createdAt": "2024-11-05T08:30:15.123Z",
    "updatedAt": "2024-11-05T08:30:15.123Z"
  }
]

Response Error (401/403):

{
  "message": "Unauthorized" // hoặc "Forbidden"
}

Ví dụ Frontend:

const token = localStorage.getItem("token");
const employeeId = "507f1f77bcf86cd799439011";

const response = await fetch(
  `http://localhost:4000/api/assessments/employee/${employeeId}`,
  {
    headers: {
      "Authorization": `Bearer ${token}`
    }
  }
);

const assessments = await response.json();

HTTP Status Codes

Code Meaning Khi nào xảy ra
200 OK Request thành công
201 Created Tạo mới thành công
400 Bad Request Dữ liệu không hợp lệ (sai username/password)
401 Unauthorized Chưa đăng nhập hoặc token không hợp lệ
403 Forbidden Đã đăng nhập nhưng không có quyền
404 Not Found Endpoint không tồn tại
500 Internal Server Error Lỗi server
501 Not Implemented Chức năng chưa được implement

Error Handling

Tất cả errors đều trả về format:

{
  "message": "Error description"
}

Ví dụ xử lý lỗi trong Frontend:

try {
  const response = await fetch("http://localhost:4000/api/employees", {
    headers: {
      "Authorization": `Bearer ${token}`
    }
  });

  if (!response.ok) {
    const error = await response.json();
    
    if (response.status === 401) {
      // Token hết hạn hoặc không hợp lệ
      localStorage.removeItem("token");
      window.location.href = "/login";
    } else if (response.status === 403) {
      // Không có quyền
      alert("Bạn không có quyền truy cập");
    } else {
      alert(error.message);
    }
    return;
  }

  const data = await response.json();
  // Xử lý data...
  
} catch (error) {
  console.error("Network error:", error);
  alert("Không thể kết nối tới server");
}

Common Frontend Patterns

1. API Helper Function

// utils/api.js
const API_BASE_URL = "http://localhost:4000";

export async function apiCall(endpoint, options = {}) {
  const token = localStorage.getItem("token");
  
  const config = {
    ...options,
    headers: {
      "Content-Type": "application/json",
      ...options.headers,
    }
  };

  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }

  const response = await fetch(`${API_BASE_URL}${endpoint}`, config);

  if (response.status === 401) {
    localStorage.removeItem("token");
    window.location.href = "/login";
    throw new Error("Unauthorized");
  }

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.message || "Request failed");
  }

  return response.json();
}

// Sử dụng:
const employees = await apiCall("/api/employees");
const assessment = await apiCall("/api/assessments", {
  method: "POST",
  body: JSON.stringify({ employee: "...", ... })
});

2. React Hook Example

// hooks/useEmployees.js
import { useState, useEffect } from "react";
import { apiCall } from "../utils/api";

export function useEmployees() {
  const [employees, setEmployees] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function fetchEmployees() {
      try {
        const data = await apiCall("/api/employees");
        setEmployees(data);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    }

    fetchEmployees();
  }, []);

  return { employees, loading, error };
}

// Sử dụng trong component:
function EmployeeList() {
  const { employees, loading, error } = useEmployees();

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;

  return (
    <ul>
      {employees.map(emp => (
        <li key={emp._id}>{emp.fullName}</li>
      ))}
    </ul>
  );
}

Testing với Postman

1. Login

POST http://localhost:4000/api/auth/login
Body (JSON):
{
  "username": "manager",
  "password": "123456"
}

→ Copy token từ response

2. Get Employees

GET http://localhost:4000/api/employees
Headers:
  Authorization: Bearer <paste_token_here>

3. Create Assessment

POST http://localhost:4000/api/assessments
Headers:
  Authorization: Bearer <paste_token_here>
  Content-Type: application/json
Body (JSON):
{
  "employee": "507f1f77bcf86cd799439011",
  "period": "quarterly",
  "cycleLabel": "Q4 2024",
  "criteria": [
    { "key": "technical", "label": "Kỹ năng chuyên môn", "score": 4 }
  ],
  "overall": 4
}

Notes

  1. Token Expiration: JWT token hết hạn sau 8 giờ. Frontend cần handle 401 error và redirect về login.

  2. CORS: Backend chỉ chấp nhận requests từ http://localhost:5173. Nếu frontend chạy port khác, cần update trong server.js.

  3. Role-based Access:

    • supervisor: Có thể xem danh sách employees, tạo assessments, xem assessments của bất kỳ employee nào
    • employee: Chỉ có thể xem assessments của chính mình
  4. Data Validation: Backend tự động validate:

    • Required fields
    • Enum values (period, role)
    • Number ranges (score: 0-5, overall: 0-5)
    • Unique constraints (username)
  5. Timestamps: Mọi documents đều có createdAtupdatedAt tự động.


Contact

Nếu có vấn đề hoặc cần thêm endpoints, liên hệ Backend Team.