# E Xode Vue Ssr Vue Ssr Server

> Vue SSR Server (Backend: Express 5 + MongoDB)

- Skill: `tomevault-io/e-xode-vue-ssr-vue-ssr-server` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tomevault-io/e-xode-vue-ssr-vue-ssr-server`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tomevault-io/e-xode-vue-ssr-vue-ssr-server/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: tomevault-io (https://skillmd.com/u/tomevault-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tomevault-io/e-xode-vue-ssr-vue-ssr-server

---


# Vue SSR Server (Backend: Express 5 + MongoDB)

> Owns Express 5 API route mechanics and MongoDB data access. Auth domain logic → `vue-ssr-auth`; file structure/SSR lifecycle → `vue-ssr-architecture`. Security guardrails live in rule `server-security`; error/ObjectId handling in rule `api-error-handling`.

## Server entry (`server.js`)

Boot order: `mongoConnect()` → `ensureIndexes(db)` → `express()` → `helmet` → (prod) rate limits → `session` → `cors` → `express.json()` → API router → SSR catch-all. The API is mounted via `createApiRouter(db)`: in dev through `vite.ssrLoadModule('/src/api/router.js')`, in prod via static import.

## Route-module pattern

Each endpoint is a file exporting `setupXRoute(app, db)`:

```javascript
import { getUserWithCounts } from '#src/shared/dbHelpers.js';

export function setupMeRoute(app, db) {
  app.get('/api/auth/me', async (req, res) => {
    try {
      const user = await getUserWithCounts(db, req.session.userId);
      res.json({ user });
    } catch (err) {
      console.error('Me endpoint error:', err);
      res.status(500).json({ error: 'error.server' });
    }
  });
}
```

- Register the setup function inside `createApiRouter(db)` in `router.js`.
- Error `error` fields are i18n keys (`error.server`, `error.unauthorized`) resolved client-side.
- The try/catch → `console.error` → 500 shape is mandatory — see rule `api-error-handling`.

## Folder map

```
src/api/
  router.js        createApiRouter(db) + per-endpoint limiters
  middleware.js    setMiddlewareDb, requireAuth, requireAdmin
  auth/            signin, signup, signout, me, verifyCode, ... (setupXRoute)
  admin/           users, logs (admin-guarded)
  contact/         send
```

## Middleware guards (`src/api/middleware.js`)

- `requireAuth` — 401 if no `req.session.userId`; sets `req.userId` (ObjectId); destroys session + 403 if `user.isBlocked`.
- `requireAdmin(db)` — factory middleware; 403 unless `user.type === 'admin'`.
- `setMiddlewareDb(db)` — call once from `createApiRouter` before `requireAuth` is used.

```javascript
app.get('/api/admin/users', requireAdmin(db), async (req, res) => { ... });
```

## MongoDB access

- Single shared client from `src/shared/mongo.js`: `mongoConnect()` returns `{ db, error }`; `mongoClose()` on shutdown.
- Inject the existing `db` into every route — never open a client per request.
- Validate ids with `parseObjectId(str)` from `src/shared/dbHelpers.js` (returns ObjectId or null) before any `_id` query.
- `parsePagination(req.query)` for list endpoints; richer accessors (e.g. `getUserWithCounts(db, id)`) live in `dbHelpers.js`.
- Indexes are declared in `ensureIndexes(db)` in `server.js` (users.email unique, blockedIps.ip unique, logs).

## Rate limiting (`src/api/router.js`)

`createLimiter(max)` returns a real limiter in production and a pass-through in dev. Pre-built: `signupLimiter` (5), `authLimiter` (10), `accountLimiter` (20), `contactLimiter` (3). Mount before the route via `router.use('/api/...', limiter)`. Global + `/api/` ceilings (production only) live in `server.js`.

## Server-only shared utilities

- `src/shared/email.js` — nodemailer transporter, security-code email (uses `node:crypto`).
- `src/shared/security.js` — file-based helpers (`node:fs`/`node:path`).
- `src/shared/captcha.js` — reCAPTCHA v3 verification.
- `src/shared/log.js` — `logInfo`/`logWarn` structured logging.

These are server-only — never import them from client code (rule `client-server-boundary`). Auth-specific logic (security-code generation, hashing, sessions, captcha flow): see skill `vue-ssr-auth`.

---
> Source: [e-xode/vue-ssr](https://github.com/e-xode/vue-ssr) — distributed by [TomeVault](https://tomevault.io).
<!-- tomevault:4.0:skill_md:2026-06-02 -->

