In this lesson we demonstrate how to audit a small Express (Node.js) project for software design, modularity, and architectural issues using Claude Code. The aim is a structured findings report with concrete, code-level remediation you can apply incrementally.

audits/SOFTWARE_DESIGN_ARCHITECTURE_ANALYSIS.md. The cleaned and consolidated version of that report follows.
Project: Express Login Demo
Executive summary
Overall Architecture Score: 4/10 This Express Login Demo exhibits a minimal MVC-inspired structure but contains significant design and operational shortcomings. Business logic is embedded in route handlers, there’s limited abstraction, and the app lacks centralized error handling and input validation. These problems raise technical debt and make the code harder to test, secure, and scale.Architecture analysis
1. Architectural pattern assessment
Pattern identified: Minimal MVC-like structure- Model: PostgreSQL integration via
config/database.js - View: JSON API responses
- Controller: Route handlers in
routes/auth.js
- Business logic and data access are mixed into route handlers.
- No service or repository layer is present.
- DB config is separated (positive).
2. Project structure
routes/auth.js. No migrations, no distinct repositories or service abstractions.
3. Data flow (high-level)
- HTTP request →
routes/auth.js(validation, DB queries, auth logic) →config/database.js→ PostgreSQL - Missing: service layer, caching, rate limiting, centralized logging, and centralized error handling
- Single DB pool without explicit connection limits
- Blocking synchronous crypto (if used) can stall the Node event loop
- No caching — every request hits the database
- No rate limiting — auth endpoints exposed to brute-force attempts
Anti-patterns identified
-
God object / God module (Severity: 8/10)
- Location:
routes/auth.js - Symptom: One file handles routing, validation, business logic, and DB access.
- Impact: Hard to test and maintain.
- Location:
-
Primitive obsession (Severity: 6/10)
- Location:
routes/auth.js— raw SQL and primitive payload handling. - Example:
- Remediation: Introduce repositories/models and token services.
- Location:
-
Copy-paste programming (Severity: 5/10)
- Location:
routes/auth.js - Symptom: Repeated error response patterns and duplicated logic.
- Remediation: Centralize error responses with middleware.
- Location:
-
Tight coupling (Severity: 7/10)
- Location: Route handlers
requireDB, bcrypt, and jwt directly. - Symptom: Hard to unit test and mock dependencies.
- Remediation: Use dependency injection via factories.
- Location: Route handlers
-
Missing input validation/sanitization (Severity: 6/10)
- Location:
routes/auth.js - Symptom: No robust validation (consider
express-validator). - Remediation: Add validation middleware.
- Location:
Detailed findings
High priority issues
Medium priority issues
Low priority issues
Recommended architecture improvements
Layered architecture (conceptual)
Proposed directory structure
Dependency flow (text diagram)
Concrete remediations (drop-in examples)
Below are small, focused code patterns to reduce coupling, improve testability, and add defenses.- Auth service (move business logic out of routes):
- Repository abstraction for data access:
- Use a factory to wire routes with injected services:
- Input validation middleware using express-validator:
- Centralized error handler:
- Token service:
Security & operational recommendations
- Sanitize and validate all inputs (e.g., express-validator).
- Always use parameterized queries (prepared statements) to prevent SQL injection.
- Run CPU-bound crypto (bcrypt) using async APIs; consider background workers for heavy tasks.
- Protect auth endpoints with rate limiting (express-rate-limit).
- Implement structured logging (pino or winston) and attach correlation IDs to requests.
- Add health and readiness endpoints for orchestration tooling.
- Implement graceful shutdown to drain DB/pool connections on SIGTERM/SIGINT.
Final assessment and next steps
- Current state: Functional but with high architectural debt.
- Technical debt: High — refactoring required for scale and maintainability.
-
Immediate actions:
- Extract services and repositories from route handlers.
- Add global error handling middleware and an AppError pattern.
- Add input validation and sanitization.
- Introduce DI/factory functions to decouple dependencies.
- Implement structured logging and basic operational endpoints.
-
Long-term:
- Migrate to a layered architecture with clear responsibilities.
- Add automated tests (unit + integration).
- Add configuration management and environment-driven settings.
- Integrate observability: metrics & tracing.
Links and references
- express-validator: https://express-validator.github.io/docs/
- pino (structured logging): https://getpino.io/
- winston: https://github.com/winstonjs/winston
- express-rate-limit: https://www.npmjs.com/package/express-rate-limit
- JSON Web Tokens (JWT): https://jwt.io/
- Node.js best practices & architecture: https://nodejs.org/en/docs/ (general guidance)