Phase 1: Add dependency analysis documentation
This commit is contained in:
344
dashcaddy-api/DEPENDENCIES.md
Normal file
344
dashcaddy-api/DEPENDENCIES.md
Normal file
@@ -0,0 +1,344 @@
|
|||||||
|
# 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.*
|
||||||
Reference in New Issue
Block a user