TypeScript/Express + MongoDB REST API for posts, products, categories, orders, and users. JWT auth, role-based access, file uploads, rate limiting, and structured logging. Suitable for Docker and optional Cloudflare Tunnel exposure.
- Auth: JWT access + refresh, role checks (Admin, Editor)
- Product Management CRUD, category population, stock delta updates, image upload/replace
- Category Management CRUD with βin useβ protection
- Post Management Simple CRUD
- Order System Stock validation & atomic updates, owner/role-based access
- CORS: Strict allowlist for production; dev-friendly options
- Logging: Request/event logs with client IP (behind proxies)
- Rate limits: Login throttling
- Docker-ready: Compose setup; optional Cloudflare Tunnel
- Backend: Node.js, Express.js, TypeScript
- Database: MongoDB (Mongoose)
- Authentication:: JWT (access & refresh tokens)
- Uploads:: Multer (2 MB limit; JPEG/PNG/GIF/WebP)
- Environment Configuration:: dotenv
mist-server/
βββ src/
β βββ config/ # env/config/constants (roles, shipping, statuses, regex, cors
β βββ controllers/ # route handlers (auth, users, products, posts, categories, orders)
β βββ middleware/ # verifyJWT, verifyRoles, rate limiter, credentials, error handler
β βββ models/ # Mongoose schemas & TS types
β βββ routes/ # Express routers
β βββ services/ # business logic (DB ops, auth helpers)
β βββ utils/ # helpers (order number, validation, etc.)
β βββ server.ts # app bootstrap
βββ public/uploads/images/ # uploaded images (gitignored)
βββ logs/ # request/error logs (created at runtime)
βββ .env # Environment variables
βββ .gitignore # Git ignored files
βββ package.json
βββ tsconfig.json
βββ .gitignore
βββ README.md # Project documentation
- Node.js β₯ 18 (LTS recommended)
- MongoDB (local or cloud)
- npm β₯ 9
-
Clone & install
git clone https://github.com/Aztaban/mist-server.git <your-repo-folder> cd <your-repo-folder> npm ci
-
Set up environment variables: Create a
.envfile in the root directory and add the following:PORT=3500 DATABASE_URI=<your-database-uri> ACCESS_TOKEN_SECRET=<your-jwt-secret> REFRESH_TOKEN_SECRET=<your-refresh-token-secret> CORS_ORIGINS=<your-allowed-cors-origins> STRIPE_API_SECRET=<your-stripe-api-secret> COOKIE_SECURE=<true|false> TRUST_PROXY=<true|false> UPLOAD_DIR:=<your-upload-directory>
-
Run in development mode:
npm run dev
-
Run in production mode:
npm run build npm start
Base paths have no /api prefix (e.g., /auth, /products, β¦).
Protect admin/editor routes in the router with verifyJWT then verifyRoles(...).
POST /auth/register- Register (password policy enforced)POST /auth/login- Issue access + refresh tokensGET /auth/refresh- Rotate access token (if enabled)POST /auth/logout- Invalidate refresh tokenPUT /user/password- Change password (current + new)
GET /usersβ Get all users (Admin,Editor)GET /users/:idβ Get a specific user by ID (Admin)PATCH /users/:id/toggle-statusβ Enable/disable user account (Admin)PATCH /users/:id/toggle-editorβ Grant/revoke editor role (Admin)
GET /usersβ Get logged-in user's profileGET /users/ordersβ Get user's own ordersPATCH /users/addressβ Update addressPATCH /users/phoneβ Update phone numberPATCH /users/emailβ Update emailPUT /users/passwordβ Change password
GET /categoriesβ Retrieve all categories
POST /categoriesβ Create a new category (Admin,Editor)PATCH /categories/:idβ Update an existing category (Admin,Editor)DELETE /categories/:idβ Delete a category (Admin,Editor)
GET /postsβ Get all postsGET /posts/:idβ Get a specific post by ID
POST /postsβ Create a new post (Admin,Editor)PUT /posts/:idβ Update a post (Admin,Editor)DELETE /posts/:idβ Delete a post (Admin)
GET /β Get all productsGET /:idβ Get product by ID
POST /productsβ Create a new product (Admin,Editor)PATCH /products/:idβ Update a product (Admin,Editor)POST /products/imageUploadβ Upload a new product image (Admin,Editor)PUT /products/:id/imageβ Replace an existing product image (Admin,Editor)DELETE /productsβ Delete a single product by ID (passed in request body) (Admin)
POST /ordersβ Create a new orderGET /orders/:idβ Get a specific order by IDPUT /orders/:id/mark-paidβ Mark an order as paid (used after payment)
GET /ordersβ Get all orders (Admin,Editor)PATCH /orders/:idβ Update an order status (e.g., shipped, delivered) (Admin,Editor)DELETE /orders/:idβ Delete an order (Admin)
POST /orders/:id/payment-intentβ Create a Stripe payment intent for the order
- Prod: allow only your FE origins (e.g., https://mist-gate.vercel.app).
- Dev: http://localhost:5173, etc.
- CORS uses Origin (the site), not visitor IPs.
- Set trust proxy behind Cloudflare/reverse proxies; log client IP from CF-Connecting-IP/X-Forwarded-For.
- Rate limit sensitive routes (login).
- Validate ObjectIds and request bodies (done in controllers/services).
- Logs are written to logs/ with timestamp + UUID.
- Request logger includes method, origin, path, and client IP (when proxied).
- Controllers call next(error); a global error handler maps err.status or defaults to 500.
- Common client errors: 400 Invalid ... id, 409 Category has products, 400 Stock cannot be negative, 401/403 auth failures.
This project is licensed under the MIT License. See the LICENSE file for details.