Files

197 lines
7.4 KiB
Markdown

# 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
```bash
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
1. Keep this API on **3100**
2. In dashboards: `VITE_API_BASE_URL=http://localhost:3100/api/v1`
3. Backend `CORS_ORIGIN` must include local dashboard origins, e.g.
`http://baloutpastry.com:5173,http://admin.baloutpastry.com:5173,http://customer.baloutpastry.com:5173,http://localhost:5173`
4. Add local DNS in `/etc/hosts` for `baloutpastry.com`, `admin.baloutpastry.com`, `customer.baloutpastry.com``127.0.0.1`
5. Log in with the super-admin phone/password you created
- Admin: `http://admin.baloutpastry.com:5173`
- Customer: `http://customer.baloutpastry.com:5173`
## 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.
```bash
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/login` with `{ "cellNumber": "09…", "password": "…" }`
- Login with SMS: `POST /auth/login/send-code` then `POST /auth/login/verify`
- Forgot password: `POST /auth/forgot-password/send-code``/verify``/reset`
- Register: `POST /auth/register/send-code` then `POST /auth/register/verify` (SMS OTP → create `customer`)
- Only `admin` and `superAdmin` can log in to the admin API/dashboard
- Only `superAdmin` can assign `admin` or `superAdmin` roles
- `customer` users exist for orders / future customer UI
- Access token in `Authorization: Bearer …`; refresh via `POST /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:
```json
{
"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
```bash
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/dashboards` and read `CONTEXT.md`
- Website (storefront): clone `BaloutPastry/website` and read `CONTEXT.md` (dev port **5174**)
- Short API overview also in `README.md`