Skip to content

Latest commit

 

History

History
99 lines (69 loc) · 5.15 KB

File metadata and controls

99 lines (69 loc) · 5.15 KB

Server

Backend package: Fastify HTTP API, Socket.IO, MySQL via mysql2. Runtime configuration and local development are described in the repository README.


Features

The server owns all authoritative business rules and persistence. The browser and Laverna only send requests and socket events; validation on the wire is enforced here again even when the client also checks inputs.

Domain coverage

Domain Scope
Authentication Registration, login, token refresh and logout; email verification and password reset; JWT access and refresh cookies
Profiles Profile data, tags, location, image upload (validation on type, size, aspect ratio)
Discovery Browse and search with filters; parameterized SQL
Social Likes, matches, blocks, reports; notifications
Realtime Socket.IO path /api/socket.io; chat constrained to matches
Operations SQL migrations at startup; seeds; script seed:profiles

JSON request and response shapes for routes are defined alongside the client in @matcha/shared so both sides stay aligned.

Security and validation

Configuration and HTTP

  • Environment variables are validated at startup (Zod); invalid config exits before listen.
  • One allowed CORS origin; credentialed requests enabled.
  • Request bodies use shared JSON schemas; extra sanitization on free text where needed.

Sign-in and JWT cookies

  • Login with email or username + password (bcrypt). No tokens until email is verified.
  • After login: access JWT (short-lived) + refresh JWT (long-lived), both in httpOnly cookies, sameSite: lax, secure in production.
  • Access cookie path is / so the browser also sends it to Socket.IO on another port; refresh cookie stays under the API path.
  • Refresh rotation: each refresh exchanges the refresh JWT for a new one; old refresh rows are revoked (JTI tracked in the database).
  • Reuse: presenting an already-revoked refresh token revokes all refresh tokens for that user (session invalidation across devices).
  • Logout revokes the current refresh row; logout all revokes every refresh row for the user.

Calling authenticated APIs

  • Access JWT: Authorization: Bearer … or access cookie (same token).
  • Socket.IO: same access JWT via handshake or cookies (no secrets in frontend code).

Passwords and identifiers

  • Passwords: bcrypt; strength checked with zxcvbn on register / reset / change.
  • Email verification and password-reset tokens stored hashed (bcrypt compare).
  • Public UUID-shaped ids in URLs instead of numeric database ids.

Blocks, matches, and limits

  • Routes that target another user respect blocks.
  • Match-only actions require membership in that match (e.g. chat).
  • Rate limits: IP + route counters in MySQL, HTTP 429 when over budget — only in production (disabled locally).

Uploads, email, reputation

  • Images: multipart size cap, MIME allowlist, aspect ratio check, max photos per user.
  • Mail: nodemailer; dev may use test inboxes / log links; production needs SMTP in env.
  • Fame (0–100): blended score from views, likes, matches, unlikes, reports, blocks.
  • Reports: fixed reasons, optional description (sanitized, length-capped); admins can act on pending reports.

File structure

Entry point is src/index.ts: loads configuration, runs migrations, may trigger seeding, then starts Fastify and attaches Socket.IO to the same HTTP server instance. src/app.ts builds the Fastify app (plugins, routes, error handler) and creates the Socket.IO server with CORS aligned to the REST API.

server/
├── src/
│   ├── app.ts              # Fastify + Socket.IO bootstrap
│   ├── index.ts            # process entry, migrations, listen
│   ├── routes/             # route modules (auth, profiles, discovery, socials, notifications, …)
│   ├── middlewares/      # authGuard, blockGuard, matchGuard, rateLimit, password strength
│   ├── socket/             # socket auth, chat handlers, match helpers
│   ├── config/             # envSchema (Zod), constant.ts
│   ├── db/                 # migrate.ts, seed.ts
│   └── utils/              # MySQL pool, sanitizers, UUID mapping, reply helpers
├── migration/              # versioned SQL files
└── scripts/                # seedProfiles, resetDb, …

Routes are grouped by domain under routes/ (for example authentication/, profiles/, discovery/, socials/). Shared cross-cutting behavior lives in middlewares/ and is composed per route as Fastify preHandler or preValidation hooks. Socket concerns stay under socket/ so connection lifecycle is separate from REST handler files.


Database

Migrations apply automatically when the server starts. For a full reset during development, use the script from the server/ directory.

Command Description
pnpm db:reset Drop and recreate database, apply migrations
pnpm seed:profiles Run standalone profile seed

Schema and seed content are defined in migration/ and src/db/seed.ts.