هنداف توسعهدهنده
معماری، مدل داده، قراردادها، جدولهای خودکار از روی کد، امنیت، یکپارچگیها و مسیر انتشار. آنچه «خودکار» است از همین کد ساخته میشود و هرگز با پروژه ناهمگام نمیماند.
پارامتر قابلویرایش
۶۴
ماژول مدیریت
۳۲
نقش مدیریتی
۸
مجوز
۴۱
ردیف فهرست طراحی
۲۷۰
هنداف دولوپر
ابعاد فنی پروژه، معماری، مدل داده، قراردادها، تست، امنیت و مسیر رسیدن از نمونهی تعاملی به محصول واقعی.
خلاصهی فنی
| مورد | مقدار |
|---|---|
| چارچوب | Next.js 16 (App Router، خروجی استاتیک `output: export`)، React 19، TypeScript |
| استایل | Tailwind CSS v4 با توکنهای `@theme inline` در `src/app/globals.css`؛ فونت Vazirmatn |
| نقشه | Leaflet + کاشیهای OpenStreetMap (قابل تعویض با `NEXT_PUBLIC_TILE_URL`) |
| آیکن | lucide-react (فقط SVG) |
| حالت | یک State واحد در IndexedDB (`kamionet/kv/state-v3`)، BroadcastChannel بین تبها، `act(fn)` برای تغییر همزمان با ذخیرهی debounce شده |
| پشتیبان آینده | Supabase/Postgres 16: مایگریشنها در `supabase/migrations` (۳ فایل) و تست در `supabase/tests` |
| تست | `npm run test:ledger` (ثابتهای دفتر کل) + e2e با Playwright در `tests/e2e/*.mjs` |
| حجم کد | حدود ۳٬۵۰۰ خط موتور (`src/lib/engine`) + صدها کامپوننت؛ سید دترمینیستیک ~۷۰۰ سفارش (~۶ مگابایت) |
ساختار پوشهها
| مسیر | نقش |
|---|---|
| src/app | مسیرها: `/`, `/login`, `/app/*` (صاحب بار), `/driver/*` (راننده), `/admin/[[...m]]` (کنسول ۳۰ ماژولی), `/track`, `/waybill`, `/certificate`, `/blog`, `/handoff` |
| src/lib/engine | منطق کسبوکار خالص (بدون UI): core, orders, pay, payout, finance, trust, admin, kyc, profiles, pro, avail, radar, drivers, stats, demo |
| src/lib/ledger.ts | دفتر کل دوبل با ریال صحیح؛ `post()`, `bal()`, `trialBalance()`, `checkInvariants()` |
| src/lib/store.ts | ذخیرهساز، نشستها (هر پورتال جدا)، `useStore`, `act`, `startViewAs` (نمایش بهجای کاربر، فقطخواندنی) |
| src/lib/config.ts | جدول پارامترهای قابلویرایش (`CONFIG_DEFS`) و `cv(state, key)` |
| src/lib/mask.ts | مرز دید: `viewOrder()` سه سطح guest / public / full (معادل RPC/View در Postgres) |
| src/lib/seed | سید دترمینیستیک که موتور واقعی را اجرا میکند (نه دادهی دستی) |
| src/components | ui.tsx (اتمها)، molecules، portal/Shells، admin/{DataTable,kit,charts,modules}، driver، order، wizard، landing |
| tests/e2e | سناریوهای مرورگری؛ سرو `out/` روی پورت ۴۱۷۳ |
قراردادهای معماری که نباید شکسته شوند
- همهی منطق پول فقط از `ledger.post()` عبور میکند؛ هیچ UI یا سید مستقیم موجودی را تغییر نمیدهد.
- ریال صحیح؛ هیچ اعشاری در پول. تبدیل به تومان فقط در نمایش (`fmtToman`).
- هر تراکنش دفتر کل متوازن است و هیچ کیف پولی منفی نمیشود (`checkInvariants`).
- هر نمایش سفارش از `viewOrder()` میگذرد؛ فیلد حساس هرگز به UI سطح پایینتر نمیرسد.
- هر اقدام ادمین از `guard(perm)` میگذرد و در ممیزی ثبت میشود؛ مبلغ بالاتر از سقف نقش → `requestApproval` (تأیید دو نفره).
- عدد کسبوکاری هاردکد نشود؛ در `CONFIG_DEFS` اضافه و با `cv()` خوانده شود. قابلیتهای روشن/خاموش با `feature.*` و `applyFlags` اعمال میشوند.
- اپ بدون سرور اجرا میشود (static export)؛ هر `fetch` آینده باید پشت یک لایهی داده (Repository) بیاید تا سید/IndexedDB قابل تعویض بماند.
- UI فقط خوانندگی `useStore()` و اجرای `act(s => engine(...))` است.
مدل دادهی اصلی (src/lib/types.ts)
| موجودیت | کلیدها / نکته |
|---|---|
| Person / ShipperProfile / DriverProfile / AdminUser | هر Person یک شماره دارد؛ پروفایل نقشها جدا. DriverProfile: kyc, docs (DocFile با notes), vehicle (make/model/year/thermo), pro, clean, controls, strikes, declaredTrips |
| Order | status (۱۷ حالت)، events[] (لاگ زماندار)، waybills[] (نسخهها)، officialDoc، insurance، paid، settlement، consignee{token,otp}، mismatchId |
| Payment / TransferReceipt / Payout / PayoutBatch / Refund / Debt / Invoice / Coupon / Incentive | همه به دفتر کل با `ref` وصلاند (orderId, personId, …) |
| LedgerEntry | txId, account, amount (بدهکار +، بستانکار −)، ref؛ حسابها: BANK, GATEWAY, SUSPENSE, ESCROW:{order}, W:S:{id}, W:D:{id}:{pending|avail|hold}, REV:*, EXP:* |
| Availability | اعلام یکپارچهی آزادی/مسیر راننده: مبدأ، مقصدها، بازه، بازهی قیمت، بازهی وزن، نوع بار، شرایط پرداخت، انحراف مجاز، کمک در بارگیری، انتظار، پذیرش خودکار |
| Ticket / Review / RuleDoc / Notification / SmsLog / AuditEntry / Approval / RiskFlag | پشتیبانی و حاکمیت |
| Chat / CallLog / Complaint | گفتگوی دو طرف هر سفارش (`orderId`)، تماس شبیهسازیشده با وضعیت RINGING/ACTIVE/ENDED/MISSED/DECLINED، شکایت با وضعیت OPEN/ANSWERED/RESOLVED/ESCALATED و لینک به Ticket |
| ConfigState | values + history + scheduled (اعمال از فردا) |
نگاشت به Postgres/Supabase (مسیر محصول واقعی)
- جداول مایگریشن فعلی: `app_config, profiles, driver_profiles, orders, order_private, order_events, order_media, rate_table` + RPC `claim_order`, `cancel_order`؛ تست با `bash supabase/tests/run.sh` (نیازمند Postgres 16 محلی).
- RLS: دید guest/public/full با View و RPC پیاده میشود؛ `order_private` آدرس/تلفن را تا بعد از بیعانه پنهان نگه میدارد.
- دفتر کل: جدول `ledger_entries` با constraint مجموع هر tx = ۰ (trigger deferred) و ایندکس روی (account, at)؛ هرگز UPDATE/DELETE.
- ایدمپوتنسی پرداخت: کلید یکتا روی `idem_key` (در نمونه `txKeys`).
- موتور (engine) باید به توابع/ترنزاکشن سمت سرور منتقل شود؛ کلاینت فقط RPC صدا بزند. ترتیب پیشنهادی: auth → orders/claim → payments+ledger → payouts → admin.
- Realtime: کانال برای وضعیت سفارش، تلمتری و اعلانها؛ جایگزین BroadcastChannel/polling فعلی.
- فایلها (عکس مدارک، حوالهی رسمی): Storage خصوصی با لینک امضاشده؛ در نمونه data URL است.
قراردادهای API پیشنهادی (از روی توابع موتور)
| عمل | تابع نمونه | ورودی → خروجی |
|---|---|---|
| ثبت سفارش | createOrders | OrderInput → {ids} |
| رزرو / تأیید راننده | claimOrder / confirmAssign | orderId → status |
| پرداخت | pay | {purpose, amount, method, orderId} → Payment |
| اجرای سفر | startToPickup / arrivePickup / startTrip / arriveDelivery / deliver | مدیا + کد گیرنده |
| مغایرت | reportMismatch / respondMismatch / resolveMismatch | — |
| آزادی راننده | announce / suggestFree / loadsForMe / requestFreeDriver | — |
| گفتگو و تماس | sendChat / startCall / answerCall / endCall (در production: WebSocket + VoIP/ماسک شماره) | فقط دو طرف سفارش |
| شکایت | fileComplaint / replyComplaint / resolveComplaint / escalateComplaint / adminResolveComplaint | ارجاع خودکار بعد از مهلت |
| رادار | radarLoads (کلاینت) → در آینده `GET /loads/near?lat&lng&radius` یا `route` | فقط وقتی خودرو خالی است |
| حوالهی رسمی | uploadOfficialDoc | orderId + فایل + شماره |
| مالی ادمین | payoutAction / createBatch / batchAction / createRefund / dailyClose / lockPeriod | با guard و approval |
متغیرهای محیطی و دستورها
| نام | کاربرد |
|---|---|
| NEXT_PUBLIC_BASE_PATH | مسیر پایه برای GitHub Pages (مثلاً /Kamionet_test) |
| NEXT_PUBLIC_DEMO_MODE | ۰ = حذف حسابهای دمو و کارگردان دمو؛ پیشفرض روشن |
| NEXT_PUBLIC_TILE_URL | آدرس کاشی نقشهی فارسی (نشان/Map.ir) |
| NEXT_PUBLIC_SITE_URL | دامنه برای sitemap و canonical |
| npm run dev / build | توسعه / خروجی استاتیک در `out/` |
| npm run test:ledger | تست ثابتهای دفتر کل روی سید کامل |
| node tests/e2e/<name>.mjs | e2e؛ نیازمند `npx serve out -l 4173` و CHROMIUM_PATH |
| node scripts/gen-trucks.mjs | ساخت دارایی تصاویر خودرو |
تست و کیفیت
- e2e فعلی: auth, landing, shipper, driver, m4 (مغایرت/رهگیری/گواهی), admin, m6 — همه باید قبل از هر انتشار سبز باشند.
- تست ثابت دفتر کل پس از سید و پس از مسیرهای UI اجرا میشود.
- پیشنهاد: افزودن تست واحد برای engine (vitest) و تست تصویری (Playwright snapshots) برای Design System.
- لینت/فرمت هنوز پیکربندی نشده؛ `tsc --noEmit` شرط ادغام است.
امنیت و حریم خصوصی
- نمونه: هر دادهای در مرورگر است؛ برای محصول واقعی همهی قوانین دید باید سمت سرور (RLS) اعمال شود.
- کد تحویل گیرنده و آدرس دقیق هرگز در پاسخ API نقشهای غیرمجاز نباشد (در نمونه فقط با mask.ts پنهان میشود، نه امن).
- OTP ورود: در نمونه ثابت ۱۲۳۴۵ است؛ باید با ارائهدهندهی پیامک، نرخمحدودیت و قفل جایگزین شود.
- احراز کد ملی/سیمکارت (شاهکار) و تطبیق شبا در حالت تست شلاند؛ برای production اجباری است.
- ذخیرهی مدارک: رمزنگاری در سکون، دسترسی با نقش `drivers.kyc`، ممیزی هر مشاهده.
- نقشها و سقف تأیید در `ROLE_PERMS` و `CEILINGS`؛ تغییر آنها حساس است.
- ۲FA ادمین در داده هست ولی اعمال نشده؛ باید فعال شود.
- قوانین و متنهای حقوقی نیازمند بازبینی حقوقیاند.
کارایی و بودجه
- بار اولیه: سید در IndexedDB ساخته میشود (~۶ مگابایت)؛ بعدیها فوری.
- جدولهای ادمین: صفحهبندی ۲۵ ردیفی؛ برای دیتای واقعی صفحهبندی سمت سرور لازم است.
- نقشه با dynamic import و بدون SSR؛ خوشهبندی مارکر برای بیش از ۲۰ بار.
- پیشنهاد بودجه: LCP < ۲٫۵s روی ۴G، JS اولیه < ۲۰۰KB gz در صفحهی لندینگ.
رصد و رخدادها
- رخدادهای پیشنهادی: order_started/step/submitted، deposit_paid/expired، claim, availability_created, radar_alert_shown/clicked, kyc_step_completed, sensor_linked, support_opened, official_doc_ready.
- ممیزی (`audit`) محل ثبت اقدامهای ادمین/سیستم است و باید به Log پایدار منتقل شود.
- خطاهای کلاینت: Sentry یا مشابه؛ برای صف آپلود آفلاین لاگ ویژه.
بدهیهای فنی و محدودیتهای شناختهشده
- همهی سرویسهای بیرونی شبیهسازیاند (درگاه، پیامک، شاهکار، شبا، GPS/سنسور، بیمهگر).
- حوالهی رسمی/عکسها data URL هستند و حجم state را بالا میبرند.
- مدل/سال خودرو توسط راننده تایپ میشود و تطبیق خودکار ندارد.
- رادار: موقعیت با geolocation مرورگر؛ در اپ بومی باید با سرویس پسزمینهی مجاز و صرفهجویی باتری بازنویسی شود.
- نقشه: کاشی OSM برای production مناسب نیست؛ ارائهدهندهی فارسی لازم است.
- ESLint/Prettier پیکربندی نشده؛ تست واحد ندارد.