Files
dashcaddy/dashcaddy-api/DEPENDENCIES.md
2026-03-22 11:01:40 +01:00

345 lines
9.4 KiB
Markdown

# 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.*