--- title: Backend Architecture tags: [architecture, backend] created: 2026-05-23 --- # Backend Architecture Module-level architecture of the Express 5 + TypeScript + Mongoose backend at `/Users/mojtabaheidari/code/backend` (development branch). > [!info] > Repo: `git@git.manko.yoga:222/nick/backend.git` · Branch: `development` · Version: 2.6.3-beta (`package.json:4`) --- ## 1. Folder tree ``` backend/src/ ├── app.ts # Express bootstrap, middleware chain, route registration ├── config/ # Per-feature config (legacy — most moved to shared/config) ├── controllers/ # HTTP request handlers (slim — delegate to services) ├── infrastructure/ │ ├── database/ # Mongoose connection, retries, graceful shutdown │ └── socket/socketService.ts # Socket.IO server, rooms, emit helpers ├── models/ # Mongoose models — see 02 - Data Models/ ├── routes/ # Express Router definitions (mounted in app.ts) ├── scripts/ # CLI utilities (seed:users, seed:categories, ...) ├── seeds/ # Seed data fixtures ├── services/ │ ├── ai/ # OpenAI integration (descriptions, moderation) │ ├── auth/ # JWT, OAuth, Passkey, password reset │ ├── blockchain/ # Web3 read/verify helpers │ ├── blog/ # Posts, categories, comments │ ├── chat/ # Conversations, messages, attachments │ ├── dispute/ # Dispute lifecycle, evidence, mediator │ ├── file/ # Multer uploads, MIME validation │ ├── marketplace/ # PurchaseRequest, SellerOffer, Template, Shop │ ├── notification/ # Templates, delivery, mark-as-read │ ├── payment/ # Payment orchestration + shkeeper/ subdir │ │ └── shkeeper/ # SHKeeper API, webhook, payout │ ├── points/ # Loyalty points, levels, redemption │ ├── redis/ # Redis client, cache helpers │ ├── user/ # Profile, preferences, addresses │ ├── admin/ # Admin-only operations │ └── email/ # Nodemailer transport + templates ├── shared/ │ ├── config/index.ts # Centralised env-var loader (typed) │ ├── middleware/ # auth, errorHandler, validators │ ├── types/ # Cross-cutting TypeScript types │ └── utils/response-handler.ts # Standard success/error response envelope └── utils/ # Pure utility fns (logger, currencyUtils, etc.) ``` > [!tip] > Service folders are self-contained: each typically has `Service.ts`, `Controller.ts`, `Routes.ts`, `Validation.ts`. This makes each service movable to a microservice later with minimal coupling. --- ## 2. Bootstrap — `src/app.ts` The bootstrap is intentionally linear and easy to audit. Execution order: 1. **Imports & env load** — `dotenv` (if used), then `import { config } from './shared/config'`. 2. **Express app construction** — `const app = express();` 3. **Trust proxy** — `app.set('trust proxy', config.trustProxy)` so X-Forwarded-For works behind Nginx. 4. **Security headers** — `app.use(helmet({ ... }))`. 5. **CORS** — `cors({ origin: config.frontendUrl, credentials: true, methods: [...] })`. 6. **Body parsers** — `express.json({ limit: '10mb' })`, `express.urlencoded({ extended: true })`. 7. **Static uploads** — `app.use('/uploads', express.static(uploadDir))`. 8. **Health endpoint** — `GET /health` for Docker healthcheck and external monitors. 9. **Route mounting** — every `/api/*` route registered before the error handler. 10. **404 handler** — catches unmatched `/api/*`. 11. **Error handler** — central `errorHandler` middleware formats responses via `response-handler.ts`. 12. **HTTP server creation** — `const server = http.createServer(app)`. 13. **Socket.IO attach** — `initSocket(server, corsOptions)` (see [[Real-time Layer]]). 14. **DB connect** — `await connectDatabase()`. 15. **Redis connect** — `await connectRedis()`. 16. **Listen** — `server.listen(config.port, ...)`. 17. **Graceful shutdown** — SIGTERM/SIGINT handlers close server, drain sockets, close Mongoose, close Redis. 18. **Optional dev seeding** — when `NODE_ENV === 'development'` and `SEED_USERS !== 'false'`, the bootstrap calls the seed scripts to provision default test users. --- ## 3. Middleware chain | Order | Middleware | Where | Purpose | |---|---|---|---| | 1 | `helmet` | global | Sets security headers (CSP, X-Frame-Options, ...). | | 2 | `cors` | global | Origin allow-list = `config.frontendUrl`, credentials enabled. | | 3 | `express.json` / `express.urlencoded` | global | Body parsers (10MB limit). | | 4 | `morgan` (dev only) | global | HTTP request log to stdout. | | 5 | `requestId` | global | Adds `X-Request-Id` for log correlation. | | 6 | `authMiddleware` | per-route | Verifies JWT, attaches `req.user`. Mounted only on protected routes. | | 7 | `roleGuard('admin'|'seller'|...)` | per-route | RBAC check after auth. | | 8 | `validate(schema)` | per-route | express-validator + zod inputs. | | 9 | `controllerFn` | per-route | Delegates to service layer. | | 10 | `notFound` | tail | Returns 404 envelope for unmatched routes. | | 11 | `errorHandler` | tail | Catches thrown errors, formats response. | > [!warning] > Rate-limit middleware is **disabled by default for personal use** (see `app.ts:227` cited in the architecture review). Enable before any real public traffic — `express-rate-limit` is already a dependency. --- ## 4. Route registration The full route table mounted by `app.ts`: | Mount path | Module | Auth | Notes | |---|---|---|---| | `/api/auth` | `services/auth/authRoutes.ts` | mixed | login, register, refresh, OAuth, passkey | | `/api/user` | `services/user/userRoutes.ts` | JWT | profile, preferences | | `/api/address` | `services/user/addressRoutes.ts` | JWT | CRUD addresses | | `/api/marketplace/requests` | `services/marketplace/controllerRoutes.ts` | JWT | PurchaseRequest CRUD | | `/api/marketplace/offers` | `services/marketplace/controllerRoutes.ts` | JWT (seller) | SellerOffer CRUD | | `/api/marketplace/templates` | `services/marketplace/controllerRoutes.ts` | JWT (seller) | RequestTemplate CRUD | | `/api/marketplace/categories` | `services/marketplace/controllerRoutes.ts` | public read | Category list | | `/api/marketplace/shop-settings` | `services/marketplace/shopSettingsController.ts` | JWT (seller) | Shop profile | | `/api/payment` | `services/payment/paymentRoutes.ts` | JWT | Payment intent, status | | `/api/payment/shkeeper/webhook` | `services/payment/shkeeper/shkeeperWebhook.ts` | HMAC | Inbound from gateway | | `/api/payment/payout` | `services/payment/shkeeper/shkeeperPayoutService.ts` | JWT (seller/admin) | Withdraw to wallet | | `/api/chat` | `services/chat/chatRoutes.ts` | JWT | Conversations, messages | | `/api/notification` | `services/notification/notificationRoutes.ts` | JWT | List, mark read | | `/api/dispute` | `services/dispute/disputeRoutes.ts` | JWT | Open, evidence, resolve | | `/api/blog` | `services/blog/blogRoutes.ts` | mixed | Public read, admin write | | `/api/admin` | `services/admin/adminRoutes.ts` | JWT (admin) | Mod operations | | `/api/points` | `services/points/pointsRoutes.ts` | JWT | Balance, redemption | | `/api/ai` | `services/ai/aiRoutes.ts` | JWT | OpenAI-backed helpers | | `/api/file` | `services/file/fileRoutes.ts` | JWT | Multipart upload | Full per-endpoint details → [[03 - API Reference/API Overview]] and the service-specific reference docs. --- ## 5. Service layer pattern Every service module follows this contract: ```ts // services//Service.ts export class FeatureService { static async createX(input, ctx): Promise { /* business logic */ } static async getX(id, ctx): Promise { /* ... */ } static async listX(filter, ctx): Promise { /* ... */ } static async updateX(id, patch, ctx): Promise { /* ... */ } } ``` - Controllers are **thin** — they validate request shape, call the service, format the response. - Services own **business logic**, side effects (DB writes, socket emits, email sends). - Models are **pure schema** — only Mongoose definitions + virtuals/hooks. Cross-service calls are direct imports — no event bus yet. When the system grows, the seam between services is a natural place to introduce a message queue. --- ## 6. Dependency map (simplified) ```mermaid flowchart TB auth[auth] user[user] market[marketplace] pay[payment] chat[chat] notify[notification] dispute[dispute] points[points] file[file] email[email] socket[socket] auth --> user auth --> notify market --> notify market --> chat market --> file pay --> market pay --> notify pay --> socket dispute --> market dispute --> chat dispute --> notify points --> notify notify --> socket notify --> email ``` > [!note] > `socket` and `email` are leaf services — every notification path funnels through them. Mocking these two in tests covers most side-effect verification. --- ## 7. Error handling All thrown errors are caught by the central error handler. The expected shape: ```ts class AppError extends Error { statusCode: number; // HTTP 4xx/5xx code: string; // app-specific code, e.g. "PAYMENT_ALREADY_REFUNDED" details?: unknown; // optional debug payload } ``` Response envelope (success path is `{success:true,data:...}`): ```json { "success": false, "error": { "code": "VALIDATION_FAILED", "message": "email is required", "details": [{ "path": "email", "msg": "required" }] } } ``` See `backend/src/shared/utils/response-handler.ts` and `backend/src/shared/middleware/errorHandler.ts`. --- ## 8. Configuration Single source of truth for env vars: `src/shared/config/index.ts`. It exports a typed `config` object — anywhere you would write `process.env.X`, instead import `config.x`. Full table in [[Environment Variables]]. Critical ones: | Key | Default | Notes | |---|---|---| | `PORT` | `5001` | Listen port | | `MONGODB_URI` | `mongodb://localhost:27017/nickapp` | Includes db name | | `REDIS_URI` | `redis://localhost:6379` | + `REDIS_PASSWORD` | | `JWT_SECRET` | required | ≥32 chars | | `JWT_EXPIRES_IN` | `7d` | | | `REFRESH_TOKEN_EXPIRES_IN` | `30d` | | | `FRONTEND_URL` | `http://localhost:3000` | CORS origin | | `SHKEEPER_API_URL` | `https://pay.amn.gg` | | | `SHKEEPER_API_KEY` | required | | | `SHKEEPER_WEBHOOK_SECRET` | required | HMAC key | | `SMTP_*` | required | Nodemailer | | `OPENAI_API_KEY` | required | | --- ## 9. Database & connection management - **Mongoose** is the ODM. Connection in `src/infrastructure/database/`. - Connection options enable retryable writes, exponential backoff on reconnect. - Indexes are defined on each model and auto-created on connect (Mongoose `autoIndex: true` in dev, recommend `false` in prod with explicit migration). - See [[Data Model Overview]] for the relational map and per-model docs. Redis client (in `src/services/redis/`) provides: - Session caching (login attempts, lockout counters) - Rate-limit counters (when middleware is enabled) - Hot-path caches (category list, level configs) --- ## 10. Background work The codebase has no dedicated queue runner — scheduled / async work is triggered inline from request handlers and uses `setTimeout` / `setInterval` patterns where needed (e.g., delayed retries). Consider introducing Bull / BullMQ if you grow: - Payment status reconciliation (polling SHKeeper for stragglers) - Notification email digests - Auto-release escrow timers - Token / refresh-token cleanup --- ## 11. Testing Jest test suites in `backend/__tests__/`: | File | Covers | |---|---| | `models.test.ts` | Schema validation, virtuals, hooks | | `payment-services.test.ts` | Payment orchestration logic | | `complete-backend.test.ts` | Cross-service integration | | `shkeeper-backend.test.ts` | SHKeeper service + webhook | Run with `npm run test:all`. CI runs the same. Reach for `npm run test:models`, `npm run test:payment`, etc. when iterating on a slice. --- ## 12. Notable files for orientation | File | Why it matters | |---|---| | `src/app.ts` | Bootstrap — read once to understand wiring | | `src/shared/config/index.ts` | All env vars, typed | | `src/shared/utils/response-handler.ts` | Standard response shape | | `src/shared/middleware/auth.ts` | JWT verify + RBAC | | `src/infrastructure/socket/socketService.ts` | All socket plumbing | | `src/services/payment/shkeeper/shkeeperWebhook.ts` | Webhook signature scheme | | `src/services/marketplace/PurchaseRequestService.ts` | Core marketplace state machine | | `src/services/auth/authService.ts` | Auth flows, lockout, hashing | | `src/models/User.ts` | Central entity with role/preferences | | `openapi.json` | Generated API spec — definitive endpoint list | --- ## Related - [[System Architecture]] — full system topology - [[Frontend Architecture]] — how the FE talks to this BE - [[Real-time Layer]] — Socket.IO room model - [[Security Architecture]] — JWT, passkeys, webhook HMAC - [[Data Model Overview]] — entity-relationship map - [[Authentication Flow]] · [[Payment Flow - SHKeeper]] · [[Dispute Flow]]