Your Name
44d9f1f198
fix(backend): close try-catch block for attribute definition route in product-attributes
2026-10-19 07:02:35 +07:00
antigravity-bot Bot and Your Name
9107a64637
fix(security): Enforce admin authentication across sensitive backend endpoints and eliminate BOM data leak ( #15 )
...
## 🛡️ Security Audit & Hardening Report
### 1. Executive Summary
PR นี้ทำการตรวจสอบและปิดช่องโหว่ด้านความปลอดภัยของ **Backend API (Elysia.js)** ทั่วทั้งระบบ โดยบังคับใช้ **Admin Authentication Guard (`adminOnly` Middleware)** กับทุก Endpoint ที่เกี่ยวข้องกับ:
1. การจัดการและแก้ไขข้อมูลแคตตาล็อกสินค้า (Product & Category CRUD, Bulk Import/Delete)
2. ข้อมูลความลับทางการค้าและสูตรการผลิต (**Bill of Materials - BOM**, ต้นทุน Raw Materials, Profitability/MRP Forecast)
3. ข้อมูลส่วนบุคคลของลูกค้า (**PII** เช่น รายชื่อลูกค้า CRM, RFM Segment, ข้อความติดต่อ Contact Form, อีเมล Newsletter Subscribers)
4. การจัดการคำสั่งซื้อและสถานะ (Order Status Update, Tracking Assignment)
5. การจัดการ Assets และเนื้อหาเว็บไซต์ (Articles, Media Deletion, Category Layout Sections)
พร้อมทั้งกำจัดจุดรั่วไหลของข้อมูลสูตรสินค้า (`bomItems` และราคาต้นทุน `rawMaterial`) ที่เคยหลุดออกไปใน Public Catalog Query (`GET /products` และ `GET /products/:id`)
---
### 2. Root Cause & Technical Findings
#### 2.1 Elysia Lifecycle Plugin Scoping Flaw
- **ปัญหาเดิม:** Middleware `adminOnly` ถูกสร้างด้วย `new Elysia({ name: 'admin-auth' }).onBeforeHandle(...)` โดยไม่มีออปชัน `{ as: 'scoped' }`
- **ผลกระทบ:** ใน Elysia.js v1.2+ หากไม่ระบุ `{ as: 'scoped' }` หรือ `{ as: 'global' }` ฮุก `onBeforeHandle` ที่ประกาศใน plugin ย่อยจะไม่ถูก propagate ไปยัง Parent Route เมื่อถูกเรียกใช้ผ่าน `.use(adminOnly)` ส่งผลให้ middleware ไม่ทำงานจริงในบาง Controller
- **การแก้ไข:** เพิ่ม `{ as: 'scoped' }` ใน `onBeforeHandle` ของ `apps/backend/src/middleware/auth.ts` และรวมศูนย์ `JWT_SECRET` ให้เป็น Single Source of Truth
#### 2.2 Business Confidentiality Leak in Public Queries
- **ปัญหาเดิม:** `GET /api/products` และ `GET /api/products/:id` ทำการ query `variants` โดย `include: { bomItems: { include: { rawMaterial: true } } }`
- **ผลกระทบ:** ผู้ใช้ทั่วไปหรือ Bot ที่เรียกดูหน้าร้าน สามารถมองเห็นสูตรผสม ปริมาณสารเคมี/วัตถุดิบ และราคาต้นทุนต่อหน่วย (`pricePerUnit`) ของสินค้าทุกรายการ
- **การแก้ไข:** ตัด `bomItems` ออกจาก Public Queries ทั้งหมด ข้อมูล BOM จะเปิดให้เข้าถึงเฉพาะผ่าน `GET /api/products/:id/bom` และ `GET /api/products/bom-status` ซึ่งถูกครอบด้วย `adminOnly` เท่านั้น
---
### 3. Comprehensive Security Matrix
| Module | Route / Endpoint | Method | Previous State | New Protected State | Justification |
| :--- | :--- | :---: | :---: | :---: | :--- |
| **Products** | `/api/products` | GET | Public (leaked BOM) | **Public (Clean)** | หน้าร้านใช้แสดงสินค้า (ตัดข้อมูลต้นทุน BOM ออก) |
| | `/api/products/brands` | GET | Public | **Public** | ตัวกรองแบรนด์สำหรับหน้าร้าน |
| | `/api/products/:id` | GET | Public (leaked BOM) | **Public (Clean)** | หน้ารายละเอียดสินค้า (ตัดข้อมูลต้นทุน BOM ออก) |
| | `/api/products/:id/detail-sections` | GET | Public | **Public** | CMS Page Builder สำหรับ Product Page |
| | `/api/products/bom-status` | GET | ⚠️ Public | 🔒 **Admin Only** | รายการสถานะสูตร BOM และต้นทุนรวมของทุกล็อต |
| | `/api/products/:id/bom` | GET, PUT | ⚠️ Public | 🔒 **Admin Only** | ความลับทางการค้า/สูตรผสมของสินค้า |
| | `/api/products` | POST | ⚠️ Public | 🔒 **Admin Only** | ป้องกันการสร้างสินค้าโดยไม่ได้รับอนุญาต |
| | `/api/products/:id` | PUT, PATCH, DELETE | ⚠️ Public | 🔒 **Admin Only** | ป้องกันการแก้ไข/ลบสินค้า |
| | `/api/products/bulk`, `/bulk-delete` | POST | ⚠️ Public | 🔒 **Admin Only** | ป้องกันการโจมตี Mass Write/Delete |
| | `/api/products/brands` | POST, PUT, DELETE | ⚠️ Public | 🔒 **Admin Only** | จัดการแบรนด์สินค้า |
| | `/api/products/:id/images` | POST | ⚠️ Public | 🔒 **Admin Only** | เพิ่มรูปภาพสินค้า |
| | `/api/products/:id/detail-sections/**` | POST, PUT, DELETE | ⚠️ Public | 🔒 **Admin Only** | แก้ไข Section ในหน้ารายละเอียดสินค้า |
| **Categories** | `/api/categories` | GET | Public | **Public** | แสดงหมวดหมู่สินค้าหน้าร้าน |
| | `/api/categories/:id` | GET | Public | **Public** | รายละเอียดหมวดหมู่ |
| | `/api/categories/:id/products` | GET | Public | **Public** | แสดงรายการสินค้าในหมวดหมู่ |
| | `/api/categories/:id/sections` | GET | Public | **Public** | Category Page Builder read |
| | `/api/categories/bulk-import` | POST | ⚠️ Public | 🔒 **Admin Only** | นำเข้าหมวดหมู่จำนวนมาก |
| | `/api/categories` | POST, PUT, DELETE | ⚠️ Public | 🔒 **Admin Only** | จัดการหมวดหมู่สินค้า |
| | `/api/categories/:id/media`, `/image` | PUT, PATCH | ⚠️ Public | 🔒 **Admin Only** | จัดการรูปภาพหมวดหมู่ |
| | `/api/categories/:id/sections/**` | POST, PUT, DELETE | ⚠️ Public | 🔒 **Admin Only** | จัดการ Section ของหมวดหมู่ |
| **Financial & MRP** | `/api/profitability/**` | ALL | ⚠️ Public | 🔒 **Admin Only** | กำไร-ขาดทุน, Margin, ค่าธรรมเนียม, MRP 30 วัน |
| | `/api/raw-materials/**` | ALL | ⚠️ Public | 🔒 **Admin Only** | สารเคมี, สต็อกวัตถุดิบ, ราคาต้นทุนต่อหน่วย |
| | `/api/business-analytics/**` | ALL | ⚠️ Public | 🔒 **Admin Only** | แผนที่การเงิน Omnichannel, Repeat Analytics |
| **CRM & Customers** | `/api/crm/**` | ALL | ⚠️ Public | 🔒 **Admin Only** | Customer RFM Scores, Churn Risk, VIP Lists |
| | `/api/customers` | GET, POST | ⚠️ Public | 🔒 **Admin Only** | รายชื่อลูกค้า, ที่อยู่, เบอร์โทรศัพท์, การปรับแต้ม |
| | `/api/contacts` | GET, PATCH | ⚠️ Public | 🔒 **Admin Only** | ข้อความติดต่อจากลูกค้าหน้าร้าน (PII) |
| | `/api/contacts` | POST | Public | **Public** | ฟอร์มติดต่อเราสำหรับผู้เยี่ยมชม |
| | `/api/newsletter/subscribers` | GET | ⚠️ Public | 🔒 **Admin Only** | รายชื่ออีเมลผู้ติดตาม Newsletter |
| | `/api/newsletter/subscribe` | POST | Public | **Public** | ฟอร์มสมัครรับจดหมายข่าว |
| **Orders & Sales** | `/api/orders` | POST, GET /:id, PATCH /:id/slip | Public | **Public** | ลูกค้าสั่งซื้อ, อัปโหลดสลิป, ดูคำสั่งซื้อของตน |
| | `/api/orders/track` | POST | Public | **Public** | ติดตามพัสดุ (ต้องกรอก OrderId + เบอร์โทรตรงกัน) |
| | `/api/orders` | GET | ⚠️ Public | 🔒 **Admin Only** | รายการคำสั่งซื้อทั้งหมด |
| | `/api/orders/:id/status`, `/tracking` | PATCH | ⚠️ Public | 🔒 **Admin Only** | เปลี่ยนสถานะคำสั่งซื้อ, ใส่เลข Tracking |
| | `/api/orders/customer/:customerId` | GET | ⚠️ Public | 🔒 **Admin Only** | ดูประวัติสั่งซื้อตาม Customer ID |
| | `/api/tiktok/**`, `/lazada-orders/**`, `/shopee/**` | ALL | ⚠️ Public | 🔒 **Admin Only** | ซิงค์คำสั่งซื้อและค่าธรรมเนียม Marketplace |
| **Promotions & CMS** | `/api/coupons/active`, `/validate` | GET, POST | Public | **Public** | ลูกค้าใช้คูปองและตรวจสอบส่วนลด |
| | `/api/coupons` (Admin CRUD) | GET, POST, PATCH, DELETE | ⚠️ Public | 🔒 **Admin Only** | สร้าง/แก้ไข/ลบคูปอง |
| | `/api/promotions/active` | GET | Public | **Public** | แสดงโปรโมชั่นหน้าร้าน |
| | `/api/promotions` (Admin CRUD) | GET, POST, PUT, DELETE | ⚠️ Public | 🔒 **Admin Only** | จัดการแคมเปญโปรโมชั่น |
| | `/api/articles` | GET, GET /:slug, GET /id/:id | Public | **Public** | อ่านบทความบล็อกหน้าร้าน |
| | `/api/articles` (Mutations) | POST, PUT, DELETE, PATCH | ⚠️ Public | 🔒 **Admin Only** | จัดการบทความและคำแปลภาษา |
| | `/api/media` | GET, DELETE | ⚠️ Public | 🔒 **Admin Only** | รายการ Media Library และการลบไฟล์ |
| | `/api/product-attributes/definitions/**` | POST, PUT, PATCH | ⚠️ Public | 🔒 **Admin Only** | การสร้างและแก้ไข Attribute Definitions |
---
### 4. Client Compatibility & Verification
- **Storefront & Website (`apps/website`, `apps/spa`):**
- ไม่ได้รับผลกระทบใดๆ ทุก Route ที่จำเป็นสำหรับการเรนเดอร์ (Catalog, Detail, Reviews, Sections, Checkout, Tracking, Contact, Newsletter) ยังคงเป็น Public
- Payload เบาลงและปลอดภัยขึ้นเนื่องจากไม่มีการส่ง `bomItems` ที่ไม่จำเป็น
- **Admin Panel (`apps/admin`):**
- ไม่ได้รับผลกระทบใดๆ เนื่องจากระบบ API Client ของ Admin ส่ง `Authorization: Bearer <token>` อยู่แล้วในทุก Request
- **Automated Test Results:**
- เพิ่ม Security Contract Test: `apps/backend/src/routes/auth-guard.contract.test.ts`
- ผ่านการทดสอบทั้งหมด 95/95 tests (0 failures)
- ทดสอบผ่าน Production Build (`tsc -b && vite build`) สมบูรณ์ 100%
---
### 5. OWASP Standards Compliance
- **A01:2021 – Broken Access Control:** แก้ไขช่องโหว่ Direct Object Reference และ Unprotected Administrative Interfaces โดยบังคับใช้ JWT Authentication ในทุกจุดสำคัญ
- **A04:2021 – Insecure Design:** แก้ไขการรั่วไหลของข้อมูลสูตรสินค้าและต้นทุนใน Public Response ด้วย Least Privilege Data Exposure Model
---------
Co-authored-by: Your Name <you@example.com >
Reviewed-on: #15
Co-authored-by: antigravity-bot <bot@kittisak.com >
2026-10-18 23:56:00 +00:00
antigravity-bot Bot and Your Name
b27afb4561
feat(website): implement PDPA cookie consent banner and script manager ( #14 )
...
### Overview
Implement PDPA & GDPR compliant Cookie Consent Management Platform (CMP) for pps/website:
- **Zustand Store (cookieConsentStore.ts):** Stores consent record (
ecessary, nalytics, marketing) in localStorage with skipHydration: true for Next.js SSR safety.
- **Cookie Banner (CookieBanner.tsx):** Fixed bottom floating banner with Quiet Luxury styling, providing Accept All, Reject Non-Essential, and Customize buttons.
- **Preferences Modal (CookiePreferencesModal.tsx):** Detailed modal dialog allowing users to granularly toggle Analytics and Marketing cookies (Strictly Necessary is locked).
- **Script Manager (ScriptManager.tsx):** Coordinates Google Consent Mode v2 (nalytics_storage, d_storage), conditionally injects GA4, Meta Pixel, and TikTok Pixel, and dispatches homaroma:consent-change DOM events.
- **Footer Revocation Link:** Added Cookie Preferences link in the Support column of Footer.tsx so users can modify/revoke consent anytime.
- **Multilingual Support:** Added localized text for TH, EN, JA, and ZH.
---------
Co-authored-by: Your Name <you@example.com >
Reviewed-on: #14
Co-authored-by: antigravity-bot <bot@kittisak.com >
2026-10-18 22:51:47 +00:00
Your Name
9a18463bda
feat(profitability): set default period to this_month on omnichannel margin page
2026-10-18 22:00:42 +07:00
admin and Your Name
dbc6c513db
feat(profitability): hybrid actual fees for Shopee/TikTok with conservative 30% fallback ( #13 )
...
Co-authored-by: Your Name <you@example.com >
Reviewed-on: #13
2026-10-18 14:53:31 +00:00
Your Name
b8bb1d4617
feat(profitability): add date range filtering and 30-day MRP inventory forecast
2026-10-18 19:10:22 +07:00
Your Name
c78a898af7
feat(bom): complete 100% master catalog BOM and add Profitability Management Suite
...
- Configured BOMs for all 585 master variants across 5 categories (Oil Ozone, Aroma Oil, Car Diffuser, Room Spray, Reed Diffuser)
- Mapped 2,111 marketplace products (Shopee and Lazada) to master catalog variants
- Added backend profitability routes (/api/profitability/matrix, /omnichannel, /mrp)
- Added 3 admin pages under Product menu: Cost & Profitability Matrix, Omnichannel Margin, and MRP & Material Demand
- Added comprehensive ledgers and production sync scripts
2026-10-18 18:58:11 +07:00
Your Name
f49776f9cb
x
2026-10-18 13:55:18 +07:00
Your Name
4fcdd8a816
feat(mcp): add BOM management tools (list_products_bom_status, get_product_bom, set_product_bom)
2026-10-18 12:25:35 +07:00
Your Name
b030c08f68
feat(raw-materials): add inline price editing with keyboard shortcuts and partial update support
2026-10-18 11:56:38 +07:00
Your Name
a5584d0d46
fix(raw-materials): remove invalid sku field from product select and resolve localized name
2026-10-18 11:44:51 +07:00
admin and Your Name
a0abfbf306
feat(bom): add BOM JSON import modal with auto-matching and live cost preview ( #12 )
...
Co-authored-by: Your Name <you@example.com >
Reviewed-on: #12
2026-10-18 04:24:17 +00:00
antigravity-bot Bot and Your Name
d8f6d8139f
feat(bom): add Get Prompt modal for LLM and fix product name resolution ( #11 )
...
### Summary of Changes
- Added 'Get Prompt' button and ProductBomPromptModal dialog on /products/:id/bom.
- Formats product ID, variants, and raw material inventory into a structured prompt for LLMs.
- Fixed backend bug in GET /products/:id?lang=all that wiped product.name when no translations existed.
- Added multi-level fallback in frontend to ensure product name never shows 'Unknown Product'.
---------
Co-authored-by: Your Name <you@example.com >
Reviewed-on: #11
Co-authored-by: antigravity-bot <bot@kittisak.com >
2026-10-18 03:55:15 +00:00
antigravity-bot Bot and Your Name
a647c9682d
feat(raw-materials): add bulk JSON import with upsert and full-page edit routes ( #10 )
...
Fixes #9
---------
Co-authored-by: Your Name <you@example.com >
Reviewed-on: #10
Co-authored-by: antigravity-bot <bot@kittisak.com >
2026-10-18 03:30:19 +00:00
Your Name
765cdd1fa9
x
2026-10-18 08:01:36 +07:00
Your Name
ca79692b3e
fix(backend): enhance sequence discovery from sister website directories and sync in post-receive
2026-10-17 11:26:29 +07:00
Your Name
0bf544720b
feat(cms): add VDO Frame Scrubber block with isolated sequence library
2026-10-17 11:23:08 +07:00
Your Name
64f7ecf729
feat(cms): add Interactive 360 Turntable and Macro Zoom Showcase block
2026-10-17 09:25:16 +07:00
Your Name
8d9f2fc587
feat(cms): add Cinematic Story Scroll and Apple Showcase blocks to Page Builder
2026-10-17 09:06:44 +07:00
Your Name
25cbe3549e
fix(website): eliminate story scroll dead zones and blank space with continuous progress engine
2026-10-17 08:38:56 +07:00
Your Name
9a5a30778e
x
2026-10-17 08:25:18 +07:00
Your Name
3f9db48df4
x
2026-10-17 08:11:33 +07:00
Your Name
34be2599fa
x
2026-10-17 05:35:27 +07:00
Your Name
9f5b6bce00
x
2026-10-16 06:31:02 +07:00
Your Name
4f8fa1ae09
x
2026-10-16 06:26:13 +07:00
Your Name
64bcd6388a
x
2026-10-15 06:56:21 +07:00
Your Name
570810acdb
x
2026-10-15 06:19:05 +07:00
Your Name
f5893c3fad
x
2026-10-11 06:43:08 +07:00
Your Name
9237c0eded
x
2026-10-10 08:00:56 +07:00
Your Name
943fd8f1a3
x
2026-10-10 06:15:48 +07:00
Your Name
dba82b26a8
x
2026-10-08 08:08:37 +07:00
Your Name
d13dedd215
x
2026-10-08 07:27:34 +07:00
Your Name
bf9599008e
x
2026-10-08 07:12:58 +07:00
Your Name
b7f337fb79
x
2026-10-06 19:55:05 +07:00
Your Name
acee55a633
x
2026-10-06 19:40:15 +07:00
Your Name
ce4502d123
x
2026-10-06 18:16:25 +07:00
Your Name
08045eabff
x
2026-10-06 18:13:03 +07:00
Your Name
46968782b6
x
2026-10-06 16:58:21 +07:00
Your Name
641cc4e42b
x
2026-10-06 16:39:41 +07:00
Your Name
3bbe2bb35e
x
2026-10-06 15:35:04 +07:00
Your Name
230716933e
x
2026-10-06 06:36:26 +07:00
Your Name
7fd3c40ae2
x
2026-10-06 06:13:41 +07:00
Your Name
ebc8f2ffeb
x
2026-10-05 06:43:10 +07:00
Your Name
142d991816
x
2026-10-05 06:17:08 +07:00
Your Name
d9901fd9a6
x
2026-10-05 06:09:46 +07:00
Your Name
af6047fb4d
x
2026-10-05 06:01:05 +07:00
Your Name
8d415ecef7
x
2026-10-04 19:56:23 +07:00
Your Name
e349ef5b84
x
2026-10-04 18:59:27 +07:00
Your Name
b641acbeb7
x
2026-10-04 06:51:38 +07:00
Your Name
04987eebac
x
2026-10-04 06:24:37 +07:00