5.3 KiB
5.3 KiB
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 <component :is>
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
- Subscription extends, never overwrites — purchase() adds days to existing expire_time via DATE_ADD
- Settings cache — 60s TTL in-memory, invalidated on admin save
- Feature toggles — maintenance_mode, enable_binding enforced server-side via settings-cache
- Timezone — SCF runs UTC, MySQL connection timezone +08:00, toMysqlDate forces UTC+8
- Mock endpoints — mock-bind, mock-purchase restricted to non-production (config.nodeEnv !== 'production')
- BLE module resolution —
services/ble.jsproxy file exists because WeChatrequire('./ble')doesn't resolveble/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:
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:
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, usechooseAvatar+ nickname input- Mock/dev endpoints are gated by
config.nodeEnv !== 'production'