# STAR Phase 1 — Tier 1 Auth System ## Technical Documentation **Version:** 1.0.0 **Author:** rgrgogu **Date:** October 6, 2025 **Stack:** Node.js · Express · Sequelize (PostgreSQL) · JWT · Google OAuth 2.0 · Nodemailer --- ## Table of Contents 1. [Architecture Overview](#1-architecture-overview) 2. [Project Structure](#2-project-structure) 3. [Setup & Installation](#3-setup--installation) 4. [Environment Variables](#4-environment-variables) 5. [Database Models](#5-database-models) 6. [Security Layers](#6-security-layers) 7. [Authentication Flows](#7-authentication-flows) 8. [API Reference](#8-api-reference) 9. [RBAC Permission Matrix](#9-rbac-permission-matrix) 10. [File-by-File Documentation](#10-file-by-file-documentation) 11. [Error Codes Reference](#11-error-codes-reference) 12. [Extending the System](#12-extending-the-system) --- ## 1. Architecture Overview ``` ┌─────────────────────────────────────────────────────────────────┐ │ Client (SPA / Mobile / Browser) │ └────────────────────────────┬────────────────────────────────────┘ │ HTTPS ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Express.js App (server.js) │ │ │ │ ┌──────────┐ ┌───────────┐ ┌────────────┐ ┌────────────┐ │ │ │ CORS │ │ Rate Limit│ │ Cookie │ │ Session │ │ │ │ Guard │ │ (global) │ │ Parser │ │ (csurf) │ │ │ └──────────┘ └───────────┘ └────────────┘ └────────────┘ │ │ │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ Routes │ │ │ │ /api/auth/* → auth.routes.js │ │ │ │ /api/client/* → client.routes.js │ │ │ │ /api/staff/users/*→ staff.routes.js │ │ │ │ /api/admin/* → admin.routes.js │ │ │ └──────────────────────────────────────────────────────────┘ │ │ │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ Middleware Chain (per-route) │ │ │ │ authLimiter → csrfProtection → validate → authenticate │ │ │ │ → requireRole() → Controller │ │ │ └──────────────────────────────────────────────────────────┘ │ │ │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ Services │ Utils │ │ │ │ email.service.js │ token.util.js │ │ │ │ │ otp.util.js │ │ │ │ │ response.util.js │ │ │ └──────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────┬───────────────────────┘ │ Sequelize ORM ▼ ┌─────────────────────────────────────────────────────────────────┐ │ PostgreSQL │ │ ┌──────────┐ ┌─────────────────┐ ┌──────────────────────┐ │ │ │ users │ │ user_sessions │ │ user_groups / │ │ │ │ │ │ │ │ user_group_members │ │ │ └──────────┘ └─────────────────┘ └──────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ``` --- ## 2. Project Structure ``` new_starr/ ├── server.js ← App entry point ├── package.json ├── .env-development ← Local dev template — copy to .env ├── .env-production ← Self-hosted/Docker template — copy to .env │ ├── config/ │ ├── db.config.js ← Sequelize PostgreSQL instance │ └── passport.config.js ← Google OAuth 2.0 strategy │ ├── models/ │ ├── users.mdl.js ← Users table (with OTP fields) │ ├── user_sessions.mdl.js ← Session audit table │ └── user_groups.mdl.js ← Groups + Junction table │ ├── middleware/ │ ├── auth.middleware.js ← JWT Bearer token verification │ ├── rbac.middleware.js ← Role-based access guards │ ├── csrf.middleware.js ← CSRF protection (csurf) │ ├── rateLimiter.middleware.js ← Per-route rate limits │ └── validate.middleware.js ← express-validator result handler │ ├── validators/ │ ├── auth.validator.js ← register / login / OTP / password rules │ └── profile.validator.js ← profile update rules │ ├── controllers/ │ ├── auth.controller.js ← Shared: register, OTP, login, refresh, logout │ ├── client/ │ │ └── profile.controller.js ← Own profile + own sessions │ ├── staff/ │ │ └── users.controller.js ← View/toggle non-admin users │ └── admin/ │ └── users.controller.js ← Full CRUD + groups │ ├── routes/ │ ├── auth.routes.js ← /api/auth/* │ ├── client/ │ │ └── client.routes.js ← /api/client/* │ ├── staff/ │ │ └── staff.routes.js ← /api/staff/users/* │ └── admin/ │ └── admin.routes.js ← /api/admin/* │ ├── services/ │ └── email.service.js ← Nodemailer OTP + welcome emails │ └── utils/ ├── token.util.js ← JWT generate / verify / hash ├── otp.util.js ← OTP generate / expiry / check └── response.util.js ← Standardised JSON responses ``` --- ## 3. Setup & Installation ```bash # 1. Clone / copy the project cd star-auth-system # 2. Install dependencies npm install # 3. Configure environment cp .env-development .env # Edit .env with your DB, SMTP, Google OAuth, and JWT credentials # (For a production/self-hosted deploy, use .env-production instead — see docker-compose.yml) # 4. Ensure PostgreSQL is running and the DB exists createdb star_db # 5. Start development server (auto-syncs models) npm run dev # 6. Production npm start ``` > **Note:** On first boot, Sequelize will create all tables automatically via `sequelize.sync({ alter: true })`. --- ## 4. Environment Variables | Variable | Description | Example | |---|---|---| | `APP_NAME` | Application name | `starr` | | `NODE_ENV` | `development` or `production` | `development` | | `ORIGIN_GUARD_DISABLED` | Set `true` to bypass originGuard (dev/Postman only; ignored in production) | `false` | | `PORT` | HTTP port | `3000` | | `APP_URL` | Frontend/app URL (used for CORS) | `http://localhost:3000` | | `DB_HOST` | PostgreSQL host | `localhost` | | `DB_PORT` | PostgreSQL port | `5432` | | `DB_NAME` | Database name | `star_db` | | `DB_USER` | DB user | `postgres` | | `DB_PASSWORD` | DB password | `yourpassword` | | `JWT_SECRET` | Access token signing key (≥32 chars) | `your_super_secret_…` | | `JWT_EXPIRES_IN` | Access token TTL | `1d` | | `JWT_REFRESH_SECRET` | Refresh token signing key | `your_refresh_secret_…` | | `JWT_REFRESH_EXPIRES_IN` | Refresh token TTL | `7d` | | `SESSION_SECRET` | Express session secret (used by csurf) | `your_session_secret_…` | | `GOOGLE_CLIENT_ID` | Google OAuth client ID | from GCP Console | | `GOOGLE_CLIENT_SECRET` | Google OAuth client secret | from GCP Console | | `GOOGLE_CALLBACK_URL` | OAuth redirect URI | `/api/auth/google/callback` | | `SMTP_HOST` | Mail server host | `smtp.gmail.com` | | `SMTP_PORT` | Mail server port | `587` | | `SMTP_USER` | Mail username | `you@gmail.com` | | `SMTP_PASS` | Mail password / App Password | `xxxx xxxx xxxx xxxx` | | `EMAIL_FROM` | Sender address | `no-reply@star-system.com` | | `OTP_EXPIRY_MINUTES` | OTP validity in minutes | `10` | --- ## 5. Database Models ### 5.1 `users` Table | Column | Type | Notes | |---|---|---| | `user_id` | BIGINT PK | Auto-increment | | `email` | VARCHAR(255) UNIQUE | Validated email | | `password` | TEXT | bcrypt hash (null for Google users) | | `is_active` | BOOLEAN | Default `true` | | `is_verified` | BOOLEAN | Default `false`; set `true` on OTP verify | | `reg_type` | ENUM | `system` or `google` | | `acc_type` | ENUM | `user` / `staff` / `admin` | | `personal_info` | JSONB | Nested name, addresses, phone, avatar, album | | `otp_code` | VARCHAR(6) | Cleared after verification | | `otp_expires_at` | TIMESTAMP | Cleared after verification | | `createdAt` | TIMESTAMP | Auto | | `updatedAt` | TIMESTAMP | Auto | ### 5.2 `user_sessions` Table | Column | Type | Notes | |---|---|---| | `session_id` | BIGINT PK | Auto-increment | | `user_id` | BIGINT FK | → users.user_id | | `login_info` | JSONB | `{ date, ip_address, device_info }` | | `logout_info` | JSONB | Populated on logout | | `refresh_token_hash` | TEXT | SHA-256 of refresh token | | `is_active` | BOOLEAN | `false` after logout | ### 5.3 `user_groups` + `user_group_members` Tables Groups are named permission bundles. A user can belong to multiple groups. ``` users ──< user_group_members >── user_groups (user_id, group_id, joined_at) ``` --- ## 6. Security Layers ### 6.1 Rate Limiting | Limiter | Routes | Window | Max | |---|---|---|---| | `globalLimiter` | All routes | 15 min | 1 000 | | `authLimiter` | `/register`, `/login` | 15 min | 20 | | `otpLimiter` | `/verify-otp`, `/resend-otp` | 15 min | 5 | | `sensitiveOpsLimiter` | `/change-password` | 60 min | 10 | ### 6.2 CSRF Protection CSRF is provided via **csurf** (Double Submit Cookie pattern). - Retrieve token: `GET /api/auth/csrf-token` - Send token: `X-CSRF-Token` header OR `_csrf` body field - Applied automatically to cookie-based flows > **SPA / REST API clients using `Authorization: Bearer` are inherently CSRF-safe** because cross-site requests cannot set custom headers. CSRF is included for hybrid/SSR scenarios. ### 6.3 JWT Authentication - **Access Token:** Short-lived (1 day). Sent as `Authorization: Bearer `. - **Refresh Token:** Long-lived (7 days). SHA-256 hash stored in `user_sessions`. Rotated on every `/refresh` call. - **Session invalidation:** Logout, password change, and admin force-terminate all flip `is_active = false`. ### 6.4 Password Security - bcryptjs with **cost factor 12** - Minimum 8 chars, must contain uppercase + digit - Current password required before change - All sessions invalidated after password change ### 6.5 Origin Guard All API routes (except `/api/health`) are protected by `originGuard.middleware.js`, a two-layer non-browser request filter: | Layer | Header checked | Applies to | Blocks | |---|---|---|---| | 1 | `Sec-Fetch-Site` (must be present) | All methods | curl, Postman, Nikto, sqlmap, scanners | | 2 | `Origin` (must be in `ALLOWED_ORIGINS`) | POST · PUT · PATCH · DELETE | Cross-origin mutation from unlisted domains | **Development bypass** — set `ORIGIN_GUARD_DISABLED=true` in `.env` to allow Postman and other tools through without restarting with a different config. The bypass is **hard-locked off** when `NODE_ENV=production`, even if the flag is set. ``` # .env — enable for Postman testing ORIGIN_GUARD_DISABLED=true # .env — re-enable when done ORIGIN_GUARD_DISABLED=false ``` > Note: BurpSuite running as a MITM proxy through a real browser is not blocked — the browser supplies all correct headers. Rate limiting and valid credentials are the only defences there. --- ### 6.6 RBAC Hierarchy ``` admin ──► can do everything │ staff ──► can view/toggle client+staff users; cannot touch admin accounts │ user ──► can only manage own profile and sessions (client) ``` --- ## 7. Authentication Flows ### 7.1 System Registration → OTP Verify → Auto-Login ``` Client Server Email │ │ │ │── POST /api/auth/register ──► │ │ │ { email, password } │ │ │ │── create user (unverified)│ │ │── generate OTP ──────────►│ │◄── 201 { email } ─────────── │ │ │ │ │ │── POST /api/auth/verify-otp ►│ │ │ { email, otp } │ │ │ │── validate OTP │ │ │── mark is_verified=true │ │ │── create session record │ │ │── send welcome email ────►│ │◄── 200 { accessToken, │ │ │ refreshToken, │ │ │ user } ─────────── │ │ ``` ### 7.2 System Login ``` Client Server │── POST /api/auth/login ─────►│ │ { email, password } │ │ │── lookup user by email │ │── bcrypt.compare(password, hash) │ │── create session record │◄── 200 { accessToken, │ │ refreshToken, │ │ session_id, user } ──│ ``` ### 7.3 Google OAuth ``` Client Google Server │── GET /api/auth/google ──────────────►│ │ │── redirect to Google │◄─────── Google consent screen ───────│ │── approve ──►[Google] ───callback──► │ │ │── find or create user │ │── create session │◄── 200 { accessToken, refreshToken } ─│ ``` ### 7.4 Token Refresh ``` Client Server │── POST /api/auth/refresh ───►│ │ { refreshToken } │ │ │── verify JWT signature │ │── lookup session by token hash │ │── rotate refresh token │◄── 200 { accessToken, │ │ refreshToken } ─────│ ``` ### 7.5 Logout ``` Client Server │── POST /api/auth/logout ────►│ │ Authorization: Bearer ... │ │ { session_id } │ │ │── authenticate JWT │ │── set session.is_active=false │ │── save logout_info │◄── 200 "Logged out" ─────── │ ``` --- ## 8. API Reference > **Base URL:** `http://localhost:3000/api` > **Auth header:** `Authorization: Bearer ` --- ### 8.1 Auth Endpoints (Public) #### `POST /auth/register` Register a new client account. **Request body:** ```json { "email": "jane@example.com", "password": "Password1" } ``` **Response 201:** ```json { "status": "success", "message": "Registration successful. Please check your email for the OTP.", "data": { "email": "jane@example.com" } } ``` --- #### `POST /auth/verify-otp` Verify email with OTP. Returns tokens (auto-login). **Request body:** ```json { "email": "jane@example.com", "otp": "048291" } ``` **Response 200:** ```json { "status": "success", "message": "Email verified successfully. You are now logged in.", "data": { "accessToken": "eyJ...", "refreshToken": "eyJ...", "session_id": 1, "user": { "user_id": 1, "email": "jane@example.com", "acc_type": "user", ... } } } ``` --- #### `POST /auth/resend-otp` Resend OTP email (5 requests / 15 min limit). **Request body:** `{ "email": "jane@example.com" }` --- #### `POST /auth/login` System (email + password) login. **Request body:** ```json { "email": "jane@example.com", "password": "Password1" } ``` **Response 200:** Same shape as verify-otp. --- #### `POST /auth/refresh` Rotate access + refresh tokens. **Request body:** `{ "refreshToken": "eyJ..." }` --- #### `GET /auth/google` Redirect to Google consent screen. No body needed. --- #### `GET /auth/google/callback` Google OAuth redirect target. Returns tokens on success. --- #### `POST /auth/logout` *(requires Bearer token)* Invalidates the specified session. **Request body:** `{ "session_id": 1 }` --- #### `POST /auth/change-password` *(requires Bearer token)* Change password. Invalidates all sessions. **Request body:** ```json { "current_password": "OldPass1", "new_password": "NewPass2" } ``` --- ### 8.2 Client Endpoints *(requires Bearer — any acc_type)* | Method | Path | Description | |---|---|---| | GET | `/client/profile` | Own profile | | PUT | `/client/profile` | Update own `personal_info` | | GET | `/client/sessions` | Own active sessions | | DELETE | `/client/sessions/:id` | Revoke one of own sessions | **PUT /client/profile — Example body:** ```json { "personal_info": { "name": { "given_name": "Jane", "last_name": "Doe" }, "occupation": "Engineer", "date_of_birth": "1995-06-15" } } ``` --- ### 8.3 Staff Endpoints *(requires Bearer — staff or admin)* | Method | Path | Description | |---|---|---| | GET | `/staff/users` | Paginated list (non-admins) | | GET | `/staff/users/:id` | Single non-admin user | | PUT | `/staff/users/:id/status` | Toggle `is_active` | | GET | `/staff/users/:id/sessions` | User's sessions | **Query params for GET list:** `?page=1&limit=20` **PUT /staff/users/:id/status — Body:** `{ "is_active": false }` --- ### 8.4 Admin Endpoints *(requires Bearer — admin only)* | Method | Path | Description | |---|---|---| | GET | `/admin/users` | All users (paginated) | | GET | `/admin/users/:id` | Any user with groups | | PUT | `/admin/users/:id` | Update `acc_type`, `is_active`, `personal_info` | | DELETE | `/admin/users/:id` | Hard delete user | | GET | `/admin/users/:id/sessions` | All sessions | | DELETE | `/admin/users/:id/sessions/:sid` | Force-terminate session | | GET | `/admin/groups` | List all groups | | POST | `/admin/groups` | Create group `{ name, description }` | | DELETE | `/admin/groups/:gid` | Delete group | | POST | `/admin/users/:id/groups/:gid` | Add user to group | | DELETE | `/admin/users/:id/groups/:gid` | Remove user from group | **PUT /admin/users/:id — Allowed fields:** ```json { "acc_type": "staff", "is_active": true, "personal_info": { ... } } ``` --- ## 9. RBAC Permission Matrix | Action | Client (`user`) | Staff (`staff`) | Admin (`admin`) | |---|:---:|:---:|:---:| | Register | ✅ | ✅ | ✅ | | Login | ✅ | ✅ | ✅ | | View own profile | ✅ | ✅ | ✅ | | Edit own profile | ✅ | ✅ | ✅ | | View own sessions | ✅ | ✅ | ✅ | | Revoke own session | ✅ | ✅ | ✅ | | Change own password | ✅ | ✅ | ✅ | | List all users | ❌ | ✅ (no admins) | ✅ | | View any user | ❌ | ✅ (no admins) | ✅ | | Toggle user status | ❌ | ✅ (no admins) | ✅ | | View user sessions | ❌ | ✅ (no admins) | ✅ | | Change user `acc_type` | ❌ | ❌ | ✅ | | View admin accounts | ❌ | ❌ | ✅ | | Hard delete users | ❌ | ❌ | ✅ | | Force-terminate session | ❌ | ❌ | ✅ | | Manage groups | ❌ | ❌ | ✅ | --- ## 10. File-by-File Documentation ### `server.js` **Purpose:** Application entry point. Bootstraps Express, registers global middleware (CORS, rate limiter, cookie-parser, session, Passport), mounts all routes, syncs DB models. **Key behaviors:** - Runs `sequelize.sync({ alter: true })` on startup (development) — safe column updates. - Registers a global 404 handler and error handler. - Enables `trust proxy` for correct IP detection behind load balancers. --- ### `config/db.config.js` **Purpose:** Creates and exports a single authenticated Sequelize instance. **Usage:** `const sequelize = require('./config/db.config');` --- ### `config/passport.config.js` **Purpose:** Registers the Google OAuth 2.0 strategy. Auto-creates user on first Google login with `reg_type='google'` and `is_verified=true`. **Usage:** Imported in `server.js`; used in `routes/auth.routes.js` via `passport.authenticate('google', ...)`. --- ### `models/users.mdl.js` **Purpose:** Defines the `users` table including OTP fields (`otp_code`, `otp_expires_at`) added for the verification flow. **Exported as:** `mdl_Users` (default) --- ### `models/user_sessions.mdl.js` **Purpose:** Audit log for logins/logouts. Stores `refresh_token_hash` for secure token rotation and session invalidation. Sets up `belongsTo/hasMany` with Users. **Exported as:** `mdl_UserSessions` (default) --- ### `models/user_groups.mdl.js` **Purpose:** `user_groups` and `user_group_members` junction table. Implements `belongsToMany` associations between Users and Groups. **Exported as:** `{ mdl_UserGroups, mdl_UserGroupMembers }` --- ### `middleware/auth.middleware.js` **Purpose:** Reads `Authorization: Bearer `, calls `verifyAccessToken()`, loads the user from DB, and attaches it to `req.user`. **Exported:** `authenticate` --- ### `middleware/rbac.middleware.js` **Purpose:** Role guards that inspect `req.user.acc_type`. All guards must be used **after** `authenticate`. **Exported:** `requireClient()`, `requireStaff()`, `requireAdmin()`, `requireOwnerOrStaff()`, `requireOwnerOrAdmin()` --- ### `middleware/csrf.middleware.js` **Purpose:** Wraps `csurf` with a token endpoint and a dedicated error handler. **Exported:** `csrfProtection`, `getCsrfToken`, `csrfErrorHandler` --- ### `middleware/rateLimiter.middleware.js` **Purpose:** Four rate-limiter configurations for different route tiers. **Exported:** `globalLimiter`, `authLimiter`, `otpLimiter`, `sensitiveOpsLimiter` --- ### `middleware/validate.middleware.js` **Purpose:** Reads the `validationResult` from express-validator and returns 422 if any rule failed. **Exported:** `validate` --- ### `validators/auth.validator.js` **Purpose:** express-validator chains for `register`, `login`, `verify-otp`, `resend-otp`, `change-password`. **Usage:** Spread into route definitions: `router.post('/login', ...loginValidator, validate, handler)` --- ### `validators/profile.validator.js` **Purpose:** Validates `personal_info` fields on profile update requests. --- ### `utils/token.util.js` **Purpose:** JWT helpers. **Functions:** - `generateTokens(user)` → `{ accessToken, refreshToken }` - `verifyAccessToken(token)` → decoded payload (throws on expiry/invalid) - `verifyRefreshToken(token)` → decoded payload - `hashToken(token)` → SHA-256 hex string for DB storage --- ### `utils/otp.util.js` **Purpose:** Cryptographically secure OTP helpers. **Functions:** - `generateOTP()` → `"048291"` (6 digits, padded) - `getOTPExpiry(minutes)` → `Date` N minutes from now - `isOTPExpired(expiresAt)` → `boolean` --- ### `utils/response.util.js` **Purpose:** Standardised response envelope `{ status, message, data?, errors? }`. **Functions:** `success(res, msg, data, statusCode)`, `error(res, msg, statusCode, errors)`, `validationError(res, errors)` --- ### `services/email.service.js` **Purpose:** Nodemailer transporter with two email templates. **Functions:** - `sendOTPEmail(to, otp, expiryMinutes)` — styled HTML OTP email - `sendWelcomeEmail(to, name)` — post-verification welcome --- ### `controllers/auth.controller.js` **Purpose:** Shared auth logic: `register`, `verifyOTP`, `resendOTP`, `login`, `googleCallback`, `refreshToken`, `logout`, `changePassword`. --- ### `controllers/client/profile.controller.js` **Purpose:** Self-service profile actions for any authenticated user. **Functions:** `getProfile`, `updateProfile` (deep-merge), `getSessions`, `revokeSession` --- ### `controllers/staff/users.controller.js` **Purpose:** Staff-level user management (read-only + status toggle; no admin data). **Functions:** `getUsers`, `getUser`, `setUserStatus`, `getUserSessions` --- ### `controllers/admin/users.controller.js` **Purpose:** Full admin control over users, sessions, and groups. **Functions:** `getUsers`, `getUser`, `updateUser`, `deleteUser`, `getUserSessions`, `terminateSession`, `getGroups`, `createGroup`, `deleteGroup`, `addUserToGroup`, `removeUserFromGroup` --- ## 11. Error Codes Reference | HTTP | Scenario | |---|---| | 400 | Bad request (missing field, wrong type, already verified) | | 401 | Missing/invalid/expired token, wrong credentials | | 403 | Account deactivated, wrong role, CSRF error | | 404 | Resource not found | | 409 | Email already registered | | 422 | Validation failed (see `errors[]` array) | | 429 | Rate limit exceeded | | 500 | Internal server error | All error responses follow: ```json { "status": "error", "message": "Human-readable reason", "errors": [ ... ] // only on 422 } ``` --- ## 12. Extending the System ### Add a New Endpoint 1. Create validator rules in `validators/` 2. Create or extend a controller in `controllers//` 3. Add the route in `routes//.routes.js` with appropriate middleware chain 4. No changes to `server.js` needed if mounting the same base path ### Add a New Role 1. Add the ENUM value to `acc_type` in `users.mdl.js` 2. Add a guard in `rbac.middleware.js` (e.g., `requireSuperAdmin()`) 3. Create a dedicated route + controller folder ### Add Redis Session Store Install `connect-redis` and update `server.js`: ```js const RedisStore = require('connect-redis').default; const { createClient } = require('redis'); const redisClient = createClient({ url: process.env.REDIS_URL }); await redisClient.connect(); app.use(session({ store: new RedisStore({ client: redisClient }), ... })); ``` ### Production Checklist - [ ] Set `NODE_ENV=production` - [ ] Set `ORIGIN_GUARD_DISABLED=false` (or remove the key entirely) - [ ] Use strong `JWT_SECRET` (≥ 64 random characters) - [ ] Enable HTTPS / TLS (set `cookie.secure: true`) - [ ] Point `APP_URL` to your actual domain for CORS - [ ] Replace in-memory rate limiter with Redis store - [ ] Set up log rotation (replace `console.log` with Winston/Pino) - [ ] Use `sequelize.sync({ force: false, alter: false })` in production (run migrations instead) --- *End of Documentation — STAR Phase 1 Auth System v1.0.0*