- docs/casdoor-auth.md: addresses and credentials (Casdoor console admin/123, seeded users), in-page login flow, status-code table, the User/Organization/Role/Permission/Application model, the 9 failure scenarios with debug steps, Test 1-6 results, 23-item checklist, and how to manage Casdoor (console, seeding, first-admin bootstrap) - README: replace the 'no authentication' and 'Casdoor not seeded' notes with the current login flow, developer-mode toggle and a link to the auth guide
213 lines
8.4 KiB
Markdown
213 lines
8.4 KiB
Markdown
# Procurement Stack v1.3 — Dockerized (PostgreSQL + FastAPI + React + MinIO)
|
||
|
||
Self-contained ship package: everything needed to run the stack is in this
|
||
folder — no external files or sibling folders required.
|
||
|
||
| Service | Container | Tech | Exposed port |
|
||
|---|---|---|---|
|
||
| **postgres** | `procurement-postgres` | PostgreSQL 18 | `5433` |
|
||
| **minio** | `procurement-minio` | MinIO object storage (S3-compatible) | `9000` (API), `9001` (console) |
|
||
| **casdoor** | `procurement-casdoor` | Casdoor (OIDC identity provider) | `8080` |
|
||
| **api** | `procurement-api` | FastAPI + SQLAlchemy (asyncpg) | `8000` |
|
||
| **frontend** | `procurement-frontend` | React 19 + Vite, served by nginx | `3000` |
|
||
|
||
```
|
||
Browser ──► frontend :3000 (nginx SPA)
|
||
│
|
||
└── /api/* proxy ──► api :8000 (FastAPI, /api/v1)
|
||
│
|
||
├── postgres :5432 (procurement DB)
|
||
├── minio :9000 (invoice/proforma files, bucket `procurement-files`)
|
||
└── casdoor :8000 (OIDC — login for the inventory panel)
|
||
```
|
||
|
||
---
|
||
|
||
## 📁 Layout
|
||
|
||
```text
|
||
v1.3/
|
||
├── docker-compose.yml ← all paths are relative to this folder
|
||
├── start.ps1 ← PowerShell helper (build + start + status)
|
||
├── mc.cmd ← MinIO Client helper (inspect the bucket)
|
||
├── README.md
|
||
├── sql/
|
||
│ └── migration.sql ← DB schema v2.6 (auto-runs on first boot)
|
||
├── docs/ ← ERDs + migration plan + auth guide
|
||
│ ├── erd.txt (v2.4 — old procurement schema)
|
||
│ ├── new erd.txt (v2.5 — material → supplier → category)
|
||
│ ├── NewERD.txt (v2.6 — integrated procurement + inventory)
|
||
│ ├── casdoor-auth.md (v2.6 — Casdoor login, roles, failure scenarios)
|
||
│ └── material-supplier-category-migration-plan.md
|
||
├── backend/ ← build context of the `api` service
|
||
│ ├── Dockerfile
|
||
│ ├── requirements.txt
|
||
│ ├── .dockerignore
|
||
│ ├── app/ (source code — procurement + inventory + auth)
|
||
│ └── tools/ (smoke-test + seed scripts, copied into the image)
|
||
└── frontend/ ← build context of the `frontend` service
|
||
├── Dockerfile
|
||
├── nginx.conf
|
||
├── .dockerignore
|
||
├── .env.example (copy to .env if you need a custom API base URL)
|
||
├── index.html
|
||
├── package.json
|
||
├── package-lock.json
|
||
├── tsconfig*.json
|
||
├── vite.config.ts
|
||
├── public/
|
||
└── src/
|
||
└── pages/
|
||
├── Dashboard/ (procurement office)
|
||
├── Wizard/ (add new offer)
|
||
├── Suppliers/ (suppliers & topics)
|
||
├── Projects/ (projects)
|
||
├── Units/ (unit conversions)
|
||
└── Inventory/ (warehouse management panel — React port)
|
||
```
|
||
|
||
---
|
||
|
||
## 🔐 Login
|
||
|
||
The whole system is behind a login page (`/login`). Login is **in-page**:
|
||
the form (username / password / optional organization) is sent to
|
||
`POST /api/v1/auth/login`; the backend exchanges it with Casdoor
|
||
(password grant), verifies the returned JWT, and starts the session —
|
||
no browser redirect to Casdoor.
|
||
|
||
- **مدیر پروژه (PM)** → lands in the inventory panel (their project) — can record
|
||
stock changes, manage the project's warehouses and confirm arrivals («کالاهای در راه»).
|
||
- **مدیر تدارکات / ادمین** → lands in the procurement office — can manage
|
||
quotes, suppliers, projects, and in the inventory panel: dashboard, daily control,
|
||
«کالاهای در راه» (receiving included) and «سازماندهی» (users, PMs, warehouses).
|
||
The «انبارها» and «تغییر موجودی» sections are PM-only.
|
||
|
||
**Developer Mode** (top-left button on the login page) allows test login as
|
||
مدیر تدارکات / ادمین / مدیر پروژه without Casdoor. It is controlled by the
|
||
`VITE_ENABLE_DEV_LOGIN` env var (in Docker: the `DEV_LOGIN_ENABLED` compose
|
||
build arg, default `true` — set it to `false` for production builds).
|
||
|
||
| What | Where | Credentials |
|
||
|---|---|---|
|
||
| Casdoor console | http://localhost:8080 | `admin` / `123` |
|
||
| Seeded app users (org `inventory`) | `razaei` (admin), `mousavi` (مدیر تدارکات), `mohaghegh` (مدیر پروژه), `tester` (مدیر پروژه، پروژه «تست») | password `123456` |
|
||
|
||
Run `backend/tools/seed_casdoor.py` once after the first boot to create the
|
||
Casdoor organization, application and users (idempotent). Full details —
|
||
addresses, credentials, role model, failure scenarios and the checklist —
|
||
are in [`docs/casdoor-auth.md`](docs/casdoor-auth.md).
|
||
|
||
---
|
||
|
||
## Prerequisites (target machine)
|
||
|
||
- **Docker Desktop** (Windows) or Docker Engine + Compose plugin (Linux/macOS)
|
||
- ~3–4 GB free disk for images (`postgres:18`, `python:3.13-slim`, `node:22-alpine`, `nginx:alpine`, `minio/minio`, `minio/mc`)
|
||
- Internet access on first build (image + `npm ci` downloads)
|
||
|
||
---
|
||
|
||
## Start the whole stack
|
||
|
||
```powershell
|
||
cd <this-folder>
|
||
docker compose up -d --build
|
||
```
|
||
|
||
First run downloads base images and builds the frontend (takes a few minutes).
|
||
Subsequent runs: `docker compose up -d`.
|
||
|
||
Wait until all services are up:
|
||
|
||
```powershell
|
||
docker compose ps
|
||
```
|
||
|
||
All should show `Up` (postgres also `(healthy)`).
|
||
|
||
---
|
||
|
||
## Verify
|
||
|
||
| What | Where |
|
||
|---|---|
|
||
| Frontend UI | http://localhost:3000 |
|
||
| API docs (Swagger) | http://localhost:8000/docs |
|
||
| API health | http://localhost:8000/health → `{"status":"ok","service":"procurement-api"}` |
|
||
| MinIO console | http://localhost:9001 (user/pass `minioadmin`/`minioadmin`) |
|
||
| Database | `localhost:5433`, db `procurement`, user/pass `postgres`/`postgres` |
|
||
|
||
Quick end-to-end check (frontend proxy → API → DB):
|
||
|
||
```powershell
|
||
curl http://localhost:3000/api/v1/quotes?expand=supplier,project,line_items,termsheets,events,decision,receipt
|
||
```
|
||
|
||
---
|
||
|
||
## MinIO (object storage for invoice / proforma files)
|
||
|
||
| Item | Value |
|
||
|---|---|
|
||
| S3 API endpoint | `localhost:9000` (from the API container: `minio:9000`) |
|
||
| Web console | http://localhost:9001 |
|
||
| Root user / password | `minioadmin` / `minioadmin` (dev — change for production) |
|
||
| Bucket | `procurement-files` (created automatically by the `minio-init` container) |
|
||
| Object key layout | `{quote_id}/{kind}/{attachment_id}` where kind = `invoice` \| `proforma` |
|
||
|
||
File **bytes** live in MinIO; the `quote_attachments` table holds the metadata.
|
||
|
||
Ad-hoc bucket inspection from the host (see `mc.cmd`):
|
||
|
||
```powershell
|
||
.\mc.cmd ls --recursive
|
||
```
|
||
|
||
---
|
||
|
||
## Database credentials / connection
|
||
|
||
```text
|
||
Host: localhost
|
||
Port: 5433
|
||
Database: procurement
|
||
Username: postgres
|
||
Password: postgres
|
||
```
|
||
|
||
```powershell
|
||
docker exec -it procurement-postgres psql -U postgres -d procurement
|
||
```
|
||
|
||
---
|
||
|
||
## Common operations
|
||
|
||
```powershell
|
||
docker compose logs -f api # see logs
|
||
docker compose down # stop (keep data)
|
||
docker compose up -d --build # rebuild after code changes
|
||
docker compose down -v # ⚠️ full reset — wipes DB + MinIO volumes
|
||
```
|
||
|
||
---
|
||
|
||
## Known behavior
|
||
|
||
- Authentication is Casdoor-based (JWT verified via JWKS): `/auth`, `/users`,
|
||
`/inventory` and `/pm` are protected (401 without a token, 403 without a role).
|
||
The procurement CRUD endpoints (quotes, suppliers, materials, …) are still
|
||
open — dev placeholder, do not expose to the public internet.
|
||
- Roles live in the app's `users` table (Casdoor is identity-only): `pm`,
|
||
`procurement_manager`, `admin`. See `docs/casdoor-auth.md`.
|
||
- Schema runs automatically ONLY on the first boot of an empty `postgres_data` volume
|
||
(see `docker-entrypoint-initdb.d`); the API also runs `CREATE TABLE IF NOT EXISTS`
|
||
for the units-dashboard tables and `quote_attachments` at startup.
|
||
- Invoice upload requires an `accepted`/`arrived` quote; proforma has no restriction.
|
||
- The supplier detail page (`/suppliers/:id`) shows the purchase history with
|
||
invoice/proforma download links from MinIO.
|
||
- If builds fail with disk-full errors: `docker system prune -a`, then rebuild.
|
||
- If the frontend shows «اتصال به سرور برقرار نشد» → the api container is not
|
||
reachable; check `docker compose ps` and `docker compose logs api`.
|