Parcourir la source

fix: heartbeat device lookup, CMD path, and web-dashboard API URL

- Fix heartbeat: fallback to findBySerialNo() if findDeviceById() returns null
- Fix FK constraint: use device.id (nanoid) instead of dto.deviceId (serial)
- Fix CMD path in api-server Dockerfile (dist/ structure)
- Add ARG/args for NEXT_PUBLIC_API_URL so Next.js bakes correct IP
- Remove default fallback in docker-compose (fail fast if unset)
clawPi4Bot il y a 2 mois
Parent
commit
d52f8e27a2

+ 1 - 1
apps/api-server/Dockerfile

@@ -18,4 +18,4 @@ RUN cd packages/shared-types && npm run build
 RUN cd apps/api-server && npm run build
 
 EXPOSE 3001
-CMD ["node", "apps/api-server/dist/main.js"]
+CMD ["node", "apps/api-server/dist/apps/api-server/src/main.js"]

+ 5 - 0
apps/api-server/src/modules/devices/devices.repository.ts

@@ -131,6 +131,11 @@ export class DevicesRepository {
     return result[0] ?? null
   }
 
+  async findBySerialNo(serialNo: string) {
+    const result = await db.select().from(devices).where(eq(devices.serialNo, serialNo)).limit(1)
+    return result[0] ?? null
+  }
+
   async verifyApiKey(hash: string, apiKey: string) {
     if (!hash) return false
     return bcrypt.compare(apiKey, hash)

+ 4 - 4
apps/api-server/src/modules/devices/devices.service.ts

@@ -102,7 +102,7 @@ export class DevicesService {
   // ── Heartbeat ──────────────────────────────────────────────
 
   async createHeartbeat(dto: HeartbeatDto, apiKey: string) {
-    const device = await this.repo.findDeviceById(dto.deviceId)
+    const device = (await this.repo.findDeviceById(dto.deviceId)) ?? await this.repo.findBySerialNo(dto.deviceId)
     if (!device) throw new NotFoundException(`Device ${dto.deviceId} not found`)
 
     const validKey = await this.repo.verifyApiKey(device.apiKeyHash, apiKey)
@@ -115,7 +115,7 @@ export class DevicesService {
 
     await Promise.all([
       this.repo.insertHeartbeat({
-        deviceId: dto.deviceId,
+        deviceId: device.id,
         tempC: dto.tempC ?? null,
         batteryPct: dto.batteryPct ?? null,
         storageFreeGb: dto.storageFreeGb,
@@ -123,10 +123,10 @@ export class DevicesService {
         lastCaptureAt: dto.lastCaptureAt ?? null,
         networkStatus: dto.networkStatus ?? 'online',
       }),
-      this.repo.updateDeviceStatus(dto.deviceId, dto.status, now, dto.firmwareVersion),
+      this.repo.updateDeviceStatus(device.id, dto.status, now, dto.firmwareVersion),
     ])
 
-    const pendingCommands = await this.repo.getPendingCommandCount(dto.deviceId)
+    const pendingCommands = await this.repo.getPendingCommandCount(device.id)
 
     if (device.projectId && device.orgId) {
       this.realtime.emitDeviceHeartbeat(

+ 2 - 0
apps/web-dashboard/Dockerfile

@@ -1,5 +1,7 @@
 FROM node:20-alpine
 
+ARG NEXT_PUBLIC_API_URL=http://localhost:3001
+
 RUN apk add --no-cache npm
 
 WORKDIR /app

+ 3 - 1
docker-compose.yml

@@ -60,10 +60,12 @@ services:
     build:
       context: .
       dockerfile: apps/web-dashboard/Dockerfile
+      args:
+        NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL}
     restart: unless-stopped
     environment:
       NODE_ENV: production
-      NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:3001}
+      NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL}
     ports:
       - '3000:3000'
     depends_on: