ready to test

Testing

Signed-off-by: Kenneth Obsequio <k80308392@gmail.com>
This commit is contained in:
2026-06-22 10:06:58 +08:00
parent bf48c95467
commit 439bb33f77
189 changed files with 17559 additions and 686 deletions
+147
View File
@@ -0,0 +1,147 @@
# Products Controller Documentation
**File:** `controllers/admin/products.controller.js`
**Base URL:** `/api/admin/products`
**Guards:** `authenticate → requireAdmin() → adminLimiter`
---
## Table of Contents
- [Get Course Product](#get-course-product)
- [Upsert Course Product](#upsert-course-product)
- [Remove Course Product](#remove-course-product)
- [Get Course Categories](#get-course-categories)
- [Sync Course Categories](#sync-course-categories)
---
## Notes
- Each course has **at most one** product listing (`products` table, unique on `course_id`).
- Upsert restores a soft-deleted product if one exists rather than creating a duplicate.
- Categories are managed via the `course_product_categories` junction table (many-to-many between `courses` and `categories`).
- Syncing categories replaces the full set — it is a replace-all, not an append.
---
## Get Course Product
**`GET /api/admin/products/courses/:courseId/product`**
Returns the product listing for a course, or `null` if none exists. Includes archived products (`paranoid: false`).
### Response `200`
```json
{
"status": "success",
"message": "Product retrieved.",
"data": {
"id": 1,
"course_id": 5,
"name": "Advanced JavaScript",
"description": "Full course access",
"price": "49.99",
"currency": "USD",
"access_days": 365,
"is_active": true,
"createdAt": "2026-01-01T00:00:00.000Z",
"updatedAt": "2026-01-01T00:00:00.000Z",
"deletedAt": null
}
}
```
---
## Upsert Course Product
**`PUT /api/admin/products/courses/:courseId/product`**
Creates the product if it does not exist. If a soft-deleted product exists, it is restored and updated. If an active product exists, it is updated.
### Request Body
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | **Yes** | Product name |
| `price` | number | **Yes** | Price (decimal, e.g. `49.99`) |
| `description` | string | No | |
| `currency` | string | No | ISO 4217 code. Default: `USD` |
| `access_days` | number | No | Days of access after purchase. `null` = lifetime |
| `is_active` | boolean | No | Default: `true` |
### Response `200` (updated) / `201` (created)
```json
{
"status": "success",
"message": "Product updated.",
"data": { ... }
}
```
### Error Responses
| Status | Message |
|--------|---------|
| `400` | `name and price are required.` |
---
## Remove Course Product
**`DELETE /api/admin/products/courses/:courseId/product`**
Soft-deletes the course product.
### Response `200`
```json
{ "status": "success", "message": "Product removed." }
```
### Error Responses
| Status | Message |
|--------|---------|
| `404` | `Product not found.` |
---
## Get Course Categories
**`GET /api/admin/products/courses/:courseId/categories`**
Returns the list of categories assigned to a course.
### Response `200`
```json
{
"status": "success",
"message": "Course categories retrieved.",
"data": [
{ "id": 1, "name": "Business", "slug": "business", "is_active": true },
{ "id": 3, "name": "Design", "slug": "design", "is_active": true }
]
}
```
### Error Responses
| Status | Message |
|--------|---------|
| `404` | `Course not found.` |
---
## Sync Course Categories
**`POST /api/admin/products/courses/:courseId/categories`**
Replaces the full set of category assignments for a course. All existing assignments are removed first, then the new set is inserted.
### Request Body
```json
{ "category_ids": [1, 3, 7] }
```
Pass an empty array to clear all category assignments.
### Response `200`
```json
{ "status": "success", "message": "Course categories updated." }
```