| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- ---
- 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<Order[]>('/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 & `<script setup>`**
- Rationale: simpler syntax and tree-shaking.
- ```vue
- <script setup lang="ts">
- import { ref } from 'vue'
- const count = ref(0)
- function increment() { count.value++ }
- </script>
- ```
- - **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<Order[]>([])
- const error = ref<string | null>(null)
- async function fetchOrders() {
- try {
- const res = await useApi().get<Order[]>('/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.
|