# Repository Reality - WeChat Mini Program (`miniprogram/`) + Tencent Cloud SCF HTTP backend (`server/`) + Vue 3 H5 admin console (`admin-console/`). - Backend: Express.js with DAO layer, deployed as Tencent Cloud HTTP Function. - Database: TencentDB MySQL, schema in `server/sql/schema.sql`. - Storage: Tencent COS for firmware and admin H5 artifacts. # Architecture ## Server (`server/src/`) ``` app.js — Express app, middleware, route mounting, rate limiting index.js — SCF entry point (lib/serverless.js adapter) config.js — Environment config with production guards lib/ db.js — MySQL2 pool, query/one/transaction helpers, namedPlaceholders auth.js — JWT sign/verify, bcrypt compare, randomHex response.js — ok()/fail() response wrappers settings-cache.js — Cached settings with 60s TTL + invalidateCache() serverless.js — SCF event → Express req/res adapter utils.js — toMysqlDate (UTC+8 aware) middleware/ auth.js — requireUser/requireAdmin Express middleware dao/ — 11 DAO files: admin, binding, command, device, device-event, firmware, log, settings, subscription, treatment, user routes/ — 7 route files: admin, auth, device, firmware, subscription, treatment, user scripts/ local-server.js — Local dev server (app.listen) init-db.js — Database schema initialization ``` **Route mounting:** - `/api/v1` — auth, user, device, subscription, treatment, firmware - `/api/v1/admin` — admin routes - Rate limiting: user login 10/15min, admin login 5/15min **Auth:** - User: JWT_SECRET, payload.type === 'user', 7d expiry, 1d refresh grace - Admin: ADMIN_JWT_SECRET, payload.type === 'admin' - bcrypt for passwords, SHA-256 legacy auto-migration ## Mini Program (`miniprogram/`) ``` pages/ — 15+ pages (index, profile, subscribe-*, treating, etc.) services/ ble.js — Proxy: module.exports = require('./ble/index') ble/ protocol.js — Constants, frame encode/decode, uint32ToBytes, hexToBytes connection.js — Scan, connect, disconnect, reconnect, event emitter commands.js — writeCommand, startTreatment, stopTreatment, bindDevice index.js — Barrel export (39 exports including REGION_NAMES) utils/ api.js — Named API functions matching server routes request.js — wx.request wrapper with token refresh page.js — getStatusBarHeight, navigateBack, isDevMode config/ env.js — API base URL per environment ``` **BLE frame format:** `0xAA 0x55 | length | type | payload | XOR checksum` **Device binding:** Two-step (bind request → BLE handshake → confirm) or mock-bind (dev only). ## Admin Console (`admin-console/`) ``` pages/ login/index.vue — Standalone login page admin/index.vue — SPA shell: AdminLayout + keep-alive + dynamic views/ — 9 views: Dashboard, DeviceList, DeviceDetail, UserList, UserDetail, Subscription, Record, Log, Settings components/ AdminLayout.vue — Sidebar nav, emits 'navigate' with view names DataTable.vue — Reusable table + pagination ConfirmModal.vue — Reusable modal utils/ useList.js — listMixin for paginated list views styles/ common.css — Shared styles including form classes ``` **SPA routing:** Component-based (no URL routing). keep-alive caches views by `name` property. # Key Design Decisions 1. **Subscription extends, never overwrites** — purchase() adds days to existing expire_time via DATE_ADD 2. **Settings cache** — 60s TTL in-memory, invalidated on admin save 3. **Feature toggles** — maintenance_mode, enable_binding enforced server-side via settings-cache 4. **Timezone** — SCF runs UTC, MySQL connection timezone +08:00, toMysqlDate forces UTC+8 5. **Mock endpoints** — mock-bind, mock-purchase restricted to non-production (config.nodeEnv !== 'production') 6. **BLE module resolution** — `services/ble.js` proxy file exists because WeChat `require('./ble')` doesn't resolve `ble/index.js` # Security Measures - Rate limiting on auth endpoints (express-rate-limit) - Production guards: throw if JWT secrets or admin credentials use defaults - Parameterized queries (namedPlaceholders) everywhere except one Number()-coerced IN clause - JWT type field prevents cross-contamination between user/admin tokens - CORS currently `*` (development phase, to be restricted for production) # Deployment **Backend local dev:** ```bash cd server && npm install && npm start ``` **SCF deploy:** - HTTP function, uses `scf_bootstrap` (not event handler) - Must be in TencentDB VPC/subnet - Function name: `jw-beauty-api` **Admin H5:** ```bash cd admin-console && npm install && npm run build:h5 && npm run deploy:cos ``` **Test API base:** `https://1426323813-ilxkhlxf4p.ap-guangzhou.tencentscf.com` # Working Rules - Use current code as source of truth, not older planning docs - Never commit `.env`, credentials, or signed URLs - WeChat miniprogram `require()` does not auto-resolve directories — always use explicit proxy files - `wx.getUserProfile()` is deprecated; if reliable profile needed, use `chooseAvatar` + nickname input - Mock/dev endpoints are gated by `config.nodeEnv !== 'production'`