# Partner Authentication Refactoring - Visual Guide ## Before vs After Architecture ### ❌ Before Refactoring ``` ┌──────────────────────────────────────────────────────────┐ │ testPartnerAuth_post() Controller │ │ (Testing authentication) │ └────────────────────┬─────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────┐ │ authenticateAndCache() │ │ ┌────────────────────────────────────────────┐ │ │ │ 1. Make API call to SatLoc │ │ │ │ 2. Validate response │ │ │ │ 3. Build auth data │ │ │ │ 4. Cache in Redis ← ⚠️ SIDE EFFECT │ │ │ │ 5. Return auth data │ │ │ └────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────┘ │ ▼ ┌────────────────┐ │ Redis Cache │ ← ⚠️ Polluted during testing └────────────────┘ ⚠️ Problems: - Testing pollutes cache - Tight coupling of concerns - Side effects in test endpoints ``` ### ✅ After Refactoring ``` ┌──────────────────────────────────────────────────────────┐ │ testPartnerAuth_post() Controller │ │ (Testing authentication) │ └────────────────────┬─────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────┐ │ authenticate() │ │ ┌────────────────────────────────────────────┐ │ │ │ 1. Make API call to SatLoc │ │ │ │ 2. Validate response │ │ │ │ 3. Build auth data │ │ │ │ 4. Return auth data │ │ │ │ │ │ │ │ ✅ NO CACHING - Pure function │ │ │ └────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────┐ │ Production Flow │ └────────────────────┬─────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────┐ │ authenticateAndCache() │ │ ┌────────────────────────────────────────────┐ │ │ │ 1. Call authenticate() ← REUSES │ │ │ │ 2. Cache result in Redis │ │ │ │ 3. Return auth data │ │ │ └────────────────────────────────────────────┘ │ └──────────────────────┬───────────────────────────────────┘ │ ▼ ┌────────────────┐ │ Redis Cache │ ← ✅ Only cached in production └────────────────┘ ✅ Benefits: - Separation of concerns - No cache pollution during testing - Code reusability - Single source of truth ``` ## Method Comparison ### authenticate() - Pure Authentication ``` ┌─────────────────────────────────────────────┐ │ authenticate(credentials) │ ├─────────────────────────────────────────────┤ │ │ │ INPUT: │ │ • credentials { username, password } │ │ • customerId (for logging) │ │ │ │ PROCESS: │ │ 1. Call SatLoc API /AuthenticateAPIUser │ │ 2. Parse response │ │ 3. Build auth data structure │ │ 4. Return auth data │ │ │ │ OUTPUT: │ │ { │ │ userId: "...", │ │ companyId: "...", │ │ expiresAt: 1234567890, │ │ lastHealthCheck: 1234567890, │ │ originalResponse: {...} │ │ } │ │ │ │ SIDE EFFECTS: None ✅ │ │ │ └─────────────────────────────────────────────┘ ``` ### authenticateAndCache() - With Caching ``` ┌─────────────────────────────────────────────┐ │ authenticateAndCache(credentials) │ ├─────────────────────────────────────────────┤ │ │ │ INPUT: │ │ • credentials { username, password } │ │ • customerId (for caching key) │ │ │ │ PROCESS: │ │ 1. Call authenticate() ← REUSES │ │ └─ Returns auth data │ │ 2. Calculate TTL from expiresAt │ │ 3. Store in Redis with TTL │ │ 4. Return auth data │ │ │ │ OUTPUT: │ │ { │ │ userId: "...", │ │ companyId: "...", │ │ expiresAt: 1234567890, │ │ lastHealthCheck: 1234567890, │ │ originalResponse: {...} │ │ } │ │ │ │ SIDE EFFECTS: │ │ • Stores auth data in Redis ✅ │ │ • Sets TTL on cache entry ✅ │ │ │ └─────────────────────────────────────────────┘ ``` ## Usage Decision Tree ``` Need to authenticate? │ ▼ ┌───────────────────────┐ │ What's the use case? │ └───────────┬───────────┘ │ ┌───────────────┼───────────────┐ │ │ ▼ ▼ ┌───────────────┐ ┌───────────────┐ │ Testing? │ │ Production? │ │ Validation? │ │ Normal flow? │ └───────┬───────┘ └───────┬───────┘ │ │ ▼ ▼ ┌────────────────────┐ ┌────────────────────┐ │ authenticate() │ │authenticateAndCache│ │ │ │ │ │ ✅ No caching │ │ ✅ With caching │ │ ✅ Pure function │ │ ✅ Reuses auth() │ │ ✅ For testing │ │ ✅ For production │ └────────────────────┘ └────────────────────┘ ``` ## Code Examples ### Example 1: Testing Endpoint ```javascript // controllers/partner.js async function testPartnerAuth_post(req, res) { const { customerId, partnerId, username, password } = req.body; // Validate partner system user const partnerSystemUser = await findAndValidatePartnerSystemUser( customerId, partnerId, { requireActive: true, username, password } ); // Get partner service const partnerService = partnerServiceFactory.getService(partnerCode); const credentials = partnerConfig.getApiCredentials(partnerSystemUser, partnerCode); // ✅ Use authenticate() - no caching for testing const authResult = await partnerService.authenticate(credentials, customerId); res.json({ authSuccess: true, userId: authResult.userId, companyId: authResult.companyId }); } ``` ### Example 2: Production Flow ```javascript // services/partner_sync_service.js async function syncPartnerData(customerId, partnerId) { const partnerService = partnerServiceFactory.getService('SATLOC'); const credentials = getCredentials(customerId); // ✅ Use authenticateAndCache() - with caching for production const authData = await partnerService.authenticateAndCache(credentials, customerId); // Use authData for API calls const aircraftList = await partnerService.getAircraftList(authData); return aircraftList; } ``` ### Example 3: Getting Cached or Fresh Auth ```javascript // services/satloc_service.js async getApiCredentials(credentials, customerId) { // Check cache first const cached = await this.cache.getAuth(this.partnerCode, customerId); if (cached && cached.expiresAt > Date.now()) { // ✅ Return cached auth return cached; } // Cache miss - authenticate and cache // ✅ Uses authenticateAndCache() internally const authData = await this.authenticateAndCache(credentials, customerId); return authData; } ``` ## Sequence Diagrams ### Testing Flow (No Caching) ``` ┌──────────┐ ┌────────────┐ ┌─────────┐ ┌───────────┐ │ Client │ │ Controller │ │ Service │ │ SatLoc API│ └────┬─────┘ └─────┬──────┘ └────┬────┘ └─────┬─────┘ │ │ │ │ │ POST testAuth │ │ │ │──────────────>│ │ │ │ │ │ │ │ │ authenticate()│ │ │ │──────────────>│ │ │ │ │ │ │ │ │ GET /Auth... │ │ │ │─────────────>│ │ │ │ │ │ │ │ Success │ │ │ │<─────────────│ │ │ │ │ │ │ authData │ │ │ │<──────────────│ │ │ │ │ │ │ 200 OK │ │ │ │<──────────────│ │ │ │ │ │ │ ✅ NO CACHE OPERATIONS - Clean test ``` ### Production Flow (With Caching) ``` ┌──────────┐ ┌─────────┐ ┌─────────┐ ┌───────────┐ ┌───────┐ │ Sync Job │ │ Service │ │ Service │ │ SatLoc API│ │ Redis │ └────┬─────┘ └────┬────┘ └────┬────┘ └─────┬─────┘ └───┬───┘ │ │ │ │ │ │ sync data │ │ │ │ │─────────────>│ │ │ │ │ │ │ │ │ │ │authenticateAn│ │ │ │ │dCache() │ │ │ │ │─────────────>│ │ │ │ │ │ │ │ │ │ │authenticate()│ │ │ │ │─────────────>│ │ │ │ │ │ │ │ │ │ GET /Auth... │ │ │ │ │─────────────>│ │ │ │ │ │ │ │ │ │ Success │ │ │ │ │<─────────────│ │ │ │ │ │ │ │ │ │ authData │ │ │ │ │<─────────────│ │ │ │ │ │ │ │ │ │ setAuth() │ │ │ │ │──────────────────────────>│ │ │ │ │ │ │ │ │ OK │ │ │ │ │<──────────────────────────│ │ │ │ │ │ │ │ authData │ │ │ │ │<─────────────│ │ │ │ │ │ │ │ │ data synced │ │ │ │ │<─────────────│ │ │ │ │ │ │ │ │ ✅ CACHED FOR REUSE - Efficient production flow ``` ## Benefits Summary | Aspect | Before | After | |--------|--------|-------| | **Test Isolation** | ❌ Tests pollute cache | ✅ Tests are isolated | | **Code Reuse** | ❌ Duplicated logic | ✅ Shared authenticate() | | **Maintainability** | ❌ Coupled concerns | ✅ Separated concerns | | **Debugging** | ❌ Cache interference | ✅ Clear flow | | **Performance** | ❌ Unnecessary caching | ✅ Cache only when needed | | **Testing** | ❌ Complex mocking | ✅ Simple unit tests | --- This refactoring provides a cleaner, more maintainable architecture while maintaining full backward compatibility!