📖 HƯỚNG DẪN PHÁT TRIỂN DỰ ÁN

Hệ Thống Đặt Vé Xem Phim

📋 MỤC LỤC

  1. Tổng quan dự án
  2. Cấu trúc thư mục dự án
  3. Cấu trúc Database
  4. Quy tắc API
  5. Cấu trúc Response
  6. Service Pattern
  7. Quy tắc viết Code
  8. Documentation
  9. Quy trình làm việc

🎯 TỔNG QUAN DỰ ÁN

Công nghệ sử dụng

Kiến trúc


📁 CẤU TRÚC THƯ MỤC DỰ ÁN

Cấu trúc hoàn chỉnh

LVTN_BE/
├── app/
│   ├── Http/
│   │   ├── Controllers/
│   │   │   ├── Api/              # API Controllers cho Mobile
│   │   │   ├── Admin/            # Admin Controllers
│   │   │   ├── Partner/          # Partner Controllers
│   │   │   └── Web/              # Public Web Controllers
│   │   ├── Middleware/
│   │   ├── Requests/             # Form Requests
│   │   ├── Resources/            # API Resources
│   │   └── Traits/
│   ├── Models/
│   ├── Services/                 # Service Layer
│   ├── Helpers/                  # Helper Classes
│   └── Providers/
├── bootstrap/
├── config/
├── database/
│   ├── migrations/
│   └── seeders/
├── doc/
│   ├── api/                      # API Documentation (Markdown)
│   ├── html/                     # API Documentation (HTML)
│   └── task/                     # Task Documentation
├── resources/
│   ├── lang/
│   └── views/
├── routes/
│   ├── api.php
│   └── web.php
└── ...

Mô tả các thư mục chính


🗄️ CẤU TRÚC DATABASE

Schema chính

Database schema được định nghĩa trong file b.sql. Các bảng chính:

1. Phân quyền

2. Media System

3. Core Business

4. Reviews & Favorites

5. Vouchers

Quy tắc khi tạo Migration

✅ BẮT BUỘC:
  1. Tất cả Foreign Keys PHẢI có Index
    $table->foreign('user_id')->references('id')->on('users');
    $table->index('user_id'); // BẮT BUỘC
  2. Tất cả cột thường query PHẢI có Index
    • status, email, code, slug, name, date, created_at
    • Composite indexes cho các query phức tạp
  3. Soft Deletes cho các bảng quan trọng
    $table->softDeletes();
    $table->index('deleted_at');
  4. ENUM cho các trường có giá trị cố định
    $table->enum('status', ['active', 'inactive'])->default('active');
  5. UNIQUE constraints cho các trường không được trùng
    $table->unique(['cinema_id', 'name']); // Không được trùng tên phòng trong cùng rạp
  6. NOT NULL cho các trường bắt buộc
    $table->string('name')->nullable(); // Chỉ nullable khi thực sự cần

Ví dụ Migration đúng chuẩn

Schema::create('showtimes', function (Blueprint $table) {
    $table->id();
    $table->foreignId('movie_id')->constrained()->onDelete('restrict');
    $table->foreignId('room_id')->constrained()->onDelete('restrict');
    $table->date('date');
    $table->time('start_time');
    $table->time('end_time');
    $table->decimal('price', 10, 2);
    $table->enum('status', ['scheduled', 'ongoing', 'completed', 'cancelled'])->default('scheduled');
    $table->timestamps();
    $table->softDeletes();
    
    // Indexes BẮT BUỘC
    $table->index('movie_id');
    $table->index('room_id');
    $table->index('date');
    $table->index('status');
    $table->index(['date', 'start_time']);
    $table->index(['movie_id', 'date']);
    $table->index('deleted_at');
    
    // UNIQUE constraint
    $table->unique(['room_id', 'date', 'start_time']);
});

🔐 QUY TẮC API

Headers bắt buộc

TẤT CẢ API phải có 2 headers sau:
  1. X-Api-Key: API key do server cấp
    X-Api-Key: your-api-key-here
  2. Language: Ngôn ngữ (en hoặc vi), mặc định: en
    Language: vi
    hoặc
    Language: en

Middleware Order

Thứ tự middleware áp dụng:

LanguageMiddleware → ApiKeyMiddleware → JWT → Role → Permission
Lưu ý quan trọng: LanguageMiddleware PHẢI chạy trước ApiKeyMiddleware để đảm bảo message error được dịch đúng ngôn ngữ khi API key không hợp lệ.

📤 CẤU TRÚC RESPONSE

Format thống nhất

TẤT CẢ API phải trả về cùng 1 format:

Response thành công:

{
  "success": true,
  "code": "USER_CREATED_SUCCESS",
  "message": "User created successfully",
  "data": {
    "id": 10,
    "name": "Nguyễn Văn A"
  }
}

Response lỗi:

{
  "success": false,
  "code": "EMAIL_EXISTS",
  "message": "The email has already been taken",
  "errors": {
    "email": "This email is already in use"
  }
}

Quy tắc

  1. Luôn có code: Cả success và error đều phải có code
  2. Message theo ngôn ngữ: Lấy từ resources/lang/{locale}/errors.php hoặc success.php
  3. Không dùng text tự do: Tất cả message phải định nghĩa trong file lang

API Resources

TẤT CẢ dữ liệu trả về PHẢI sử dụng API Resources để format.

Ví dụ Resource

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email,
            'phone' => $this->phone,
            'address' => $this->address,
            'role' => new RoleResource($this->whenLoaded('role')),
            'avatar' => new MediaFileResource($this->whenLoaded('avatar')),
            'created_at' => $this->created_at?->toDateTimeString(),
            'updated_at' => $this->updated_at?->toDateTimeString(),
        ];
    }
}

Sử dụng trong Controller

use App\Http\Traits\ApiResponseTrait;
use App\Http\Resources\UserResource;

class AuthController extends Controller
{
    use ApiResponseTrait;
    
    public function register(Request $request)
    {
        // ... logic tạo user
        
        return $this->successResponse(
            'USER_CREATED_SUCCESS',
            new UserResource($user),
            'User created successfully'
        );
    }
    
    public function me()
    {
        $user = auth()->user();
        $user->load(['role', 'avatar']); // Eager load relationships
        
        return $this->successResponse(
            'USER_FETCHED_SUCCESS',
            new UserResource($user),
            'User fetched successfully'
        );
    }
}

🏗️ SERVICE PATTERN

Nguyên tắc

Controllers KHÔNG được chứa business logic. Tất cả logic đặt trong Services.

Cấu trúc thư mục

app/Services/
├── Auth/
│   └── AuthService.php
├── Movie/
│   ├── MovieService.php
│   └── MovieSearchService.php
├── Booking/
│   ├── BookingService.php
│   └── BookingValidationService.php
├── Cinema/
│   ├── CinemaService.php
│   ├── RoomService.php
│   └── SeatService.php
└── ...

Quy tắc viết Service

  1. Service trực tiếp làm việc với Model (không dùng Repository pattern)
  2. Mỗi Service class chỉ xử lý 1 domain cụ thể
  3. Service methods phải có tên rõ ràng, mô tả đúng chức năng
  4. Service trả về data, không trả về Response

Ví dụ Service

namespace App\Services\Movie;

use App\Models\Movie;
use Illuminate\Support\Facades\DB;

class MovieService
{
    public function getAllMovies(array $filters = [])
    {
        $query = Movie::query();
        
        if (isset($filters['status'])) {
            $query->where('status', $filters['status']);
        }
        
        if (isset($filters['search'])) {
            $query->where('title', 'like', '%' . $filters['search'] . '%');
        }
        
        return $query->with(['poster', 'trailer'])->paginate(15);
    }
    
    public function createMovie(array $data): Movie
    {
        return DB::transaction(function () use ($data) {
            return Movie::create($data);
        });
    }
}

📝 QUY TẮC VIẾT CODE

1. Models

Relationships

2. Controllers

Quy tắc

3. Form Requests

Validation

4. Middleware

Đăng ký Middleware trong Config Files

❌ KHÔNG làm như này:
// config/api.php
return [
    'middleware' => [
        'api.key' => \App\Http\Middleware\ApiKeyMiddleware::class,
    ],
];
✅ NÊN làm như này:
// config/api.php
use App\Http\Middleware\ApiKeyMiddleware;

return [
    'middleware' => [
        'api.key' => ApiKeyMiddleware::class,
    ],
];

Quy tắc:


📚 DOCUMENTATION

API Documentation

Sau khi viết xong 1 API, BẮT BUỘC phải viết documentation:
  1. File Markdown trong doc/api/ (ví dụ: doc/api/auth-otp.md)
  2. File HTML trong doc/html/ (ví dụ: doc/html/auth-otp.html) - Convert từ Markdown với dark theme, format đẹp để hiển thị trên web

Task Documentation

Sau khi hoàn thành 1 task, ghi lại trong doc/task/:

Format: YYYY-MM-DD-[tên-task].md

Ví dụ: 2024-01-15-implement-authentication-api.md


✅ CHECKLIST KHI TẠO API MỚI


✅ CHECKLIST KHI TẠO ADMIN PAGE


🚫 NHỮNG ĐIỀU KHÔNG ĐƯỢC LÀM

  1. KHÔNG viết business logic trong Controller
  2. KHÔNG trả về response format khác nhau
  3. KHÔNG trả về Model trực tiếp, PHẢI dùng API Resource
  4. KHÔNG dùng text tự do trong response message
  5. KHÔNG tạo migration thiếu indexes
  6. KHÔNG viết code lan man, mở rộng không cần thiết
  7. KHÔNG tạo API mà không viết documentation (phải có bảng Request Parameters và Response Fields)
  8. KHÔNG commit code chưa test
  9. KHÔNG viết documentation thiếu format chuẩn
  10. KHÔNG dùng full namespace string trong config files, PHẢI dùng use statement
  11. KHÔNG tạo helper function tùy chỉnh, PHẢI dùng chuẩn Laravel (__())
  12. KHÔNG gửi email mà không truyền locale, PHẢI gửi email theo đúng ngôn ngữ client yêu cầu

📖 TÀI LIỆU THAM KHẢO


💡 LƯU Ý QUAN TRỌNG

  1. Luôn tập trung vào vấn đề chính, tránh viết code lan man
  2. Tái sử dụng code qua Service pattern
  3. Thống nhất format response cho tất cả API
  4. Viết documentation sau mỗi API
  5. Test kỹ trước khi commit

🚀 Chúc các bạn code vui vẻ!