--- description: globs: alwaysApply: true --- # Code Guidelines for Influencer–Vendor Automation Platform ## 1. Project Overview A unified web platform to automate ordering, shipping, settlement, and notifications between influencers and vendors. Key architectural decisions: - Frontend: Vue 3 + Nuxt 3 (SSR/SSG), Composition API, TypeScript, Pinia, Vuetify, Axios - BFF: Node.js + Express (ES Modules), Socket.IO for real-time - Backend API: CodeIgniter 4 RESTful controllers, MySQL (RDS), Redis cache - Deployment: Docker → Kubernetes, CI/CD via GitHub Actions - Integrations: Google Cloud Vision OCR, Courier & ERP REST APIs, JWT/OAuth2 authentication --- ## 2. Core Principles 1. Single Responsibility: each function/module addresses one concern; max 200 lines. 2. Strong Typing: avoid `any`; define interfaces for props, DTOs, API responses. 3. Consistent Error Handling: centralize and standardize error responses and logs. 4. DRY & Reusable: extract shared logic into composables, services, or utilities. 5. Domain-Driven Modules: group files by business domain (order, shipping, finance). --- ## 3. Language-Specific Guidelines ### 3.1 Vue 3 + Nuxt 3 + TypeScript - File Organization: - `/pages` → route pages - `/components/{domain}` → feature components - `/composables` → reusable logic hooks (prefixed `useXxx`) - `/stores/{domain}` → Pinia modules (one per domain) - `/plugins`, `/middleware`, `/assets`, `/layouts` - Imports & Aliases: - Use Nuxt aliases: `import X from '~/components/order/OrderList.vue'` - Group imports: external packages → aliased aliases → relative (sorted alphabetically) - Error Handling: - Global error plugin `~/plugins/error.ts` to catch and display Axios errors - In composable: ```ts export async function useFetchOrders() { try { const { data } = await $axios.get('/api/orders') return data } catch (error: unknown) { throw new ApiError(error) } } ``` ### 3.2 Node.js + Express (BFF) - Folder Structure: ``` /src /controllers /services /routes /middlewares /utils app.js ``` - Dependency Management: - Use ES Modules (`"type": "module"`) or TypeScript. - Version-lock in `package.json`; run `npm audit` in CI. - Error Handling: - Create `HttpError` class in `/utils/HttpError.js` - Middleware `errorHandler.js` at the end: ```js app.use((err, req, res, next) => { logger.error(err) res.status(err.statusCode || 500).json({ success: false, message: err.message || 'Internal Server Error' }) }) ``` ### 3.3 CodeIgniter 4 (REST API) - Controllers: one per resource, extend `ResourceController` - Models: use Entities and Query Builder; keep business logic in Services - Validation & Responses: ```php public function create() { $rules = ['order_id' => 'required|integer', /* ... */]; if (! $this->validate($rules)) { return $this->fail($this->validator->getErrors()); } $entity = new OrderEntity($this->request->getPost()); $this->orderService->save($entity); return $this->respondCreated($entity); } ``` - Error Handling: use `HTTPException` for 404/403, global logging in `app/Filters`. --- ## 4. Code Style Rules ### 4.1 MUST Follow - **Use Strict Typescript** Rationale: catch errors at compile time. ```jsonc // tsconfig.json { "compilerOptions": { "strict": true, "noImplicitAny": true, "forceConsistentCasingInFileNames": true } } ``` - **One Component per File** Rationale: clarity, reusability, smaller diffs. - **Composition API & ` ``` - **Pinia Stores for State** Rationale: predictable global state with actions, getters. ```ts import { defineStore } from 'pinia' export const useOrderStore = defineStore('order', { state: () => ({ list: [] as Order[] }), actions: { async fetch() { this.list = await fetchOrders() } } }) ``` - **RESTful API Design** Rationale: consistency and predictability. - Use resource paths: `/vendors/{id}/orders` - HTTP verbs: GET/POST/PUT/DELETE - Standard response envelope: ```json { "success": true, "data": {...}, "error": null } ``` - **Centralized Error Handler** Rationale: unified logging and client messages. ### 4.2 MUST NOT Do - **Avoid `any` or disabling lint rules** Rationale: loses type-safety. - **No Large “God” Modules** Rationale: hard to test and maintain. - **No Inline Styles or Scripts** Rationale: separates concerns; use Vuetify theme or SCSS. - **No Nested Callbacks (Callback Hell)** Rationale: use async/await or Promises. - **No Direct DOM Manipulation** Rationale: Vue manages DOM; use refs or directives. --- ## 5. Architecture Patterns ### 5.1 Component & Module Structure - Domain-Driven Folders: ``` /components/order /components/shipping /composables/order /stores/order /services/api/order.ts ``` - Layers in BFF: - **Routes** → **Controllers** → **Services** → **Data Access** ### 5.2 Data Flow - **Frontend**: Props ↓, Events ↑, Store (Pinia) for shared state, Composables for side-effects. - **API Calls**: Axios interceptors attach JWT, handle 401 globally, retry logic for idempotent GETs. - **Real-time**: Socket.IO client in plugin; update Pinia store on events. ### 5.3 State Management - Local state in component for UI-only values (`ref`, `reactive`). - Global state in Pinia: one store per domain; expose typed actions/getters. - Keep store actions async, commit minimal state changes. ### 5.4 API Design Standards - Base URL per domain: `/api/v1/orders`, `/api/v1/vendors` - Pagination: standard query `?page=1&limit=20`, return `{ items, total, page, limit }`. - Filtering & Sorting: query params `?status=shipped&sort=-date`. - Consistent Error Payload: ```json { "success": false, "error": { "code": "VALIDATION_FAILED", "message": "Invalid field: quantity" } } ``` --- ## 6. Example Code Snippets ### 6.1 Vue Composition & API Call ```ts // MUST: composable with typed response and error handling import { ref } from 'vue' import { Order } from '~/types' import { useApi } from '~/composables/useApi' export function useOrders() { const list = ref([]) const error = ref(null) async function fetchOrders() { try { const res = await useApi().get('/orders') list.value = res.data } catch (e) { error.value = e.message } } return { list, error, fetchOrders } } ``` ```ts // MUST NOT: direct Axios calls in component, untyped any setup() { axios.get('/orders').then(res => { this.orders = res.data }) } ``` ### 6.2 Node.js Express Route & Error ```js // MUST: clean controller and error propagation // src/routes/order.js import { Router } from 'express' import { listOrders } from '../controllers/order.js' const router = Router() router.get('/', listOrders) export default router // src/controllers/order.js export async function listOrders(req, res, next) { try { const orders = await OrderService.fetchAll() res.json({ success: true, data: orders }) } catch (err) { next(new HttpError(500, 'Failed to fetch orders')) } } ``` ```js // MUST NOT: catch without forwarding or unstructured response app.get('/orders', async (req, res) => { try { const orders = await OrderService.fetchAll() res.send(orders) } catch (err) { res.status(500).send('Error') } }) ``` ### 6.3 CodeIgniter4 Controller ```php // MUST: validate, use entity, consistent response class OrderController extends ResourceController { public function create() { $rules = ['vendor_id'=>'required|integer', 'items'=>'required|array']; if (! $this->validate($rules)) { return $this->failValidationErrors($this->validator->getErrors()); } $order = new OrderEntity($this->request->getPost()); $this->orderService->create($order); return $this->respondCreated(['order' => $order]); } } ``` ```php // MUST NOT: raw SQL in controller, no validation class OrderController extends BaseController { public function create() { $db->query("INSERT INTO orders ..."); // anti-pattern } } ``` --- End of Guidelines. Follow these rules as the single source of truth for code quality, maintainability, and consistency.