提交图
100 次代码提交
作者 SHA1 备注 提交日期
Guoguo 5775568cd6 feat: add loading animation on reconnect button, 5s timeout 2026-07-02 06:06:11 -07:00
Guoguo dae50a74fd fix: remove scan duration hint text from auto-scan page 2026-07-02 06:05:29 -07:00
Guoguo 0341e62726 feat: add smart_mode_free toggle — all users get smart mode when enabled
Server: subscription API returns active when smart_mode_free is true.
Admin console: add toggle switch in settings page under feature flags.
Default: true (free for all users during promotion period).
2026-07-02 06:05:04 -07:00
Guoguo 94c9af146a chore: bump version to v0.1.8 2026-07-01 05:43:36 -07:00
Guoguo 784af52b7a fix: require seenRunState1 before judging fitting failure, prevent initial frame false trigger 2026-07-01 05:34:05 -07:00
Guoguo 06e8c9831c fix: skip fitting/run_state monitoring in normal mode (mode=0) 2026-07-01 05:29:22 -07:00
Guoguo 515153f134 feat: auto-scan 3-phase state machine with proper PD collection timing
- Phase 1 (waiting_fit): after sending control=0x01, wait for fitting=1
- Phase 2 (collecting): once fitting=1 AND run_state=1, start PD accumulation
- Phase 3 (done): run_state 1→0, calculate averages, auto-send treatment
- Check start-collecting in BOTH fitting and run_state handlers
- fitting=0 + run_state 1→0 = fitting failure, prompt retry
- Timeout 3 minutes (was 30s), auto-start treatment on completion
2026-06-29 05:36:12 -07:00
Guoguo b7b76a675d chore: remove dead regions param from wear-check 2026-06-29 05:29:51 -07:00
Guoguo f85925ecd1 fix: correct page flow — wear-check before mode select, smart mode to auto-scan
- wear-check onNext → treatment-setup (was auto-scan)
- treatment-setup smart mode → auto-scan (was wear-check)
Flow: index → wear-check → treatment-setup → normal: treat / smart: auto-scan → treat
2026-06-29 05:28:05 -07:00
Guoguo 74591d4da2 fix: audit fixes — dedupe run_state logs, stop device on scan exit
- Only log run_state when value changes (avoid flooding console)
- Send stopTreatment on unload if scan is in progress (stop device LEDs)
2026-06-29 04:02:16 -07:00
Guoguo f5cd882986 feat: redesign auto-scan as detection page with manual trigger and PD averaging
- Add "start detection" button (not auto-start on page load)
- Send control=0x01 only when user clicks button
- Accumulate PD values across all ADC frames during scan
- Monitor run_state: wait for 0x01→0x00 transition as completion signal
- Calculate PD averages on completion
- Send treatment command (control=0x02) on "next" with calculated params
- TODO: plug in full NR diagnosis algorithm when PD→region mapping confirmed
2026-06-29 03:58:40 -07:00
Guoguo 2995b0ee02 fix: smart mode goes to wear-check first instead of directly to auto-scan 2026-06-29 03:57:31 -07:00
Guoguo f9141b25d0 refactor: wear-check is now pure manual confirm, no BLE commands
Remove all fitting detection logic (setParams, fitting event listener,
timeout). User manually confirms wearing, then proceeds to detection
page. No BLE commands sent on this page.
2026-06-29 03:57:05 -07:00
Guoguo 52f3ef971b fix: auto-scan onNext goes directly to treating instead of looping back to setup 2026-06-24 19:38:16 -07:00
Guoguo c5afce59d5 fix: restore fitting check control to 0x01 (scan/detect mode) 2026-06-24 18:55:27 -07:00
Guoguo 5cd3dc1e5d fix: fitting check uses control=IDLE to avoid triggering scan sequence 2026-06-24 18:49:17 -07:00
Guoguo bf83adcd28 chore: bump version to v0.1.7 2026-06-24 05:21:19 -07:00
Guoguo ec5b8584ec refactor: remove 17-byte FFE4 and 33-byte FFE1 legacy compat code
- Remove parseVendorStatus 17-byte branch (FFE4 is now 19 bytes)
- Remove parseVendorStatus 33-byte branch (FFE1 is now 34 bytes)
- Remove buildVendorCommand33 deprecated alias
- Remove fitting/run_state !== -1 guards in connection.js
- Update commands.js to use buildVendorCommand directly
2026-06-24 05:13:36 -07:00
Guoguo 29975c6043 fix: restore fitting timeout to 10s for hardware detection delay 2026-06-24 04:12:50 -07:00
Guoguo ca1b9b4377 debug: log FFE1 command hex on every writeRawCommand 2026-06-24 04:10:58 -07:00
Guoguo a5dacef4a7 debug: log stopTreatment success/failure on stop button 2026-06-24 03:53:31 -07:00
Guoguo 229e5f4ed5 fix: default gain to 0 instead of brightness per protocol examples 2026-06-24 03:16:19 -07:00
Guoguo da307e32c8 fix: reduce fitting timeout from 10s to 3s (firmware not yet reporting fitting) 2026-06-24 03:11:32 -07:00
Guoguo c6d958d2ea debug: log FFE4 frame length and type on receive 2026-06-24 02:31:23 -07:00
Guoguo 4c674e5c23 fix: address audit findings — fitting trigger, race guards, state conflicts
wear-check:
- Send weak pulse light (brightness=26) to trigger FFE4 fitting report
- Timeout degrades to pass (backward compat with 17-byte firmware)
- Sync _resolved flag prevents double-resolve

treating:
- Only treat run_state=0x00 as completion after seeing run_state=0x02
  (prevents false completion on startup)
- Sync _finishing flag replaces async data.completed for race prevention
- onStatus preserves paused state during fitting loss (|| fittingLost)
- Remove dead _fittingTimer reference from onUnload

auto-scan:
- Sync _completed flag in _scanComplete prevents double-build
2026-06-22 06:28:25 -07:00
Guoguo c5a9e89bd9 feat: treating page monitors fitting/run_state and handles safety events
- Listen for 'fitting' event: detect skin detachment, pause on loss,
  resume on re-attach
- Listen for 'run_state' event: detect device fault (0xFF) and IDLE
  completion (0x00)
- Low battery warnings: toast at <=10%, force stop at <=5%
- Guard finishAsComplete against double-completion
- Proper cleanup of all new event listeners on unload
2026-06-22 06:21:59 -07:00
Guoguo f4e74e9460 feat: auto-scan receives 4 sequential ADC sets for multi-spectrum scan
Firmware does R→UV→Y→IR sequential scan autonomously. Miniprogram
now listens for 4 consecutive ADC notifications, storing each as a
separate spectrum group. Also listens for run_state=IDLE as scan
completion signal. Displays all 4 spectrum groups with PD1-PD7 bars.
Stores full scan data in globalData.lastScanData for diagnosis phase.
2026-06-22 06:20:53 -07:00
Guoguo b5c6038273 feat: wear-check uses FFE4 fitting status instead of hardcoded ok
Listen for 'fitting' event from FFE4 Byte17 (0=not fitted, 1=fitted).
10s timeout if no fitting signal received. Removes vendor_33 bypass
that always returned ok.
2026-06-22 06:19:23 -07:00
Guoguo 8a4f9382e4 fix: audit fixes — add checksum_ok to params parse, passthrough control in command-sync
- parseVendorStatus: add checksum_ok verification for 34-byte and 33-byte params
- command-sync.js: passthrough control, current_gain, hold_time from server payload
- Mark buildVendorCommand33 as deprecated alias
2026-06-12 09:02:43 -07:00
Guoguo 36f12e098e feat: upgrade FFE1 command to 34 bytes with control byte
Per 协议简述(3): Byte33 is now control instruction (0=IDLE, 1=scan,
2=treat), Byte34 is XOR checksum. Backward compat with 33-byte
read-back preserved. All command sites updated with correct control:
- auto-scan: control=0x01 (scan mode)
- treatment-setup: control=0x02 (treat mode)
- stopTreatment: control=0x00 (IDLE)
2026-06-12 09:00:01 -07:00
Guoguo 69621fd2b6 feat: support FFE4 19-byte format with fitting and run_state fields
Per 协议简述(3): FFE4 now 19 bytes — adds Byte17 fitting status
(0=not fitted, 1=fitted) and Byte18 run state (0=IDLE, 1=scanning,
2=treating, FF=fault). Maintains backward compat with 17-byte format.
2026-06-12 08:52:44 -07:00
Guoguo 7270b593ae docs: add updated protocol spec v3 and firmware-mp workflow v1 2026-06-12 08:52:09 -07:00
Guoguo b4d677a9b4 docs: add protocol docs and allow docx in docs/protocols 2026-06-11 04:16:56 -07:00
Guoguo fa44f4f5ad docs: add protocol specs, task sheet, and workflow docs to docs/protocols 2026-06-11 04:16:19 -07:00
Guoguo 340837c700 feat: rebrand to LumiFlow across miniprogram, admin-console, and server 2026-06-10 18:47:22 -07:00
Guoguo edf45690c3 fix: address audit findings for Phase 1 scan
- Extract _cleanup() to properly unregister ADC listener + clear timers
- ADC callback unregisters itself on first receive (prevent duplicates)
- setParams failure now stops scanning and clears all state
- Timeout handler unregisters ADC listener
- Add BLE connection check before scan
- SCAN_TIMEOUT 8s → 12s (must exceed hold_time 10s)
- Pre-compute barWidth in JS instead of float math in WXML
- Error only shows when scanning is false
2026-06-10 08:18:54 -07:00
Guoguo 0ffa67da65 feat: implement MVP Phase 1 — full-area scan with ADC data collection
- Send scan command: all 5 regions LED on, brightness 128
- Listen for ADC notify (17 bytes) instead of broken queryStatus
- Parse and display PD1-PD7 values with visual bars
- Show VBAT/battery info
- Store scan PD data in globalData for Phase 3 smart adjustment
- 8s timeout fallback, stop LED on page unload
2026-06-10 08:16:17 -07:00
Guoguo c9799a5fc1 chore: bump version to v0.1.6 2026-06-05 23:38:02 -07:00
Guoguo 44935c4bf3 fix: correct region mapping (swap left/right, swap middle/bottom) and auto-scan proceeds on timeout
Region name mapping corrected to match actual hardware IO positions:
- 0x01: 左区→右区, 0x02: 右区→左区
- 0x08: 下区→中区, 0x10: 中区→下区
Auto-scan no longer shows timeout error, proceeds to next step instead.
2026-06-05 23:37:03 -07:00
Guoguo 4666050458 feat: add version number v0.1.5 to profile page footer 2026-06-05 23:12:15 -07:00
Guoguo dc0bcbdca3 fix: decodeURIComponent device_id in ble-connect to fix space matching 2026-06-05 22:41:28 -07:00
Guoguo 5bce7060ac fix: BLE scan match use indexOf instead of exact equals
Fixes timeout during binding when targetDeviceId is set but exact
string match fails due to encoding differences. Also skips devices
with no name, and logs match result for every candidate.
2026-06-05 22:38:07 -07:00
Guoguo e4d11d30a8 feat: add BLE scan/connect/service discovery console logs 2026-06-05 22:30:01 -07:00
Guoguo 810a3a19a5 feat: support JW_ device ID format in QR scan and BLE matching
- parseDeviceId accepts hex with spaces (e.g. "672B6D5A 4DCD861")
- BLE scan does exact match on "JW_<device_id>" when target is known
- Manual input placeholder updated to show new format
2026-06-05 19:21:43 -07:00
Guoguo 9882d19b54 fix: replace leftover 我的光面膜 with 我的设备 on home page 2026-06-05 04:37:39 -07:00
Guoguo 3486cefa18 fix: remove remaining 光子美容仪 from server and admin-console
Replace with 智能面膜 (device name) and 智美 (brand name) for regulatory compliance.
2026-06-05 04:33:55 -07:00
Guoguo ba3c621294 feat: add JW_ prefix to BLE device scan filter 2026-06-05 03:59:05 -07:00
Guoguo 29ff1c015b fix: replace facial/medical terms with neutral position labels
Region names: 左脸→左区, 右脸→右区, 额头→上区, 下巴→下区,
鼻唇→中区, 左眼→左上区, 右眼→右上区, 全脸→全区域.
Replace 面部/面罩 with 设备 in wear-check and auto-scan pages.
2026-05-31 23:39:06 -07:00
Guoguo aff8c2d9b5 fix: remove all medical device terms from user-facing text
Replace '光子美容仪' with '智美'/'智能面膜'/'我的设备' throughout.
Replace '护理' with '使用' in all UI text.
Replace '皮肤' with '检测'/'智能' where applicable.
Replace 🌸 with 💎 for brand identity.
Internal code (variable names, API paths, file names) unchanged.
2026-05-29 01:34:54 -07:00
Guoguo 22110e866a feat: add Simple Peripheral back to BLE scan for dev board testing 2026-05-20 07:41:49 -07:00
Guoguo a65dbfc5a8 chore: remove dead debug code — isDevMode, debug CSS, __DEV__ flag 2026-05-20 07:23:26 -07:00
Guoguo f0fdb285b5 chore: remove all mock/debug code for production release
Miniprogram:
- ENV switched to 'prod' (disables __DEV__ flag)
- Deleted mock.js and test-ble-frame.js
- Removed mockBind/mockPurchase from api.js
- Removed all debug UI panels and onMock* handlers from 6 pages
- Removed mock purchase fallback in subscribe-plans
- Removed SIMPLE PERIPHERAL dev board from BLE scan

Server:
- Removed /device/mock-bind route
- Removed /subscription/mock-purchase route
- Removed dev_openid fallback in wechat.js
- Removed mockBind() from binding.dao.js
- Removed mock fallback in purchase endpoint
- NODE_ENV default changed to 'production'

Admin:
- ENV switched to 'prod'

All mock code preserved in 'test' branch for future development use.
2026-05-20 07:19:26 -07:00
Guoguo 0b82d9dbcf fix: sync endpoint uses amount.total instead of payer_total for consistency 2026-05-20 07:03:51 -07:00
Guoguo 778167e47d Merge branch 'feat/production-ready' 2026-05-20 06:59:35 -07:00
Guoguo f66fbe93ec refactor: extract grantTrialIfEligible, fix race condition + hardcoded days
- New grantTrialIfEligible() in subscription.dao.js with SELECT FOR UPDATE
  to prevent concurrent bind race condition granting double trials
- confirmBind + mockBind now call the shared function (was duplicated)
- Trial days no longer hardcoded to 7 in binding — respects settings
2026-05-20 02:37:10 -07:00
Guoguo 1a180ea07b fix: prevent trial reset on device rebind
confirmBind and mockBind now check trial history before granting trial.
Previously only checked for active subscriptions — if trial expired,
rebinding would create a new 7-day trial, allowing infinite free usage.
Now checks if user ever had a trial (any status), skips if so.
2026-05-20 02:25:51 -07:00
Guoguo f1a2523cb4 fix: ADC notifications no longer emit 'status' (prevents timer jump)
- ADC (17-byte) now emits 'adc' + 'battery' events, not 'status'
- Fixes CRITICAL timer jump: remaining_ms:0 was resetting countdown
- Drop ADC packets with bad XOR checksum
- treating.js + index.js subscribe to 'battery' for live battery updates
- onStatus only updates remaining_ms when > 0
2026-05-19 03:57:47 -07:00
Guoguo 3fd7578163 feat: support 17-byte ADC status from updated vendor protocol
Protocol update adds FFE4 Status format: 7×PD sensors (little-endian)
+ VBAT battery voltage (mV) + XOR checksum = 17 bytes.

- parseVendorStatus: handles 1-byte heartbeat, 17-byte ADC, 33-byte params
- handleValueChange: ADC type extracts PD array + battery % from VBAT
- Battery calculated as linear 3000mV(0%) to 4200mV(100%)
- PD data passed through status event for treatment pages
- Updated protocol doc with full byte table and old/new comparison
2026-05-19 03:54:15 -07:00
Guoguo 0feb900a1d docs: complete developer documentation (5 guides + index)
- 01-快速开始: local setup for all 3 modules, common issues
- 02-配置说明: all env vars, WeChat/Pay/DB/COS config details
- 03-架构说明: system overview, directory structure, data flows
- 04-部署指南: Tencent Cloud SCF/COS deployment, launch checklist
- 05-API接口文档: all 42 endpoints with params and response format
- README index with audience guide and quick links
2026-05-18 08:11:30 -07:00
Guoguo afcc8d12de fix: index page — no loading flash on tab switch, subscription always tappable
- Loading animation only shows on first visit, subsequent onShow updates silently
- Subscription row always navigates to plans page (was no-op when active)
- Move devMode init to onLoad (only needs to run once)
2026-05-18 06:04:25 -07:00
Guoguo fda403d6a9 fix: index page center-aligned layout for device card 2026-05-18 05:57:47 -07:00
Guoguo b9a4f484bb fix: index page layout — separate badge from reconnect, space buttons
- Device card: top row with icon+name+badge, reconnect button below
- Action buttons wrapped in flex column with 20rpx gap
- Removed inline device-battery, now part of device-meta row
2026-05-18 05:51:13 -07:00
Guoguo 46cc225fe8 fix: add HTTP timeout and cert cache error recovery in wxpay
- httpsRequest: 15s timeout, prevents hanging on WeChat API outage
- fetchPlatformCertificates: keeps old certs if refresh fails,
  only throws if no certs at all (first time failure)
2026-05-18 05:35:17 -07:00
Guoguo 2e63213e60 fix: handle literal \n in WX_MCH_PRIVATE_KEY env var
- Replace literal '\n' with real newlines when reading private key from env
- Add PEM header validation to catch format errors early
- File-based key (privateKeyPath) unaffected
2026-05-18 05:32:22 -07:00
Guoguo c21a0912c6 fix: auto-cleanup stale payment orders and expired pending bindings
- closeStaleOrders: marks payment orders older than 24h as 'closed'
- closeExpiredPending: marks expired binding requests (bind_status=3) as cancelled
- Both run on app startup (SCF cold start), no cron needed
- countPendingByUser already filters to 2h window (previous commit)
2026-05-18 03:52:03 -07:00
Guoguo 343eeca89a fix: pending order count only includes orders created within 2 hours 2026-05-18 03:49:11 -07:00
Guoguo 05e990eda5 fix: payment security hardening — 3 CRITICAL + 3 HIGH
CRITICAL fixes:
- C1: Notify amount validation now unconditional (was skippable if amount field missing)
- C2: Sync endpoint validates payer_total against order amount before activation
- C3: Order ID uses crypto.randomBytes(6) instead of Math.random (collision-safe)

HIGH fixes:
- H1: Payment endpoints rate limited to 5/min per IP
- H2: Max 5 pending orders per user, reject new ones until completed/cancelled
- H3: Purchase endpoint returns error (not mock) when wxpay unconfigured in production

Also fixed:
- Notify handler asserts Buffer body, rejects non-Buffer (L3)
- Notify error response is generic, no internal message leak (M1)
- Private key cached in memory after first read (L2)
- Fixed duplicate paymentOrderDao const declaration
2026-05-18 03:45:57 -07:00
Guoguo 0ef359b563 fix: add WECHAT_APPID to production guard 2026-05-18 03:18:45 -07:00
Guoguo 731122064b fix: 5 critical payment issues from code review
1. Move notify route before authMiddleware (WeChat callback has no JWT)
2. Add await to verifyNotifySignature call (was fire-and-forget)
3. Remove dangerous verify fallback — all signature failures now throw
4. Payment sync polls 3x before giving up, never redirects to success
   page unless confirmed paid
5. Production guard enforces all WX_MCH_* env vars on startup
2026-05-18 03:16:44 -07:00
Guoguo e9681cdd21 fix: implement real notify signature verification + replay protection
- Fetch and cache WeChat platform certificates via /v3/certificates
- Verify notification RSA-SHA256 signature against platform cert
- Reject notifications with timestamp older than 5 minutes (anti-replay)
- Split decryptResource (raw string) from decryptNotifyResource (JSON)
  so platform cert PEM decryption works correctly
2026-05-18 03:11:33 -07:00
Guoguo 78ea1a03c5 feat: WeChat Pay V3 integration (fill credentials to activate)
Server:
- New lib/wxpay.js: native crypto RSA-SHA256 signing, JSAPI prepay,
  AES-256-GCM notify decryption, order query (no npm deps)
- New dao/payment-order.dao.js: createOrder, markPrepay,
  markPaidAndActivateSubscription (idempotent + transactional)
- New routes/payment.js: GET order status, POST order sync
- New routes/payment-notify.js: WeChat async callback handler with
  signature verification, amount/appid/mchid validation
- Modified subscription/purchase: auto-detects wxpay config, returns
  real payment_params or mock fallback
- Schema: payment_orders table with out_trade_no unique key
- app.js: express.raw() for notify path, payment routes mounted
- config.js: wxpay block with 7 env vars
- .env.example: all WeChat Pay fields documented
- .gitignore: certs/, *.pem, *.p12

Miniprogram:
- subscribe-plans doPurchase: calls real purchase API, falls back to
  mockPurchase only when server returns mock:true
- Added syncAndRedirect for post-payment order confirmation
- api.js: getPaymentOrder, syncPaymentOrder
- Removed "模拟支付"/"测试环境" from UI text
2026-05-18 03:07:59 -07:00
Guoguo 92416261ee feat: production readiness — feature gaps + config hardening
Miniprogram:
- Add BLE reconnect button on home page when disconnected
- Add loading states to index, profile, subscribe-plans pages
- Add profile editing (avatar + nickname) with COS upload
- Enable pull-to-refresh on history page
- Fix auto-scan self.options → self.data inconsistency
- Add console.error to silent catch blocks
- Gate 'Simple Peripheral' BLE scan behind __DEV__ flag
- Add production config comment to env.js

Admin console:
- Add empty state '暂无数据' to all 5 list views
- Replace plain text plan input with select dropdown
- Add type="date" to record date filters
- Add production config comment

Server:
- CORS origin restricted in production (env CORS_ORIGIN)
- DB pool size configurable via DB_POOL_SIZE env var
- .env.example updated with WeChat Pay + production fields
2026-05-15 09:07:41 -07:00
Guoguo 7e036576e3 fix: wear-check reconnect scans and connects directly
- Retry button disconnects then re-scans for device (no page navigation)
- Prevents duplicate scan with checking guard
- Disconnect before scan with 500ms delay for adapter recovery
- Clears reconnect timer on success/error/unload
- Error text updated to guide user to retry button
2026-05-12 06:37:51 -07:00
Guoguo 4149c35a0a fix: wear-check page stuck spinning in vendor_33 mode
- vendor_33 mode skips BLE wear detection (protocol doesn't support it)
  and passes check immediately if device is connected
- Show error message if device is not connected
- Retry button navigates back if disconnected instead of re-checking
2026-05-12 06:34:52 -07:00
Guoguo f69da211ab fix: BLE connection leak on page unload and retry timer cleanup
- onUnload disconnects BLE if not in 'done' state (prevents connection leak)
- onUnload clears retry timer to prevent setData on dead page
- Store retry setTimeout ref for proper cleanup
2026-05-12 06:28:36 -07:00
Guoguo 1fa6434451 fix: BLE reconnect stuck on binding state
- onRetry clears bind_result listener before disconnect
- Add 1s delay after closeBluetoothAdapter before re-scanning
- Fix binding state text from '点击连接' to '正在配对...'
2026-05-12 06:25:53 -07:00
Guoguo 8e306819ff fix: heartbeat no longer emits 'status' with remaining_ms=0
Heartbeat (1-byte FFE4 notify) now emits 'heartbeat' event only.
Only 33-byte state responses emit 'status' with parsed IO data.
Fixes timer jumping to 0 every second during treatment.
2026-05-12 06:22:28 -07:00
Guoguo 7d7cb9d081 feat: add 'Simple Peripheral' to BLE scan name filter for dev board 2026-05-12 06:19:12 -07:00
Guoguo 20d37982ca fix: vendor_33 BLE emits compatible 'status' event for existing pages
- handleValueChange now calls parseVendorStatus and emits 'status'
  with legacy-compatible shape (mode_state, battery, remaining_ms, etc.)
- 1-byte heartbeat mapped to mode_state, 33-byte state parsed for
  active IO detection
- Fixes regression where treating, index, wear-check, auto-scan pages
  never received status updates in vendor_33 mode
- Also emits 'vendor_raw' with full parsed data for future use
2026-05-12 06:03:28 -07:00
Guoguo cd088dbddc fix: BLE protocol handling matches actual device behavior
- discoverChars uses properties (write/notify) to distinguish FFE1
  command characteristic from FFE1 service UUID
- handleValueChange: vendor_33 mode emits vendor_status (FFE4 heartbeat)
  and vendor_data separately, no longer tries parseFrame on raw bytes
- parseVendorStatus handles 1-byte heartbeat and 33-byte state readback
  with proper IO1-IO5 field parsing
2026-05-12 05:59:16 -07:00
Guoguo 624f52f4cc fix: admin records filter by user_id instead of keyword search
- RecordView passes user_id as separate filter param, not as keyword
- Admin records endpoint forwards user_id to DAO
- treatmentDao.listAdmin supports exact user_id match filter
- Added visible filter tag with clear button in RecordView
2026-05-11 07:15:40 -07:00
Guoguo 0c65ef95f8 fix: cross-audit fixes — file validation, type safety, dedup
- Avatar upload: whitelist image MIME types and extensions (jpg/png/gif/webp)
- Normalize device_id to String for strict comparison in treatment sync
- Add ORDER BY expire_time DESC to purchase/adminCreate subscription queries
- Deduplicate readBearer: middleware imports from lib/auth.js
- Parameterize createTrial INTERVAL instead of string concatenation
- Add rate limiting (20/15min) to avatar upload and phone auth endpoints
2026-05-11 06:22:24 -07:00
Guoguo 583fcb7e3d feat: add user deactivation and vendor BLE protocol 2026-05-11 21:14:41 +08:00
Guoguo c95d47e0c1 fix: audit fixes — treatment sync, avatar upload, code consistency
- Always sync treatment end (not just early stop), pass start/end times
- treatment-done uses api.syncTreatment instead of raw http.post
- Move getApp() from module level to onLoad in treatment-done
- Avatar upload only returns URL, no longer updates profile directly
- COS CDN domain configurable via COS_CDN_DOMAIN env var
- Fix operator precedence in request.js token expiry check
- Remove unused result variable from COS putObject
2026-05-07 06:36:28 -07:00
Guoguo 61e1e06ec1 feat: sync treatment record at start (10min), update on early stop
- Treatment start immediately syncs record with full 10min duration
- Early stop re-syncs with actual elapsed time (upsert by session_id)
- treatment-done page uses same session_id from treating page
2026-05-07 06:30:11 -07:00
Guoguo 06b6ee6b02 fix: avatar picker uses chooseMedia, COS domain to tx.vsai.net.cn
- Replace chooseAvatar button with chooseMedia (more reliable, works on all versions)
- COS avatar URL uses tx.vsai.net.cn instead of generated bucket domain
- Phone shows '已授权' only (no actual number displayed)
2026-05-07 06:23:42 -07:00
Guoguo 6c1c421e6e fix: use unicode checkmark instead of HTML entity in wxml 2026-05-07 05:59:16 -07:00
Guoguo 9019573662 fix: serverless adapter binary body support, hide phone number in register
- Keep body as Buffer instead of utf8 string for multipart/form-data
- Set content-length header for multer compatibility
- Phone authorization shows '已授权' instead of actual number
2026-05-07 05:58:41 -07:00
Guoguo 8427d35fb3 chore: remove debug code and restore phone authorization as required
- Remove debug register page entry and console.log from login
- Remove phone skip option, phone authorization is mandatory
- Restore incomplete registration check (no phone → redirect to register)
2026-05-07 05:54:37 -07:00
Guoguo b17f8cbfb3 debug: add temporary register page entry and login debug log 2026-05-06 06:41:50 -07:00
Guoguo fcbae016ed debug: add console.log to getPhoneNumber callback 2026-05-06 06:35:50 -07:00
Guoguo c065d3fdce fix: make phone authorization skippable in registration
getPhoneNumber requires verified enterprise miniprogram account.
Allow users to skip phone auth and complete registration without it.
2026-05-06 06:29:03 -07:00
Guoguo 52456d850e fix: audit fixes for registration flow
- loadProfile() now returns Promise (was missing return)
- Avatar upload via COS instead of storing WeChat temp path
- Add POST /user/avatar endpoint with multer + COS SDK
- Incomplete registration detection: redirect to register if phone is empty
2026-05-06 06:18:21 -07:00
Guoguo 2f6ab74eab fix: admin console support non-root path deployment
- Set vite base to /admin/ (configurable via PUBLIC_PATH env var)
- Add h5 router base in manifest.json for subdirectory deployment
2026-05-06 06:12:39 -07:00
Guoguo 563e515bce feat: add registration page for new miniprogram users
- New register page with chooseAvatar, nickname input (random default),
  and required phone number authorization via getPhoneNumber
- Login simplified: removed deprecated wx.getUserProfile, checks
  is_new_user flag to redirect new users to registration
- Server login response now includes is_new_user field
2026-05-06 06:12:34 -07:00
Guoguo 5cc41f0f10 chore: update API domain deployment config 2026-05-06 21:07:44 +08:00
Guoguo ff4590767d docs: update AGENTS.md with current architecture and security measures 2026-05-05 02:35:36 -07:00
Guoguo 2eb38195f1 fix: address critical security and data integrity issues from cross-audit
- Add expire_time > NOW() filter to findActive() preventing stale subscriptions
- Add express-rate-limit on login endpoints (user: 10/15min, admin: 5/15min)
- Add production guard for default admin credentials
- Fix BLE bindDevice userId encoding (uint32 instead of hexToBytes on numeric)
- Wrap adminCreate in transaction to prevent race condition
- Add settings cache invalidation after admin saves
- Read trial_days from settings instead of hardcoding 7
- Fix double JSON.stringify in commandDao.finish call
- Cancel stale pending bindings before creating new ones
- Reduce token refresh grace period from 3 days to 1 day
- Fix subscribe-success to fetch expiry from server (correct for renewals)
- Add keep-alive name property to DashboardView and SettingsView
- Fix BLE disconnect() to preserve listener registrations across reconnects
2026-05-05 02:33:25 -07:00
Guoguo 031678c03f feat: complete feature gaps across all modules
Server:
- Add settings-cache with 60s TTL for feature toggle checks
- Enforce maintenance_mode on login, enable_binding on device bind

Admin console:
- Remove dead "发送通知" button from user detail
- Firmware check calls real API and compares versions

Miniprogram:
- Wear-check: dynamic battery/connected from BLE state
- Login: hide non-functional phone auth button
- Treating: show actual selected regions instead of hardcoded "全脸"
- Index: display subscription status with tap to manage
- Auto-scan: show "待检测" instead of "--" for PD data
- Agreements: tap shows "内容建设中" modal
2026-05-02 08:48:26 -07:00
Guoguo 1017fb5dae fix: subscription extend instead of overwrite, improve placeholder pages
- Subscription purchase now extends expire_time when user has active
  subscription, instead of cancelling and replacing
- Admin subscription creation uses same extend logic
- Subscribe page shows "续费" button and extend message for renewals
- Help and contact pages: add pink header, centered icon + text
2026-04-29 08:35:58 -07:00