# DashCaddy API Dependencies Map **Generated:** 2026-03-22 **Purpose:** Document current `ctx` (context object) usage across routes to guide refactoring --- ## Overview The DashCaddy API currently uses a **god object pattern** where a single `ctx` (context) object is passed to all route modules. This object contains 50+ properties mixing: - Utilities (asyncHandler, errorResponse, log) - Domain objects (docker, caddy, dns, session) - Managers (credentialManager, authManager, healthChecker) - Configuration (SERVICES_FILE, CONFIG_FILE, siteConfig) - Template data (APP_TEMPLATES, RECIPE_TEMPLATES) **Problem:** Routes don't declare what they actually need — dependencies are hidden, making testing and refactoring difficult. **Goal:** Move to explicit dependency injection where each route declares exactly what it needs. --- ## Most-Used Properties (Refactor Priority) | Property | Routes Using It | Type | Notes | |----------|-----------------|------|-------| | `ctx.asyncHandler` | 35 | Utility | Wrap async route handlers, universal dependency | | `ctx.errorResponse` | 27 | Utility | Standard error formatting | | `ctx.log` | 20 | Utility | Logger instance | | `ctx.docker` | 15 | Domain | Dockerode wrapper + helpers | | `ctx.caddy` | 12 | Domain | Caddyfile manipulation + reload | | `ctx.fetchT` | 12 | Utility | Timeout-wrapped fetch | | `ctx.servicesStateManager` | 12 | Manager | services.json state management | | `ctx.credentialManager` | 12 | Manager | Encrypted credential storage | | `ctx.siteConfig` | 10 | Config | Site-wide configuration | | `ctx.buildDomain` | 9 | Utility | Domain construction helper | | `ctx.dns` | 9 | Domain | DNS API wrapper | --- ## Route Dependencies (By Route File) ### High-Complexity Routes (10+ dependencies) #### `apps/deploy.js` (15 dependencies) ```javascript // Current module.exports = (ctx) => { ... }; // After refactor (explicit deps) module.exports = ({ APP_TEMPLATES, addServiceToConfig, asyncHandler, buildDomain, buildServiceUrl, caddy, dns, docker, errorResponse, log, logError, notification, portLockManager, safeErrorMessage, siteConfig, }) => { ... }; ``` **Refactor Priority:** HIGH (core deployment logic, frequently used) --- #### `config/backup.js` (16 dependencies) ```javascript // Dependencies CONFIG_FILE, NOTIFICATIONS_FILE, SERVICES_FILE, TAILSCALE_CONFIG_FILE, TOTP_CONFIG_FILE, asyncHandler, caddy, credentialManager, dns, errorResponse, fetchT, loadDnsCredentials, loadNotificationConfig, loadSiteConfig, log, totpConfig ``` **Refactor Priority:** MEDIUM (backup/restore is critical but less frequent) **Opportunity:** Extract backup logic to service layer --- #### `services.js` (13 dependencies) ```javascript // Dependencies SERVICES_FILE, asyncHandler, buildDomain, buildServiceUrl, caddy, credentialManager, dns, errorResponse, log, resyncHealthChecker, safeErrorMessage, servicesStateManager, siteConfig ``` **Refactor Priority:** HIGH (core service management, most-used route) --- ### Medium-Complexity Routes (6-9 dependencies) - `apps/restore.js` (9 deps) - `auth/sso-gate.js` (10 deps) - `dns.js` (8 deps) - `health.js` (8 deps) - `recipes/manage.js` (8 deps) - `sites.js` (12 deps) - `tailscale.js` (9 deps) --- ### Low-Complexity Routes (1-5 dependencies) Good candidates for early refactoring (simpler, less risky): - `backups.js` (2 deps: asyncHandler, backupManager) - `containers.js` (3 deps: asyncHandler, docker, log) - `credentials.js` (3 deps: asyncHandler, credentialManager, errorResponse) - `license.js` (3 deps: asyncHandler, errorResponse, licenseManager) - `monitoring.js` (3 deps: asyncHandler, docker, resourceMonitor) - `notifications.js` (3 deps: asyncHandler, errorResponse, notification) --- ## Domain Object Breakdown ### `ctx.docker` (used by 15 routes) **Properties/Methods:** - `find()` — find container by name - `getUsedPorts()` — list ports in use - `security` — docker-security module **Routes:** - apps/deploy.js, apps/helpers.js, apps/removal.js, apps/restore.js, apps/templates.js - arr/config.js, arr/detect.js, arr/helpers.js - browse.js, containers.js, context.js, logs.js, monitoring.js - recipes/deploy.js, recipes/manage.js **Refactor Suggestion:** Extract to standalone service (`services/docker-service.js`) --- ### `ctx.caddy` (used by 12 routes) **Properties/Methods:** - `modify()` — modify Caddyfile - `read()` — read Caddyfile - `reload()` — reload Caddy - `generateConfig()` — generate route config - `verifySite()` — test site accessibility - `adminUrl`, `filePath` — config properties **Routes:** - apps/deploy.js, apps/helpers.js, apps/removal.js, apps/restore.js, apps/templates.js - config/backup.js, context.js - recipes/deploy.js, recipes/manage.js - services.js, sites.js, tailscale.js **Refactor Suggestion:** Extract to `services/caddy-service.js` --- ### `ctx.dns` (used by 9 routes) **Properties/Methods:** - `call()` — DNS API call - `buildUrl()` — construct DNS API URL - `requireToken()` — token validation - `ensureToken()` — auto-refresh token if needed - `createRecord()` — create DNS record - `getToken()`, `setToken()` — token management - `refresh()` — force token refresh **Routes:** - apps/deploy.js, apps/removal.js, apps/restore.js, apps/templates.js - config/backup.js, context.js, dns.js - services.js, sites.js **Refactor Suggestion:** Extract to `services/dns-service.js` --- ## Utility Functions (Universal Dependencies) ### `ctx.asyncHandler` (35 routes) **What it does:** Wraps async Express route handlers to catch errors **Current pattern:** ```javascript router.get('/endpoint', ctx.asyncHandler(async (req, res) => { // ... async logic })); ``` **Refactor suggestion:** Keep as utility, but import directly instead of via ctx ```javascript const { asyncHandler } = require('../utils/async-handler'); router.get('/endpoint', asyncHandler(async (req, res) => { // ... async logic })); ``` --- ### `ctx.log` (20 routes) **What it does:** Structured logger (log.info, log.error, log.warn) **Refactor suggestion:** Import logger utility directly ```javascript const log = require('../utils/logger'); ``` --- ### `ctx.errorResponse` (27 routes) **What it does:** Standard error response formatting **Refactor suggestion:** Utility function, import directly ```javascript const { errorResponse } = require('../utils/responses'); ``` --- ## Manager Objects ### `ctx.credentialManager` (12 routes) **What it does:** AES-256-GCM encrypted credential storage **Routes using it:** - arr/credentials.js, arr/detect.js, arr/helpers.js - auth/sso-gate.js, auth/totp.js - config/backup.js, credentials.js, dns.js - services.js, tailscale.js **Refactor suggestion:** Keep as manager, inject explicitly --- ### `ctx.servicesStateManager` (12 routes) **What it does:** Thread-safe services.json state management **Refactor suggestion:** Keep as manager, inject explicitly --- ### `ctx.healthChecker` (1 route: health.js) **Refactor suggestion:** Already well-isolated, just make explicit --- ## Configuration Objects ### `ctx.siteConfig` (10 routes) **What it does:** Site-wide configuration (domain, TLS, etc.) **Refactor suggestion:** Load once at app startup, inject where needed --- ### File path constants (used by 6 routes) - `SERVICES_FILE` (6 routes) - `CONFIG_FILE` (3 routes) - `TOTP_CONFIG_FILE` (1 route) - `NOTIFICATIONS_FILE` (1 route) - `ERROR_LOG_FILE` (1 route) **Refactor suggestion:** Move to `src/config/paths.js`, import directly --- ## Refactoring Strategy ### Phase 1: Low-Risk Routes (Start Here) Refactor simple routes with 1-5 dependencies: 1. `backups.js` (2 deps) 2. `containers.js` (3 deps) 3. `credentials.js` (3 deps) 4. `license.js` (3 deps) 5. `monitoring.js` (3 deps) **Why:** Low complexity, easier to verify correctness, builds confidence --- ### Phase 2: Extract Common Utilities Extract universal dependencies to standalone modules: 1. `utils/async-handler.js` (used by 35 routes) 2. `utils/responses.js` (errorResponse, ok, etc.) 3. `utils/logger.js` (structured logging) 4. `utils/http.js` (fetchT wrapper) **Why:** Reduces ctx bloat, makes imports explicit --- ### Phase 3: Extract Domain Services Convert domain objects to services: 1. `services/docker-service.js` (15 routes) 2. `services/caddy-service.js` (12 routes) 3. `services/dns-service.js` (9 routes) **Why:** Separate business logic from HTTP handlers, testable in isolation --- ### Phase 4: High-Complexity Routes Refactor routes with 10+ dependencies: 1. `services.js` (13 deps) — most-used route 2. `apps/deploy.js` (15 deps) — core deployment 3. `config/backup.js` (16 deps) — extract backup service 4. `sites.js` (12 deps) **Why:** Highest impact on maintainability --- ## Success Metrics ### Before Refactor - God object `ctx` with 50+ properties - Hidden dependencies (routes don't declare what they use) - Difficult to mock for testing (need entire ctx object) ### After Refactor - ✅ Routes declare explicit dependencies - ✅ Utilities imported directly (no ctx indirection) - ✅ Domain logic extracted to services - ✅ Easy to mock (inject only what's needed) - ✅ Self-documenting (route signature shows dependencies) --- ## Next Steps 1. ✅ Document current dependencies (this file) 2. Refactor Phase 1 routes (low-risk, 1-5 deps) 3. Extract utilities (asyncHandler, errorResponse, log) 4. Extract domain services (docker, caddy, dns) 5. Refactor high-complexity routes 6. Remove `ctx` god object entirely --- *Generated by analyzing route files for `ctx.*` usage patterns.*