18 KiB
18 KiB
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
// 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
// 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
// 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!