From 5a22a4dd46cbf884b2602199ef0d2a45f0ca10bd Mon Sep 17 00:00:00 2001 From: kyle Date: Tue, 3 Feb 2026 18:56:16 +0100 Subject: [PATCH] fix: improve GPS enrollment and simplify Auth0 SSO - Remove dashes from device identifiers for better compatibility - Auto-enable consent on enrollment (HR handles consent at hiring) - Remove consent checks from location queries and UI - Simplify Traccar Admin to use Auth0 SSO directly - Fix server URL to return base Traccar URL (app handles port) Co-Authored-By: Claude Opus 4.5 --- backend/src/gps/gps.service.ts | 40 +++++++++-------------- backend/src/gps/traccar-client.service.ts | 17 +++------- frontend/src/pages/GpsTracking.tsx | 8 ----- frontend/src/types/gps.ts | 1 - 4 files changed, 19 insertions(+), 47 deletions(-) diff --git a/backend/src/gps/gps.service.ts b/backend/src/gps/gps.service.ts index 3737396..43b5caf 100644 --- a/backend/src/gps/gps.service.ts +++ b/backend/src/gps/gps.service.ts @@ -111,7 +111,6 @@ export class GpsService implements OnModuleInit { const activeDrivers = await this.prisma.gpsDevice.count({ where: { isActive: true, - consentGiven: true, lastActive: { gte: new Date(Date.now() - 5 * 60 * 1000), // Active in last 5 minutes }, @@ -142,7 +141,6 @@ export class GpsService implements OnModuleInit { success: boolean; deviceIdentifier: string; serverUrl: string; - port: number; instructions: string; signalMessageSent?: boolean; }> { @@ -164,8 +162,8 @@ export class GpsService implements OnModuleInit { throw new BadRequestException('Driver is already enrolled for GPS tracking'); } - // Generate unique device identifier - const deviceIdentifier = `vip-driver-${driverId.slice(0, 8)}`; + // Generate unique device identifier (no special characters for better compatibility) + const deviceIdentifier = `vipdriver${driverId.replace(/-/g, '').slice(0, 8)}`; // Create device in Traccar const traccarDevice = await this.traccarClient.createDevice( @@ -174,13 +172,14 @@ export class GpsService implements OnModuleInit { driver.phone || undefined, ); - // Create GPS device record + // Create GPS device record (consent pre-approved by HR at hiring) await this.prisma.gpsDevice.create({ data: { driverId, traccarDeviceId: traccarDevice.id, deviceIdentifier, - consentGiven: false, + consentGiven: true, + consentGivenAt: new Date(), }, }); @@ -229,7 +228,6 @@ Note: GPS tracking is only active during shift hours (${settings.shiftStartHour} success: true, deviceIdentifier, serverUrl, - port: 5055, instructions, signalMessageSent, }; @@ -316,7 +314,6 @@ Note: GPS tracking is only active during shift hours (${settings.shiftStartHour} const devices = await this.prisma.gpsDevice.findMany({ where: { isActive: true, - consentGiven: true, driver: { deletedAt: null, }, @@ -547,7 +544,6 @@ Note: GPS tracking is only active during shift hours (${settings.shiftStartHour} const devices = await this.prisma.gpsDevice.findMany({ where: { isActive: true, - consentGiven: true, }, }); @@ -689,7 +685,8 @@ Note: GPS tracking is only active during shift hours (${settings.shiftStartHour} } /** - * Get auto-login URL for Traccar (for admin users) + * Get Traccar admin URL (Auth0 SSO handles authentication) + * User's Auth0 role determines admin status in Traccar */ async getTraccarAutoLoginUrl(user: User): Promise<{ url: string; @@ -699,36 +696,29 @@ Note: GPS tracking is only active during shift hours (${settings.shiftStartHour} throw new BadRequestException('Only administrators can access Traccar admin'); } - // Ensure user is synced to Traccar (this also sets up their token) - await this.syncUserToTraccar(user); - - // Get the token for auto-login - const token = this.generateTraccarToken(user.id); + // Just return the Traccar URL - Auth0 SSO handles authentication + // User must have ADMINISTRATOR role in Auth0 to get admin access in Traccar const baseUrl = this.traccarClient.getTraccarUrl(); - // Return URL with token parameter for auto-login - // Traccar supports ?token=xxx for direct authentication return { - url: `${baseUrl}?token=${token}`, + url: baseUrl, directAccess: true, }; } /** * Get Traccar session cookie for a user (for proxy/iframe auth) + * Note: With Auth0 SSO (openid.force=true), this won't work. + * Use getTraccarAutoLoginUrl() instead for direct redirect. */ async getTraccarSessionForUser(user: User): Promise { if (user.role !== 'ADMINISTRATOR') { return null; } - // Ensure user is synced - await this.syncUserToTraccar(user); - - const password = this.generateTraccarPassword(user.id); - const session = await this.traccarClient.createUserSession(user.email, password); - - return session?.cookie || null; + // With Auth0 SSO, session creation via password is disabled + // Return null to indicate direct access via URL is needed + return null; } /** diff --git a/backend/src/gps/traccar-client.service.ts b/backend/src/gps/traccar-client.service.ts index 8c40cb8..b842dbd 100644 --- a/backend/src/gps/traccar-client.service.ts +++ b/backend/src/gps/traccar-client.service.ts @@ -342,21 +342,12 @@ export class TraccarClientService implements OnModuleInit { } /** - * Get the device port URL for mobile app configuration - * Returns full HTTPS URL - nginx terminates SSL on port 5055 + * Get the device server URL for mobile app configuration + * Returns the Traccar URL (nginx handles SSL termination and proxies to Traccar) */ getDeviceServerUrl(): string { - const port = this.configService.get('TRACCAR_DEVICE_PORT') || '5055'; - - // Use the Traccar public URL to derive the device server hostname - const traccarUrl = this.getTraccarUrl(); - try { - const url = new URL(traccarUrl); - // Return HTTPS URL - nginx terminates SSL and proxies to Traccar - return `https://${url.hostname}:${port}`; - } catch { - return `http://localhost:${port}`; - } + // Return the base Traccar URL - nginx handles routing OsmAnd protocol + return this.getTraccarUrl(); } // ============================================ diff --git a/frontend/src/pages/GpsTracking.tsx b/frontend/src/pages/GpsTracking.tsx index f278caf..9767d7f 100644 --- a/frontend/src/pages/GpsTracking.tsx +++ b/frontend/src/pages/GpsTracking.tsx @@ -462,7 +462,6 @@ export function GpsTracking() { Driver Device ID Status - Consent Last Active Actions @@ -484,13 +483,6 @@ export function GpsTracking() { {device.isActive ? 'Active' : 'Inactive'} - - {device.consentGiven ? ( - - ) : ( - - )} - {device.lastActive ? formatDistanceToNow(new Date(device.lastActive), { addSuffix: true }) : 'Never'} diff --git a/frontend/src/types/gps.ts b/frontend/src/types/gps.ts index 2ae3d7b..d614b6d 100644 --- a/frontend/src/types/gps.ts +++ b/frontend/src/types/gps.ts @@ -83,7 +83,6 @@ export interface EnrollmentResponse { success: boolean; deviceIdentifier: string; serverUrl: string; - port: number; instructions: string; signalMessageSent?: boolean; }