Files
motovaultpro/backend/src/core
Eric Gullickson 20189a1d37
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 4m37s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 38s
Deploy to Staging / Verify Staging (pull_request) Successful in 6s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 6s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
feat: Add tier-based vehicle limit enforcement (refs #23)
Backend:
- Add VEHICLE_LIMITS configuration to feature-tiers.ts
- Add getVehicleLimit, canAddVehicle helper functions
- Implement transaction-based limit check with FOR UPDATE locking
- Add VehicleLimitExceededError and 403 TIER_REQUIRED response
- Add countByUserId to VehiclesRepository
- Add comprehensive tests for all limit logic

Frontend:
- Add getResourceLimit, isAtResourceLimit to useTierAccess hook
- Create VehicleLimitDialog component with mobile/desktop modes
- Add useVehicleLimitCheck shared hook for limit state
- Update VehiclesPage with limit checks and lock icon
- Update VehiclesMobileScreen with limit checks
- Add tests for VehicleLimitDialog

Implements vehicle limits per tier (Free: 2, Pro: 5, Enterprise: unlimited)
with race condition prevention and consistent UX across mobile/desktop.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-11 16:36:53 -06:00
..
2025-08-24 14:39:50 -05:00
2025-11-01 21:27:42 -05:00
2026-01-01 11:40:49 -06:00

Core Module Index

Configuration (src/core/config/)

  • config-loader.ts — Load and validate environment variables
  • database.ts — PostgreSQL connection pool
  • redis.ts — Redis client, cache helpers, and distributed locking
  • user-context.ts — User context utilities

Distributed Lock Service

The DistributedLockService in redis.ts provides Redis-based distributed locking for preventing duplicate operations across multiple containers (blue-green deployments).

All scheduled jobs MUST use distributed locking to prevent duplicate execution when multiple backend containers are running.

import { randomUUID } from 'crypto';
import { lockService } from '../core/config/redis';

// Acquire lock (returns false if already held)
const lockKey = 'job:my-scheduled-task';
const lockValue = randomUUID();  // Unique identifier for this execution
const ttlSeconds = 300;          // Auto-release after 5 minutes

const acquired = await lockService.acquireLock(lockKey, ttlSeconds, lockValue);
if (!acquired) {
  // Another container is already running this job
  return;
}

try {
  // Do work...
} finally {
  // Always release the lock
  await lockService.releaseLock(lockKey, lockValue);
}

API:

Method Description
acquireLock(key, ttlSeconds, lockValue) Acquire lock atomically (SET NX EX)
releaseLock(key, lockValue) Release only if we hold it (Lua script)
isLocked(key) Check if lock exists

Plugins (src/core/plugins/)

  • auth.plugin.ts — Auth0 JWT via JWKS (@fastify/jwt, get-jwks)
  • error.plugin.ts — Error handling
  • logging.plugin.ts — Request logging

Logging (src/core/logging/)

  • logger.ts — Structured logging (Winston)

Middleware

  • middleware/user-context.ts — User ID extraction from JWT

Storage (src/core/storage/)

  • storage.service.ts — Storage abstraction
  • adapters/filesystem.adapter.ts — Filesystem storage adapter