@valentine-efagene/qshelter-common 2.0.63 → 2.0.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -321,10 +321,67 @@ model Tenant {
321
321
  documentTemplates DocumentTemplate[]
322
322
  offerLetters OfferLetter[]
323
323
 
324
+ // API keys for third-party integrations
325
+ apiKeys ApiKey[]
326
+
324
327
  @@index([subdomain])
325
328
  @@map("tenants")
326
329
  }
327
330
 
331
+ // =============================================================================
332
+ // API KEYS - Third-party integration credentials
333
+ // =============================================================================
334
+ // ApiKey enables partners/integrations to authenticate via token exchange.
335
+ //
336
+ // Flow:
337
+ // 1. Admin creates API key for a partner (POST /api-keys)
338
+ // 2. System generates secret, stores in Secrets Manager, returns id.secret ONCE
339
+ // 3. Partner calls token endpoint with id.secret (POST /api-keys/:id/token)
340
+ // 4. Token endpoint validates via Secrets Manager, returns short-lived JWT
341
+ // 5. Partner uses JWT for API requests; authorizer validates + resolves scopes
342
+ //
343
+ // Security:
344
+ // - Raw secret stored ONLY in AWS Secrets Manager (secretRef = ARN)
345
+ // - Secret returned only once at creation; admin must rotate if lost
346
+ // - Scopes define allowed operations (e.g., ["contract:read", "payment:read"])
347
+ // - Short-lived JWTs (5-15 min) minimize exposure on key compromise
348
+ // =============================================================================
349
+
350
+ model ApiKey {
351
+ id String @id @default(cuid())
352
+ tenantId String
353
+ tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
354
+
355
+ // Identification
356
+ name String // Human-readable name (e.g., "Paystack Integration")
357
+ description String? @db.Text // Optional description
358
+ provider String // Partner/vendor name (e.g., "paystack", "flutterwave")
359
+
360
+ // Secret management (NEVER store raw secret in DB)
361
+ secretRef String // AWS Secrets Manager ARN or name
362
+
363
+ // Permissions - scopes this API key is allowed to request
364
+ // Examples: ["contract:read", "payment:*", "property:read"]
365
+ scopes Json // JSON array of scope strings
366
+
367
+ // Lifecycle
368
+ enabled Boolean @default(true)
369
+ expiresAt DateTime? // Optional expiration date
370
+ lastUsedAt DateTime? // Updated on each token exchange
371
+ revokedAt DateTime? // Set when key is revoked
372
+ revokedBy String? // User ID who revoked
373
+
374
+ // Audit
375
+ createdBy String? // User ID who created
376
+ createdAt DateTime @default(now())
377
+ updatedAt DateTime @updatedAt
378
+
379
+ @@index([tenantId])
380
+ @@index([provider])
381
+ @@index([enabled])
382
+ @@map("api_keys")
383
+ }
384
+
328
385
  model RefreshToken {
329
386
  id String @id @default(cuid())
330
387
  // Use the JWT `jti` for indexed lookups and keep the raw JWT (optional)