7.4 KiB
Balout Pastry — Backend (setup context)
NestJS API for شیرینیفروشی بلوط. Serves the admin Dashboards SPA (and future customer apps).
Repo: https://git.meshkee.com/BaloutPastry/backend.git
Dashboards repo: https://git.meshkee.com/BaloutPastry/dashboards.git
Stack
- NestJS 11 / TypeScript
- Prisma 6 + PostgreSQL 16 (Docker Compose)
- JWT access + refresh tokens (bcrypt password hashes)
- Parspack S3-compatible object storage (prefix
balout/)
Prerequisites
- Node.js 20+ (LTS recommended)
- npm
- Docker + Docker Compose (for local Postgres)
- S3 credentials if you need media upload (can leave blank for auth/users-only local work)
Setup on a new device
git clone https://git.meshkee.com/BaloutPastry/backend.git
cd backend
cp .env.example .env
# Fill S3_ACCESS_KEY_ID / S3_SECRET_ACCESS_KEY if you need uploads
# Change JWT_* secrets before any shared/staging use
npm install
npm run db:up # Postgres on 127.0.0.1:5434
npx prisma migrate deploy # apply migrations
npx prisma generate # if client missing after install
npm run create-super-admin -- --phone 09120000000 --password secret123
# optional: --first علی --last رضایی --title "جناب آقای"
npm run start:dev # http://localhost:3100/api/v1
Health check: GET http://localhost:3100/api/v1/auth/me → 401 without token is expected (server is up).
Pair with Dashboards
- Keep this API on 3100
- In dashboards:
VITE_API_BASE_URL=http://localhost:3100/api/v1 - Backend
CORS_ORIGINmust include local dashboard origins, e.g.
http://baloutpastry.com:5173,http://admin.baloutpastry.com:5173,http://customer.baloutpastry.com:5173,http://localhost:5173 - Add local DNS in
/etc/hostsforbaloutpastry.com,admin.baloutpastry.com,customer.baloutpastry.com→127.0.0.1 - Log in with the super-admin phone/password you created
- Admin:
http://admin.baloutpastry.com:5173 - Customer:
http://customer.baloutpastry.com:5173
- Admin:
Scripts
| Command | What it does |
|---|---|
npm run start:dev |
Nest watch mode → http://localhost:3100/api/v1 |
npm run start:prod |
Run compiled dist/main |
npm run build |
Compile Nest → dist/ |
npm run db:up |
docker compose up -d (Postgres) |
npm run db:down |
Stop Postgres container |
npm run prisma:migrate |
Create/apply migrations in dev |
npm run prisma:deploy |
Apply existing migrations (CI / new device) |
npm run prisma:generate |
Regenerate Prisma Client |
npm run create-super-admin |
Create first superAdmin user |
npm run send-sms |
Send SMS via Meshkee (--to / --message) |
npm run lint |
ESLint |
Environment
Copy from .env.example. Do not commit .env.
| Variable | Notes |
|---|---|
DATABASE_URL |
Prisma connection string (default → local Docker on 5434) |
POSTGRES_* |
Used by Docker Compose |
PORT |
API port, default 3100 |
CORS_ORIGIN |
Comma-separated origins; include dashboard URL |
JWT_ACCESS_SECRET / JWT_REFRESH_SECRET |
Change from example values |
JWT_ACCESS_EXPIRES_IN / JWT_REFRESH_EXPIRES_IN |
e.g. 15m / 7d |
STORAGE_DISK |
s3 for Parspack |
S3_* |
Endpoint, bucket, public URL, keys |
MEDIA_MAX_FILE_SIZE_MB |
Upload size cap |
MESHKEE_SMS_URL |
Meshkee public SMS send endpoint |
MESHKEE_SMS_API_KEY |
Partner API key (X-Api-Key) — server only |
MESHKEE_SMS_DOMAIN |
Partner domain, e.g. baloutpastry.com |
Inject SmsService from SmsModule to send SMS from the backend (never from the frontend). Limits: 30/partner/min, 5/destination/min.
npm run send-sms -- --to 09127004945 --message "متن پیام"
Ports are intentional vs Meshkee: API 3100, Postgres host 5434 (Meshkee uses 3000 / 5432).
Auth rules
- Login:
POST /auth/loginwith{ "cellNumber": "09…", "password": "…" } - Login with SMS:
POST /auth/login/send-codethenPOST /auth/login/verify - Forgot password:
POST /auth/forgot-password/send-code→/verify→/reset - Register:
POST /auth/register/send-codethenPOST /auth/register/verify(SMS OTP → createcustomer) - Only
adminandsuperAdmincan log in to the admin API/dashboard - Only
superAdmincan assignadminorsuperAdminroles customerusers exist for orders / future customer UI- Access token in
Authorization: Bearer …; refresh viaPOST /auth/refresh
Main routes (/api/v1)
| Area | Methods |
|---|---|
| Auth | POST /auth/login, /auth/login/send-code, /auth/login/verify, /auth/forgot-password/send-code, /auth/forgot-password/verify, /auth/forgot-password/reset, /auth/register/send-code, /auth/register/verify, /auth/refresh, /auth/logout, GET /auth/me |
| Users | CRUD + PATCH /users/:id/role, /password + addresses under /users/:id/addresses |
| Flavors | CRUD |
| Categories | tree CRUD + GET|PUT /categories/:id/options |
| Products | CRUD (options must match category templates); list filters q, categoryId, minPrice, maxPrice |
| Orders | GET /orders, GET /orders/:id, POST /orders, PATCH /orders/:id/status |
| Media | POST /media/upload?kind=main|gallery|temp |
| Settings | districts, shipping exceptions, branches |
Guards: most routes require JWT + admin/superAdmin. Role changes require superAdmin.
Orders
Create body example:
{
"customerId": "...",
"deliveryType": "pickup",
"branchId": "...",
"note": "optional",
"items": [
{ "productId": "...", "quantity": 2, "optionIds": ["..."] }
]
}
For shipping: deliveryType: "shipping" + shippingAddressId (from user addresses). Prices/names are snapshotted. Display code: BL-{number}.
Domain notes
- Prices are integer تومان
- Phone numbers:
09+ 9 digits (English digits) - User titles/categories are fixed Persian enums in
src/users/users.constants.ts
Project layout
prisma/ schema + migrations
scripts/ create-super-admin.ts
src/
auth/ JWT login, refresh, guards, roles
users/ users + addresses
flavors/
categories/
products/
orders/
media/ uploads
settings/ districts, shipping, branches
storage/ S3 driver
prisma/ PrismaModule / PrismaService
main.ts global prefix api/v1, CORS, ValidationPipe
docker-compose.yml local Postgres
Production sketch
cp .env.example .env # real secrets, DB, CORS, S3
npm ci
npx prisma migrate deploy
npm run build
npm run start:prod
Ensure Postgres is reachable via DATABASE_URL and CORS_ORIGIN lists the real dashboard origin(s).
Common issues
| Symptom | Likely cause |
|---|---|
ECONNREFUSED / Prisma errors |
Postgres not up → npm run db:up, check DATABASE_URL / port 5434 |
| Port already in use | Another process on 3100 or 5434 |
| Login rejected for valid user | Role is customer, or wrong phone format |
| CORS errors from dashboard | CORS_ORIGIN missing http://localhost:5173 |
| Upload fails | Missing/invalid S3_* keys or endpoint |
User already exists on create-super-admin |
That phone is already in DB |
Related
- Dashboards setup: clone
BaloutPastry/dashboardsand readCONTEXT.md - Website (storefront): clone
BaloutPastry/websiteand readCONTEXT.md(dev port 5174) - Short API overview also in
README.md