diff --git a/README.md b/README.md index a7edde9..945b883 100644 --- a/README.md +++ b/README.md @@ -1,359 +1,191 @@ +# ERP & PM Integrated Platform — Dockerized +## سامانه یکپارچه تدارکات، انبارداری، مدیریت پروژه (PM) و ربات هوشمند -# Procurement Stack v1.3 — Dockerized (PostgreSQL + FastAPI + React + MinIO) +مجموعه نرم‌افزاری یکپارچه و خودکفا (Self-contained) شامل تمامی سرویس‌ها، ماژول‌ها و تنظیمات زیرساختی مورد نیاز برای اجرا در محیط توسعه و عملیات: -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 (one instance: `procurement` + `casdoor` DBs) | `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 (internal) | via Traefik | -| **traefik** | `procurement-traefik` | Traefik v3 — public reverse proxy (edge) | `80` (web), `443` (websecure) | - - -``` - -Browser ──► Traefik :80 (edge) -│ -├── Host(localhost) ──► frontend (nginx SPA :80) -│ │ -│ └── /api/* proxy ──► api :8000 (/api/v1) -│ -├── Host(api.localhost) ──► api :8000 -├── Host(auth.localhost) ──► casdoor :8000 (OIDC login) -└── Host(s3/storage.localhost) ──► minio (API / console) -│ -├── postgres :5432 (procurement + casdoor DBs) -└── minio :9000 (invoice/proforma files) - -``` +| **postgres** | `procurement-postgres` | PostgreSQL 18 (دیتابیس مشترک `procurement` + `casdoor`) | `5455:5432` | +| **minio** | `procurement-minio` | MinIO Object Storage (S3-compatible) برای فایل‌ها و پیش‌فاکتورها | `9000` (API), `9001` (کنسول) | +| **casdoor** | `procurement-casdoor` | ارائه‌دهنده متمرکز هویت سازمانی (OIDC Provider) | `8080:8000` | +| **api** | `procurement-api` | بک‌اند اصلی تدارکات و انبار (FastAPI + Asyncpg) | `8000:8000` | +| **frontend** | `procurement-frontend` | فرانت‌اند وب ERP (React 19 + Vite + Tailwind) | سرو از طریق Traefik روی پورت `80` | +| **pm-api** | `pm-api` | بک‌اند بومی مدیریت پروژه ساخت (FastAPI + Python 3.12) | درون‌شبکه‌ای (زیرمسیر `/pm/api`) | +| **pm-frontend** | `pm-frontend` | فرانت‌اند پلتفرم PM (React 19 + تقویم شمسی + گانت + QC) | سرو از طریق Traefik روی `/pm` | +| **bot** | `procurement-bot` | ربات هوشمند بله با پردازش صوت و متن (DeepSeek LLM + STT) | ارتباط Long-polling با Bale | +| **db-backup** | `procurement-db-backup` | پشتیبان‌گیری خودکار زمان‌بندی‌شده از هر دو پایگاه داده | کانتینر دوره‌ای در پس‌زمینه | +| **traefik** | `procurement-traefik` | ریورس پروکسی و مدیریت ترافیک لایه لبه (Traefik v3) | `80` (HTTP), `443` (HTTPS) | --- -## 📁 Layout +## 🌐 معماری شبکه و هدایت ترافیک (Traefik Edge Routing) ```text -v1.3/ -├── docker-compose.yml ← all paths are relative to this folder -├── docker-compose.prod.yml ← production overlay (real domains + HTTPS via Let's Encrypt) -├── start.ps1 ← PowerShell helper (build + start + status) -├── mc.cmd ← MinIO Client helper (inspect the bucket) -├── README.md + ┌────────────────────────┐ + │ Browser / Client │ + └───────────┬────────────┘ + │ :80 / :443 + ▼ + ┌────────────────────────┐ + │ Traefik v3 (Edge) │ + └───────────┬────────────┘ + │ + ┌────────────────────────────────────┼───────────────────────────────────┐ + │ │ │ + ▼ (Host: localhost) ▼ (PathPrefix: /pm) ▼ (Host: api.localhost) +┌───────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐ +│ frontend (React) │ │ pm-frontend / pm-api │ │ api (FastAPI Core) │ +│ /api/* Proxy ───────┼────────────┼───────────────────────┼──────────►│ /api/v1/* │ +└───────────────────────┘ └───────────────────────┘ └───────────┬───────────┘ + │ │ + ├────────────────────────────────────┬──────────────────────────────────────┤ + ▼ ▼ ▼ +┌───────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐ +│ Casdoor OIDC (:8080) │ │ MinIO S3 (:9000) │ │ PostgreSQL 18 (:5455) │ +│ Host: auth.localhost │ │ Host: s3 / storage │ │ procurement + casdoor │ +└───────────────────────┘ └───────────────────────┘ └───────────────────────┘ + ▲ + │ ثبت پیش‌نویس استعلام + ┌────────┴──────────────┐ + │ bot (Bale AI Agent) │ + └───────────────────────┘ +``` + +--- + +## 📁 ساختار پوشه‌ها و اجزای مخزن + +```text +ERP/ +├── docker-compose.yml ← پیکربندی اصلی اجرای کامل تمام سرویس‌های استک +├── docker-compose.prod.yml ← لایه تنظیمات عملیاتی (Let's Encrypt و دامنه‌های رسمی) +├── docker-compose.coolify.yml ← پیکربندی سازگار با استقرار بر روی Coolify +├── start.ps1 ← اسکریپت هلپر پاورشل برای ساخت و اجرا +├── mc.cmd ← ابزار خط فرمان MinIO Client برای مدیریت باکت‌ها +├── README.md ← همین سند راهنما +├── backend/ ← سرویس بک‌اند اصلی تدارکات و انبار (procurement-api) +│ ├── app/ +│ │ ├── db/ ← اتصال دیتابیس و توابع راه‌اندازی اسکیمای خودکار (init_db.py) +│ │ ├── models/ ← مدل‌های پایگاه‌داده (procurement, inventory, catalog) +│ │ ├── routers/ ← اندپوینت‌های API v1 (quotes, inventory, users, drafts, ...) +│ │ ├── schemas/ ← مدل‌های اعتبارسنجی Pydantic +│ │ ├── services/ ← منطق بیزینس (انبارداری، استعلام‌ها، ذخیره‌سازی، ...) +│ │ ├── utils/ ← ابزارهای امنیتی، خطایابی، ریت‌لیمیت +│ │ ├── auth.py ← تایید توکن Casdoor و تفکیک دسترسی‌ها +│ │ ├── config.py ← متغیرهای پیکربندی +│ │ └── main.py ← اسمبلی برنامه FastAPI و میدل‌ورها +│ └── tools/ ← اسکریپت‌های سیدینگ (seed_casdoor.py) و تست‌های دود (Smoke) +├── frontend/ ← وب‌اپلیکیشن اصلی ERP (procurement-frontend) +│ ├── src/ +│ │ ├── components/ ← کامپوننت‌های مشترک، لایه‌بندی و سوییچر پنل‌ها +│ │ ├── pages/ +│ │ │ ├── Admin/ ← پنل مدیریت سامانه و همگام‌سازی کاربران +│ │ │ ├── Auth/ ← صفحه ورود و احراز هویت +│ │ │ ├── Dashboard/ ← کارتابل استعلام‌ها و تصمیم‌گیری خرید +│ │ │ ├── Inventory/ ← انبارداری (موجودی، ورود کالا، انتقال کارگاهی، کنترل روزانه) +│ │ │ ├── Organization/ ← ماتریس دسترسی پنل‌ها و انتساب پروژه‌ها +│ │ │ ├── Projects/ ← مدیریت پروژه‌های عمرانی +│ │ │ ├── Suppliers/ ← دسته‌بندی موضوعی و فهرست تأمین‌کنندگان +│ │ │ ├── Units/ ← سیستم کاتالوگ متریال‌ها، تامین‌کنندگان و ضرایب تبدیل +│ │ │ └── Wizard/ ← ویزارد مرحله‌ای ثبت استعلام (با اتصال مستقیم به پیش‌نویس ربات) +│ │ ├── store/ ← مدیریت وضعیت با Zustand +│ │ └── App.tsx ← درخت روت‌ها، گیت‌های امنیتی پنل‌ها و نقش‌ها +├── pm/ ← پلتفرم مدیریت پروژه و کنترل کیفیت (پلتفرم آرامش) +│ ├── backend/ ← بک‌اند مستقل PM (FastAPI, CPM Engine, QC Service) +│ ├── frontend/ ← فرانت‌اند PM (گانت چارت شمسی، WBS، ثبت عیوب و بازرسی) +│ ├── sql/ ← اسکیما و اسکریپت‌های اختصاصی پایگاه داده PM +│ └── API_CONTRACT.md ← قرارداد کامل اندپوینت‌های PM +├── bot/ ← ایجنت هوشمند بله برای ثبت صوتی/متنی استعلام‌ها +│ ├── app/ ← کلاینت Bale، پردازشگر STT صوتی، استخراج NLU با DeepSeek +│ ├── docs/SETUP.md ← راهنمای راه‌اندازی و اتصال توکن بله +│ └── requirements.txt +├── monitoring/ ← استک مانیتورینگ، متریک‌ها و لاگ‌ها (پرومتئوس، گرافانا، لوکی) +├── infra/ ← تنظیمات وب‌هوک دیپلوی خودکار و کانفیگ‌های داینامیک Traefik ├── sql/ -│ ├── migration.sql ← DB schema v2.6 (auto-runs on first boot) -│ └── 02-casdoor-db.sql ← creates the `casdoor` role+DB on the same instance -├── infra/ -│ └── traefik-dynamic.yml ← Traefik shared middlewares (HTTP→HTTPS redirect) -├── 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) - +│ ├── migration.sql ← اسکریپت اولیه پایه دیتابیس +│ └── 02-casdoor-db.sql ← اسکریپت راه‌اندازی دیتابیس هویت Casdoor +└── tests/ ← تست‌های یکپارچگی NLU و ویزارد استعلام ``` --- -## 🔐 Login +## 🔐 سیستم احراز هویت، ماتریس پنل‌ها و کنترل دسترسی (RBAC) -The whole system is behind a login page (`/login`). Login is **in-page**: -the form (username / password) 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. +سامانه از سیستم احراز هویت **Casdoor OIDC** بهره می‌برد؛ ورود به صورت In-Page بوده و توکن JWT صادر شده توسط بک‌اند با JWKS اعتبارسنجی می‌شود. -* **مدیر پروژه (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. +مدل دسترسی سامانه بر پایه **پنل‌ها (`user_panels`)** بازطراحی شده است: -**Developer Mode** (top-left button on the login page) is a 3-step flow for -the admin (super user): ① superuser auth gate (admin credentials only) → -② role switcher (ادمین / مدیر تدارکات / مدیر پروژه + project) → ③ session -activation by role (admin → **پنل مدیریت ادمین** at `/admin`, مدیر تدارکات → -procurement office, مدیر پروژه → their project's inventory panel). 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). +### ۱. لایه‌های دسترسی پنل‌ها +* **پنل تدارکات (`procurement`):** + * `full`: دسترسی کامل به کارتابل استعلام‌ها، تایید یا رد پیشنهادها، تامین‌کنندگان و قیمت‌ها. + * `limited`: فقط امکان ثبت استعلام جدید در ویزارد برای پروژه‌های منتسب به کاربر (کاربر پس از ورود مستقیماً به `/wizard` یا `/requester` هدایت می‌شود). +* **پنل انبارداری (`inventory`):** + * `full`: مشاهده موجودی همه انبارها، رهگیری «کالاهای در راه» و کارتابل تایید رسید. + * `limited`: فقط مشاهده و مدیریت انبارهای پروژه‌های تحت عضویت، همراه با دسترسی به ثبت تغییر موجودی کارگاهی (`/inventory/change`). +* **پنل مدیریت پروژه (`pm`):** + * دسترسی به مشاهده یا ویرایش تسک‌ها، چارت گانت، ثبت عیوب و فرم‌های QC در `/panel/pm`. -| What | Where | Credentials | -| --- | --- | --- | -| App | http://localhost (via Traefik) | — | -| Casdoor console | http://localhost:8080 | admin credentials are set when you run the seeder (`CASDOOR_ADMIN_PW`) — never commit them | -| Seeded app users (org `inventory`) | `razaei` (admin), `mousavi` (مدیر تدارکات), `mohaghegh` (مدیر پروژه), `tester` (مدیر پروژه، پروژه «تست») | password from `CASDOOR_SEED_PASSWORD` (bcrypt-hashed at rest — see `backend/tools/seed_casdoor.py`) | - -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`](https://www.google.com/search?q=docs/casdoor-auth.md). - -> The **currently committed seed** (`backups/علی محقق/`) instead ships a -> single admin — `ali.mohaghegh` («علی محقق») — see -> [Restoring the committed seed data](https://www.google.com/search?q=%23restoring-the-committed-seed-data). +### ۲. قوانین و نقش سرپرست پروژه (`supervisor`) +* کاربرانی با نقش `supervisor` تنها در صورتی مجاز به ورود به سامانه هستند که حداقل یک پروژه در جدول `user_project_members` یا `projects.pm_user_id` به آن‌ها منتسب شده باشد. در غیر این صورت، پیام عدم تخصیص پروژه نمایش داده شده و اجازه ورود نخواهند داشت. --- -## 🌐 Working with the deployed system (server) +## 🚀 راهنمای سریع راه‌اندازی محیط توسعه (Docker) -The production deployment of this stack runs on the server and is reachable -at these public addresses (HTTPS): +### پیش‌نیازها +* Docker Desktop (ویندوز) یا Docker Engine + Docker Compose Plugin (لینوکس) +* حداقل ۴ گیگابایت فضای خالی دیسک و اتصال اینترنت برای بارگیری ایمیج‌های اولیه -| What | Address | -| --- | --- | -| **App (ERP)** | https://aramesh.bennu-api-bahrestan.ir/ | -| **Casdoor admin panel** | https://casdoor.bennu-api-bahrestan.ir/ | - -Log in to the app with your Casdoor account (org `inventory`); the role is -assigned inside the app (`users.role` — see «Login» above and -[`docs/casdoor-auth.md`](https://www.google.com/search?q=docs/casdoor-auth.md)). - -### MinIO console on the server (SSH tunnel) - -The MinIO console is deliberately **loopback-only** on the server -(`127.0.0.1:9001`) — verified unreachable from the internet — so the way in -is an SSH tunnel from your machine: - -1. Open PowerShell and start the tunnel (**keep the window open** while you -use the panel): -```powershell -ssh -L 9001:127.0.0.1:9001 @ - -``` - - -You will also land in a normal SSH session — that is fine; the tunnel -lives as long as the window stays open. -2. In your browser, open: **http://localhost:9001** -3. Log in with the production MinIO root credentials from the server's -`/srv/erp/.env` (`MINIO_ROOT_USER` / `MINIO_ROOT_PASSWORD`) — they are -**never** written in this repo or its history. See -[`docs/SECRET-MANAGEMENT.md`](https://www.google.com/search?q=docs/SECRET-MANAGEMENT.md). - -You will see the **`procurement-files`** bucket — the invoices/proformas the -ERP stores, browsable and downloadable from there. - -⚠️ Those credentials are **full admin access to the file storage**. They live -only in the server-side `.env`; if one ever leaks, rotate it immediately -(checklist in `docs/SECRET-MANAGEMENT.md`). - -Close the PowerShell window (or `Ctrl+C`) when you are done to drop the -tunnel. - -Notes from the server setup: - -* The panel is published only on the server's loopback, so the internet -cannot reach it at all — the tunnel is what carries it to your browser. -* Host port `9000` stays reserved for the deploy-webhook receiver, which is -why the console uses `9001`. -* If you ever need the raw S3 API from your machine, or a clickable URL for -the console (e.g. `storage.aramesh.bennu-api-bahrestan.ir` behind Traefik -with a password prompt on top), that can be arranged on request — the -tunnel remains the safer default. - ---- - -## 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 +# ۱. رفتن به پوشه پروژه و ساخت/اجرای کانتینرها 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)`). +تمام سرویس‌ها باید وضعیت `Up` و دیتابیس وضعیت `(healthy)` را نشان دهند. + +### درگاه‌ها و آدرس‌های محلی + +| بخش | آدرس محلی | توضیحات | +|---|---|---| +| **رابط کاربری ERP** | http://localhost | داشبورد اصلی سامانه | +| **پلتفرم PM** | http://localhost/pm | مدیریت پروژه و کنترل کیفیت (قابل دسترس در `/panel/pm`) | +| **مستندات API (Swagger)** | http://localhost:8000/docs | مستندات تعاملی اندپوینت‌های تدارکات | +| **سلامت API** | http://localhost:8000/health/ready | بررسی اتصال دیتابیس، Casdoor و MinIO | +| **کنسول MinIO** | http://localhost:9001 | نام کاربری و رمز پیش‌فرض: `minioadmin` / `minioadmin` | +| **کنسول Casdoor** | http://localhost:8080 | نام کاربری و رمز اولیه: `admin` / `123` | +| **پایگاه داده PostgreSQL** | `localhost:5455` | نام دیتابیس: `procurement`، کاربر: `postgres` | --- -## Verify +## 🤖 ربات هوشمند بله (`procurement-bot`) -| What | Where | -| --- | --- | -| Frontend UI | http://localhost | -| API docs (Swagger) | http://localhost:8000/docs | -| API health | http://localhost:8000/health → `{"status":"ok","service":"procurement-api"}` | -| API readiness (DB + MinIO + Casdoor) | http://localhost:8000/health/ready | -| Metrics | http://localhost:8000/metrics | -| MinIO console | http://localhost:9001 (user/pass `minioadmin`/`minioadmin`) | -| Database | `localhost:5433`, db `procurement`, user/pass `postgres`/`postgres` (Casdoor uses the same instance, db `casdoor`) | - -Automated end-to-end checks (authenticates via `SMOKE_USER` / -`SMOKE_PASSWORD` — the seeder users): - -```powershell -backend\tools\smoke_test.py # read paths -backend\tools\smoke_test_write.py / smoke_test_misc.py - -``` - -> Every API route now requires a Casdoor JWT — a bare -> `curl http://localhost/api/v1/quotes` returns **401** by design. -> Day-2 operations (deploys, backups, monitoring): [`docs/OPERATIONS.md`](https://www.google.com/search?q=docs/OPERATIONS.md). +ربات پیام‌رسان بله به عنوان یک سرویس اختصاصی درون شبکه فعال است: +1. پیام صوتی یا متنی فرستاده شده از طریق هوش مصنوعی (DeepSeek NLU) و تبدیل صوت به متن پردازش می‌شود. +2. قلم‌ها، متریال‌ها، پروژه‌ها و تامین‌کنندگان به صورت فازی جستجو و شناسایی می‌شوند. +3. پیش‌نویس در جدول `bot_drafts` ذخیره شده و شناسه پیش‌نویس تولید می‌شود. +4. کاربر می‌تواند با زدن دکمه روی بله یا مراجعه به لینک مستقیم: + `http://localhost/wizard?draft=` + اطلاعات استخراج‌شده را در ویزارد فرانت‌اند مرور، تکمیل و نهایی کند. +5. راهنمای تکمیلی تنظیم توکن در [bot/docs/SETUP.md](file:///c:/Users/Reza/Desktop/v1.6/bot/docs/SETUP.md) قرار دارد. --- -## MinIO (object storage for invoice / proforma files) +## 🔄 انتقال بین‌کارگاهی کالاها (`project_transfers`) -| 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 - -``` +سامانه دارای سیستم ردیابی انتقال متریال بین کارگاه‌هاست: +* ثبت انتقال از طریق صفحه «تغییر موجودی» با نوع `انتقال بین کارگاهی`. +* وضعیت‌های انتقال: `در حال انتقال (in_transit)`، `تحویل‌شده (received)` و `لغوشده (cancelled)`. +* کارگاه مقصد از طریق زبانه «انتقالات ورودی» در صفحه «کالاهای در راه» اقلام ارسالی را دریافت و به انبارهای خود تخصیص می‌دهد. --- -## Database credentials / connection +## 🛠️ عملیات نگهداری و دیپلوی در سرور (Operations) -```text -Host: localhost -Port: 5433 -Database: procurement -Username: postgres -Password: postgres - -``` - -```powershell -docker exec -it procurement-postgres psql -U postgres -d procurement - -``` - ---- - -## Recovery / seeding - -The databases are **not** in git — Docker volumes hold the data, and -database dumps must never be committed (they contain user rows and signing -material). Two supported ways to bring a fresh stack up: - -1. **Empty boot** — schema v2.6 auto-applies on the first boot of an empty -`postgres_data` volume; then run the seeders: -```powershell -# Casdoor org + app + users (prints/generates credentials — do not commit them) -docker compose run --rm -e CASDOOR_BASE=http://casdoor:8000 api python tools/seed_casdoor.py -# Demo dataset (optional): -docker exec procurement-api sh -c "cd /srv/backend && python -m tools.seed" - -``` - - -2. **Restore your own dump** — create dumps on the server (kept server-side, -e.g. `/srv/erp/backups/`), never in git: -```powershell -docker exec procurement-postgres pg_dump -U postgres -d procurement -Fc > /srv/erp/backups/procurement-$(date +%F).dump -docker exec procurement-postgres pg_dump -U postgres -d casdoor -Fc > /srv/erp/backups/casdoor-$(date +%F).dump - -``` - - -Restore with `pg_restore --clean --if-exists` (stop `api` + `casdoor` -first — this **replaces all data**). The scheduled backup sidecar -(see `docs/OPERATIONS.md`) automates this. - -## 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) and **required on -every API route** except `/health`, `/health/ready` and `/auth/login` -(401 without a token, 403 without a role). The former dev-header fallback -(`X-User-Role` / `X-User-Name-B64`) is disabled unless -`PROCUREMENT_DEV_LOGIN_ENABLED=true` — never enable it in production. -* Roles live in the app's `users` table (Casdoor is identity-only): `pm`, -`procurement_manager`, `admin`. Role changes are **admin-only** (RBAC); -the procurement manager can only assign projects to project managers. -The admin has a dedicated panel at `/admin` (user sync from Casdoor + -grant/revoke «مدیر تدارکات»). -* **Partial goods receipt** («رسید جزیی») is supported in «کالاهای در راه»: -at least one item with a valid quantity is enough to submit; other items -stay in transit. The procurement ledger shows «رسیده X از Y» / «در راه Z» -badges and a «رسید جزیی» badge on the quote. -* **One PostgreSQL instance** serves both the app (`procurement`) and Casdoor -(`casdoor`) — the separate casdoor-postgres container is gone (data was -dumped/restored; see `docs/casdoor-auth.md`). -* **Traefik v3** is the public edge (ports 80/443); the frontend nginx only -serves the SPA and proxies `/api` internally. Production (real domains, -HTTPS via Let's Encrypt, HTTP→HTTPS redirect): -`docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build` -(see the prod file header for the required env vars). -* 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. -* **Material-Supplier Lookup**: Clicking a material in the catalog (e.g., on the `/units` page) dynamically fetches its assigned suppliers (`GET /api/materials/{id}/suppliers`). The backend uses an atomic JOIN to guarantee accurate supplier data (avoiding SQLAlchemy identity-map mismatches), and the UI displays a clean empty state («تامین‌کننده‌ای برای این متریال ثبت نشده است») if none exist. -* 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`. - -``` +* **دیپلوی خودکار:** سرور با هر Push به برنچ `production` از طریق وب‌هوک اختصاصی به صورت خودکار بیلد و بالا می‌آید. راهنمای کامل: [docs/OPERATIONS.md](file:///c:/Users/Reza/Desktop/v1.6/docs/OPERATIONS.md). +* **پشتیبان‌گیری پایگاه داده:** سرویس `db-backup` به صورت روزانه از هر دو پایگاه داده `procurement` و `casdoor` فایل‌های `.dump` تولید و در پوشه `backups/` نگهداری می‌کند. +* **مانیتورینگ و مشاهده‌پذیری:** ابزارهای Prometheus، لاگ‌های Loki و ردیابی خطاهای GlitchTip در پوشه [monitoring/](file:///c:/Users/Reza/Desktop/v1.6/monitoring/README.md) سازمان‌دهی شده‌اند. diff --git a/bot/README.md b/bot/README.md index 50350d0..6aa05d9 100644 --- a/bot/README.md +++ b/bot/README.md @@ -1,120 +1,70 @@ -# procurement_ai_agent — Bale chatbot for the procurement ERP +# procurement_ai_agent — ایجنت هوشمند بله برای سامانه ERP -A **Bale messenger bot** that turns Persian **chat messages and voice notes** -into procurement actions in the -[procurement ERP](https://git.bennu-api-bahrestan.ir/ali_mohaghegh/ERP) — -draft-first: it captures what it understood, tells you **what it did** and -**what is still empty**, and **commits only after you approve** with a ✅ button. +بات پیام‌رسان بله (Bale Messenger Bot) که پیام‌های صوتی و متنی فارسی کاربران را دریافت کرده و با استفاده از مدل‌های هوش مصنوعی (DeepSeek NLU + Whisper STT) آن‌ها را به اقدامات و پیش‌نویس‌های استعلام در سامانه ERP تبدیل می‌کند. -``` -you (Bale, text/voice) ┌─────────────────────────────────┐ - │ getUpdates (long poll) │ procurement_ai_agent │ - ▼ │ ffmpeg → STT (Persian) │ -┌──────────────────┐ POST {base}/bot │ LLM → intent + entities │ -│ tapi.bale.ai │◄───────────────────────►│ fuzzy resolve → draft payload │ -└──────────────────┘ sendMessage / buttons │ review + «چه چیزهایی خالی مونده»│ - └───────────────┬─────────────────┘ - │ HTTP + X-Actor-Id - ▼ - ┌─────────────────────────────────┐ - │ ERP api (/api/v1) │ - │ quotes · suppliers · materials│ - └─────────────────────────────────┘ +--- + +## 🏗️ وضعیت استقرار در استک ERP + +این ایجنت **به صورت سرویس بومی (`procurement-bot`) مستقیماً درون `docker-compose.yml` ریشه پروژه** تعریف شده است و نیازی به نصب یا راه‌اندازی دستی ندارد. + +* **نوع اتصال:** Long-polling از سرور بله (`tapi.bale.ai`) — بدون نیاز به باز کردن پورت خارجی، وب‌هوک یا TLS. +* **ارتباط با بک‌اند:** به صورت مستقیم و درون‌شبکه‌ای با سرویس `api` در آدرس `http://api:8000/api/v1`. +* **پایگاه داده:** استفاده از جدول `bot_drafts` در پایگاه‌داده مشترک PostgreSQL. + +```text +کاربر (بله: متن یا صوت) + │ getUpdates (Long-polling) + ▼ +┌─────────────────────────────────┐ +│ procurement_ai_agent │ +│ ffmpeg → STT تبدیل صوت به متن │ +│ LLM → استخراج نیت و موجودیت‌ها │ +│ Fuzzy Match → انطباق با ERP │ +│ ایجاد پیش‌نویس در bot_drafts │ +└────────────────┬────────────────┘ + │ + ├── ثبت نهایی از بله با دکمه تایید + └── یا باز کردن مستقیم در ویزارد وب: + /wizard?draft= ``` -## What it can do +--- -| Activity | Example (voice or text) | Committed via | +## 🌟 قابلیت‌ها و کاربردها + +| فعالیت | نمونه پیام (صوت یا متن) | اقدام نهایی | |---|---|---| -| Register a supplier quote | «سازان نو برای پروژه برج آسمان ۵۰۰ کیلو میلگرد A3 سایز ۱۴، هر کیلو ۴۵ تومن، پرداخت ۳ فاز» | `POST /quotes` | -| Add a supplier | «تأمین‌کننده جدید پروفیل بر، دسته لوله و اتصالات، تلفن ۰۹۱۲…» | `POST /suppliers` | -| Add a material | «کالای جدید میلگرد A3 سایز ۱۸ با واحد کیلوگرم» | `POST /materials` | -| Status queries | «استعلام‌های در انتظار؟» / «کدام‌ها به‌زودی منقضی می‌شوند؟» | `GET /quotes?…` | -| Accept a quote | «استعلام سازان نو را قبول کن» | `PATCH /quotes/{id}/accept` | -| Announce a delivery | «اقلام سازان نو رسید، ۵۰۰ و ۲۰۰» | `PATCH /quotes/{id}/arrive-items` | +| **ثبت استعلام جدید** | «سازان نو برای پروژه برج آسمان ۵۰۰ کیلو میلگرد A3 سایز ۱۴، هر کیلو ۴۵ تومن، پرداخت ۳ فاز» | `POST /quotes` | +| **تعریف تأمین‌کننده** | «تأمین‌کننده جدید پروفیل بر، دسته لوله و اتصالات، تلفن ۰۹۱۲…» | `POST /suppliers` | +| **تعریف متریال جدید** | «کالای جدید میلگرد A3 سایز ۱۸ با واحد کیلوگرم» | `POST /materials` | +| **استعلام وضعیت** | «استعلام‌های در انتظار؟» / «کدام‌ها به‌زودی منقضی می‌شوند؟» | `GET /quotes` | +| **پذیرش استعلام** | «استعلام سازان نو را قبول کن» | `PATCH /quotes/{id}/accept` | -### The draft → approve loop +--- -1. Send a message or voice note. Voice → ffmpeg → STT; text/STT text → LLM - extracts a typed **intent + entities** (JSON mode, Persian digits - normalized). -2. Names are fuzzy-matched against the ERP. Several candidates → inline - **pick buttons**; no match → listed as missing. -3. The bot replies with a **review card**: everything captured + a - ✅/⚠️/❌ list of what is still empty. -4. Keep chatting to refine («قیمت میلگرد ۴۷ شد») — the open draft updates and - re-renders. Drafts survive bot restarts (postgres-backed, TTL-swept). -5. **Nothing is written to the ERP until you tap ✅.** After commit you get the - created quote id and the fields left empty. +## 🔗 حلقه پیش‌نویس و تایید (Draft-First Loop) -### Team access & attribution +1. کاربر پیام صوتی یا متنی می‌فرستد. صوت به متن تبدیل شده و مدل هوش مصنوعی موجودیت‌ها را استخراج می‌کند. +2. اسامی تامین‌کننده، متریال، پروژه و واحدها با کاتالوگ ERP تطبیق داده می‌شوند. +3. کارت مرور پیش‌نویس همراه با فیلدهای مشخص‌شده و اقلام خالی («چه چیزهایی ناقص است») برای کاربر ارسال می‌شود. +4. **دو روش برای تکمیل و ثبت نهایی وجود دارد:** + * **از طریق چت بله:** با ارسال پیام‌های اصلاحی و در نهایت لمس دکمه «✅ ثبت نهایی». + * **از طریق پنل وب ویزارد:** با کلیک روی لینک مستقیم `/wizard?draft=` که اطلاعات به صورت خودکار در فرم ۵ مرحله‌ای ویزارد بارگذاری می‌شود و کاربر می‌تواند فایل فاکتور را نیز ضمیمه کند. -Each member links their Bale chat once: `/start` → Casdoor username → password -(validated via the ERP's real `POST /auth/login`, used once, never stored). -Every mutating call carries `X-Actor-Id: ` so `quote_events.actor` -records the **human** who asked. +--- -Commands: `/start` · `/help` · `/drafts` · `/cancel` · `/whoami` · `/unlink` +## ⚙️ متغیرهای محیطی و پیکربندی -## Quick start (Docker) +تنظیمات بات از طریق فایل `.env` در ریشه پروژه خوانده می‌شود: -```bash -cp .env.example .env # fill PROCUREMENT_BOT_BOT_TOKEN + AI_API_KEY -docker build -t procurement-ai-agent . -docker run -d --name procurement-bot --env-file .env \ - --add-host host.docker.internal:host-gateway \ - procurement-ai-agent -docker logs -f procurement-bot +```env +BALE_BOT_TOKEN=توکن_دریافتی_از_بات_فادر_بله +BALE_API_BASE=https://tapi.bale.ai +AI_BASE_URL=https://api.deepseek.com +AI_API_KEY=کلید_سرویس_هوش_مصنوعی +AI_LLM_MODEL=deepseek-flash +BALE_ADMIN_CHAT_IDS=شناسه_عددی_مدیران_در_بله ``` -Or as part of the ERP stack — see [`integration/`](integration/README.md) -(compose service + the one tiny ERP-side patch). - -Full setup, env-var reference, flows and troubleshooting: -**[docs/SETUP.md](docs/SETUP.md)**. - -## Architecture - -``` -app/ -├── main.py ensure bot tables → sweeper task → getUpdates long-poll loop -├── config.py pydantic-settings, PROCUREMENT_BOT_ prefix -├── bale/client.py Telegram-compatible Bale API (poll, send, edit, buttons, files) -├── api/client.py ERP /api/v1 client (X-Actor-Id attribution, error envelope) -├── stt.py ffmpeg (OGG/Opus → MP3) → OpenAI-compatible /audio/transcriptions -├── nlu.py Persian intent+entity extraction (JSON-mode chat completions) -├── resolve.py fuzzy name→id matching (difflib over ilike search), TTL caches -├── drafts.py draft store · QuoteCreate payload builder · missing-field logic -├── keyboards.py inline keyboards (callback_data ≤ 64 B op-codes) -├── texts.py Persian message templates -├── runtime.py context, link store, in-memory pending flows -├── models.py bot_links / bot_drafts / bot_messages / bot_meta (own schema) -└── handlers/ dispatch · commands · callbacks · links · - quote · supplier · material · queries · decisions -``` - -Design notes: - -- **Telegram-compatible Bale API** (`tapi.bale.ai`): getUpdates long polling — - no public port, no webhook, resumable offset persisted across restarts. -- **Draft-first**: `bot_drafts.payload` holds a talking-friendly JSON that is - converted into the exact `POST /quotes` request body (temp_id - cross-references) only on approval; the API deliberately tolerates - incomplete quotes, so partial commits are explicit, never accidental. -- **Accept flow echoes the termsheet's existing `schedule_steps`** back to - `PATCH /quotes/{id}/accept` (the API replaces steps with what it receives). -- **Persian-aware matching**: Persian/Arabic digit normalization, ZWNJ folding, - Arabic ya/ka folding, difflib ranking on top of the API's ilike search. -- **Voice notes** arrive as OGG/Opus; ffmpeg converts to mono 16 kHz MP3 before - STT. The LLM provider and the STT provider are configured independently - (e.g. DeepSeek for NLU + any whisper-compatible endpoint for voice). - -## Testing - -An offline end-to-end harness stubs Bale/ERP/AI and drives the real handler -pipeline with fake updates — no token, DB or API key needed: - -```bash -pip install -r requirements.txt -python tools/smoke_test.py # → ALL PASSED: 48 passed -``` +راهنمای گام‌به‌گام اتصال و عیب‌یابی در [docs/SETUP.md](docs/SETUP.md) در دسترس است. diff --git a/pm/README.md b/pm/README.md index 64bc04d..0555831 100644 --- a/pm/README.md +++ b/pm/README.md @@ -1,91 +1,59 @@ -# PM — سامانه یکپارچه مدیریت پروژه‌های ساخت و کنترل کیفیت +# PM — سامانه یکپارچه مدیریت پروژه‌های ساخت و کنترل کیفیت (Aramesh PM) -اپلیکیشن موبایل‌محور و تحت وب برای مدیریت جامع پروژه‌های عمرانی و ساخت: مدیریت سلسله‌مراتب فعالیت‌ها (WBS)، زمان‌بندی و گانت چارت، مسیر بحرانی (CPM)، سیستم پیشرفته کنترل کیفیت (QC)، مدیریت مصالح و انبار (با اتصال به ERP) و داشبورد عملیاتی روزانه. +پلتفرم تخصصی مدیریت پروژه‌های عمرانی، کنترل کیفیت و زمان‌بندی کارگاهی که به صورت وندور شده و یکپارچه در کنار سامانه ERP قرار دارد. --- -## دسترسی سریع +## 🏗️ نحوه استقرار و دسترسی در سامانه ERP -| سامانه | آدرس شبکه محلی | آدرس محلی سیستم | -|---|---|---| -| **PM (وب + نمای موبایل)** | http://192.168.1.103:8083 | http://localhost:8083 | -| **PM API Health** | http://192.168.1.103:8083/api/v1/health | http://localhost:8083/api/v1/health | +پلتفرم PM در استک یکپارچه پروژه از دو سرویس داکر تشکیل شده است: +* **`pm-backend` (`pm-api`):** وب‌سرویس پایتون مبتنی بر FastAPI روی شبکه داخلی استک. +* **`pm-frontend` (`pm-frontend`):** اپلیکیشن کلاینت React با سرور داخلی Nginx که از طریق ریورس‌پروکسی Traefik زیر مسیر `/pm` قرار گرفته است. -**ورود پیش‌فرض:** `admin` / `pm123456` (قابل تغییر از طریق فایل `.env`) +### راه‌های دسترسی: +1. **از داخل رابط کاربری ERP:** با ورود به حساب کاربری (نقش‌های مجاز یا پنل PM) و انتخاب منوی **«مدیریت پروژه (PM)»** در آدرس `/panel/pm` (به صورت آی‌فریم روان با سشن یکپارچه). +2. **دسترسی مستقیم مرورگر:** در آدرس `http://localhost/pm` (یا دامنه عملیاتی با پسوند `/pm/`). --- -## معماری سامانه +## 🗄️ پایگاه داده و احراز هویت مشترک -``` -PM Frontend (React 19, Tailwind CSS, تقویم شمسی, نمای موبایل و دسکتاپ) - │ /api/v1 - ▼ -PM Backend (FastAPI, Python 3.12, SQLAlchemy 2.0 Async) - │ - ├── Projects & Tasks Engine (سلسله‌مراتب نامحدود WBS، زمان‌بندی CPM، گانت) - ├── QC Module (قالب‌های سراسری، تعریف‌های مستقل تسک، چک‌لیست، ثبت عیوب) - ├── Materials & Resources (تخصیص نیروی انسانی، ماشین‌آلات، مصالح و رزرو انبار) - ├── ERP Integration (استعلام موجودی کاتالوگ و انبارهای پروژه) - └── PM Postgres (ذخیره‌سازی بومی داده‌ها با پشتیبانی از JSONB و UUID) -``` +* **پایگاه‌داده مشترک:** سرویس PM مستقیماً به همان دیتابیس `procurement` در کانتینر Postgres متصل می‌شود. جداول اختصاصی PM (`pm_projects`, `pm_tasks`, `pm_qc_*`, `pm_defects`, ...) در زمان بوت اولیه به صورت خودکار و بدون تداخل با جداول تدارکات ایجاد می‌شوند (`schema_sync.py`). +* **احراز هویت یکپارچه (SSO):** ورود با همان حساب کاربری Casdoor انجام شده و سطح دسترسی پنل PM (`user_panels.pm`) کنترل می‌شود. --- -## مالکیت داده +## ⚙️ قابلیت‌های اصلی پلتفرم PM -| حوزه داده | متولی و مالک | توضیحات | -|---|---|---| -| پروژه‌ها، فعالیت‌ها، وابستگی‌ها، مایلستون‌ها | **PM Platform** | مدیریت کامل در دیتابیس بومی PM | -| چک‌لیست‌ها و کنترل کیفیت (QC) | **PM Platform** | پیش از اجرا، حین اجرا و پس از اجرا | -| ثبت عیوب و اقدامات اصلاحی | **PM Platform** | الصاق تصویر، شدت عیب، پیگیری رفع | -| کاتالوگ مصالح و موجودی واقعی انبار | **ERP** | استعلام برخط موجودی از طریق API | -| رزرو مصالح و درخواست‌های خرید | **PM Platform** | رزرو نرم بدون دستکاری انبار تا زمان تأیید | +### ۱. مدیریت زمان‌بندی و شکست کار (WBS & CPM Engine) +* ساختار شکست کار با عمق نامحدود (فاز، بخش، فعالیت، زیرفعالیت). +* روابط وابستگی چهارگانه بین فعالیت‌ها (`FS`, `SS`, `FF`, `SF`) به همراه زمان وقفه (Lag). +* محاسبه خودکار مسیر بحرانی (Critical Path Method) و شناوری کل فعالیت‌ها. +* گانت چارت شمسی و تعریف مایلستون‌های کلیدی پروژه. + +### ۲. چرخه سه‌مرحله‌ای کنترل کیفیت (QC Module) +* **قالب‌های عمومی بازرسی (QC Templates):** تعریف چک‌لیست‌های استاندارد کیفیت برای انواع فعالیت‌های ساختمانی. +* **مراحل ارزیابی:** + * **پیش از اجرا (`pre`):** دروازه ورود به تسک؛ تا زمان تایید این مرحله، پیشرفت تسک نمی‌تواند بیشتر از ۰٪ شود. + * **حین اجرا (`during`):** ثبت بازرسی‌های فنی حین عملیات اجرایی. + * **پس از اجرا (`after`):** کنترل نهایی؛ تا زمان تایید تمامی سوالات الزامی، پیشرفت تسک اجازه ۱۰۰٪ شدن ندارد. +* **ثبت و پیگیری عیوب (Defects):** ثبت عیوب همراه با تصاویر، سطح بحرانی بودن و لزوم بازرسی مجدد پس از اقدامات اصلاحی. + +### ۳. مدیریت منابع و اتصال به انبار کارگاه +* امکان تخصیص متریال و ثبت رزرو نرم با استعلام موجودی واقعی انبارهای متناظر در ERP. --- -## قابلیت‌های کلیدی - -### ۱. مدیریت زمان‌بندی و گانت چارت (CPM Engine) -- ایجاد پروژه‌ها با کدهای اختصاصی و تیم پروژه -- ساختار شکست کار (WBS) در عمق‌های نامحدود (فاز، بخش، فعالیت، زیرفعالیت) -- وابستگی‌های چهارگانه بین فعالیت‌ها (`FS`, `SS`, `FF`, `SF`) همراه با روزهای تأخیر (Lag) -- محاسبه خودکار مسیر بحرانی (Critical Path) و شناوری کل فعالیت‌ها -- تعریف مایلستون‌ها و نقاط عطف کلیدی پروژه - -### ۲. چرخه سه‌مرحله‌ای کنترل کیفیت (QC) -- **مراحل ارزیابی:** پیش از اجرا (`pre`) · حین اجرا (`during`) · پس از اجرا (`after`) -- **قوانین دروازه‌ای سرور:** - - فعالیت تا زمان تأیید الزامات پیش از اجرا اجازه شروع (پیشرفت > ۰) ندارد. - - فعالیت تا زمان پاس شدن همه الزامات الزامی اجازه رسیدن به ۱۰۰٪ ندارد. -- ثبت عیوب همراه با تصاویر و الزام به بازرسی مجدد پس از اصلاح. - -### ۳. مدیریت منابع و ارتباط با ERP -- تخصیص نفرات، ماشین‌آلات و مصالح به تفکیک فعالیت -- اتصال پروژه به پروژه متناظر در ERP جهت استعلام موجودی انبارهای کارگاه -- رزرو نرم مصالح جهت جلوگیری از تداخل مصرف در بخش‌های مختلف پروژه - -### ۴. تقویم و تاریخ‌های شمسی -- تقویم بومی جلالی بدون خطا و با رعایت روزهای کاری -- ثبت و نمایش روان تاریخ‌ها در رابط کاربری به زبان فارسی - ---- - -## راه‌اندازی و اجرا - -اجرای آسان با اسکریپت پاورشل یا داکر کامپوز: +## 🧪 اجرای آزمایشی مستقل (Standalone Dev) +در صورت تمایل به اجرای مستقل پلتفرم PM برای تست‌های ایزوله: ```powershell -# اجرای خودکار از پوشه PM: +# از درون پوشه pm: powershell -ExecutionPolicy Bypass -File .\start.ps1 ``` - -یا مستقیماً با داکر: -```powershell -docker compose up -d --build -``` +این حالت روی پورت محلی `8083` به صورت ایزوله اجرا خواهد شد. --- -## قرارداد API -مستندات کامل اندپوینت‌ها: [`API_CONTRACT.md`](API_CONTRACT.md) +## 📑 قرارداد و مستندات API +قرارداد جامع اندپوینت‌ها و نمونه پیام‌ها در فایل [API_CONTRACT.md](API_CONTRACT.md) و راهنمای تفصیلی ساختار جداول در [DATABASE_GUIDE.md](DATABASE_GUIDE.md) مستند شده است.