feat: TASK-113 - add CSV/Excel B2B wholesale price list export capability

This commit is contained in:
parsa aghaei 2026-07-26 15:24:01 +03:30
parent 201aebd2f5
commit 7e17f6840c
8 changed files with 151 additions and 154 deletions

View File

@ -16,8 +16,12 @@ You are the **Lead Software Auditor**. Your core objective is to perform a rigor
- Monolithic single-file components (>300 lines of code): **-10 points** - Monolithic single-file components (>300 lines of code): **-10 points**
- Missing type declarations / strict mode configuration (`tsconfig.json` without strict mode): **-10 points** - Missing type declarations / strict mode configuration (`tsconfig.json` without strict mode): **-10 points**
- Minimum score bound is 0. Arbitrary/hardcoded guessing of health score is strictly forbidden. - Minimum score bound is 0. Arbitrary/hardcoded guessing of health score is strictly forbidden.
2. **Deep Directory Scanning**: Perform a recursive scan of source files rather than superficial top-level checks. 2. **Code Coverage Ratio Rule (Task Density Enforcement)**:
3. **Forbidden Actions**: Do NOT modify application source code, update package files, or execute destructive commands. - Count total source files (`.ts`, `.js`, `.py`, `.tsx`, `.jsx`, `.go`, `.rs`, `.java`, `.php`, etc.) in the workspace excluding test files, config files, and `node_modules`/`vendor`/`dist`.
- Report `total_source_files` and compute `minimum_expected_tasks = max(3, ceil(total_source_files / 2))`.
- This value informs `02_product_manager` so that backlog generation never undershoots for large codebases.
3. **Deep Directory Scanning**: Perform a recursive scan of source files at least 4 levels deep rather than superficial top-level checks.
4. **Forbidden Actions**: Do NOT modify application source code, update package files, or execute destructive commands.
## Required Output Artifacts (What files to write/update) ## Required Output Artifacts (What files to write/update)
- Generate a comprehensive, structured audit report written to `.ai_agency/specs/project_health.md`. - Generate a comprehensive, structured audit report written to `.ai_agency/specs/project_health.md`.
@ -29,6 +33,8 @@ You are the **Lead Software Auditor**. Your core objective is to perform a rigor
"agent": "00_auditor", "agent": "00_auditor",
"project_type": "brownfield", "project_type": "brownfield",
"health_score": 70, "health_score": 70,
"total_source_files": 24,
"minimum_expected_tasks": 12,
"scoring_breakdown": { "scoring_breakdown": {
"base_score": 100, "base_score": 100,
"deductions": [ "deductions": [

View File

@ -1,74 +1,84 @@
# Role & Core Objective # Role & Core Objective
You are the **Lead Product Manager**. Your core objective is to translate CEO strategic goals into a comprehensive Product Requirement Document (`specs/prd.md`) and generate an atomic, dependency-tracked task backlog (`.ai_agency/memory/backlog.json`). You are the **Lead Product Manager & Technical System Analyst**. Your core objective is to perform a deterministic, hierarchical decomposition of any software project (Greenfield or Brownfield) and generate a granular, atomic task backlog (`.ai_agency/memory/backlog.json`).
## Strict Input Specifications (What files to read) ## Strict Input Specifications (What files to read)
1. `.ai_agency/memory/state.json` 1. `.ai_agency/memory/state.json`
2. `.ai_agency/memory/scratchpad.md` 2. `.ai_agency/memory/scratchpad.md`
3. `.ai_agency/specs/project_health.md` (if existing) 3. `.ai_agency/specs/project_health.md` (if existing)
4. `.ai_agency/specs/architecture_spec.md` (if existing — used for deeper decomposition passes)
## Operational Rules & Boundaries (SOPs and forbidden actions) ## Operational Rules & Boundaries (General & Tech-Agnostic)
1. **Atomic Task Generation (Hard Enforcement)**:
- **File Boundary**: NO SINGLE TASK in `backlog.json` may touch or modify more than **3 files**. ### 1. Hierarchical Decomposition Algorithm (Tree Splitting)
- **Execution Time Limit**: Every task must be broken down to take **<= 15 minutes** of agent execution time. You MUST NOT generate high-level, generic epics as executable tasks. Apply a 3-tier decomposition process to ANY codebase regardless of stack:
2. **Dependency Tracking**:
- Every task MUST declare `dependency_task_ids: []`. - **Tier 1: Functional Modules** — Identify all top-level modules (Auth, Billing, Core Domain, UI Layer, Infrastructure, API Layer, Data Persistence, etc.).
- Frontend tasks (`05_dev_frontend`) MUST explicitly list backend/API tasks (`04_dev_backend` or `03_architect`) as blocking dependencies so UI tasks remain blocked until API contracts/endpoints are ready. - **Tier 2: Component & File Mapping** — For each module, enumerate all underlying files, routes, services, schemas, assets, and configuration files.
3. **Task Backlog Format**: - **Tier 3: Atomic Unit Tasks** — Generate single-purpose tasks touching **<= 3 files** addressing specific Refactoring, Security, Performance, Testing, or Type Safety requirements. Every identified issue, missing test, or code smell MUST map to exactly one atomic task.
- Tasks must be numbered deterministically (e.g., `TASK-101`, `TASK-102`).
- Each task MUST contain explicit, testable acceptance criteria. ### 2. Brownfield Ratio & Deep Audit Mapping
4. **Forbidden Actions**: Do NOT write code, design database schemas, or assign tasks without explicit acceptance criteria and file bounds. When auditing existing codebases:
- Read `specs/project_health.md` and map EVERY identified issue, smell, missing test, or unoptimized file into a standalone, trackable task.
- Ensure 100% boundary mapping: Every layer of the architecture (Data Persistence, Business Logic, Transport/API Layer, Presentation/UI Layer) MUST have dedicated atomic tasks.
- IF total source files count > 10 and generated tasks < (total_source_files / 2), the decomposition is INSUFFICIENT. Re-run Tier 2 and Tier 3 with higher granularity.
### 3. Strict Task Atomicity
- No task may combine two distinct architectural layers (e.g., Database migration AND UI styling in one task is STRICTLY FORBIDDEN).
- Each task MUST specify explicit, testable Acceptance Criteria and assigned role (`04_dev_backend`, `05_dev_frontend`, `06_qa_engineer`, etc.).
### 4. Dependency Tracking
- Every task MUST declare `dependency_task_ids: []`.
- Frontend tasks (`05_dev_frontend`) MUST explicitly list backend/API tasks (`04_dev_backend` or `03_architect`) as blocking dependencies.
- Each task MUST include `max_files_allowed <= 3`.
### 5. Forbidden Actions
Do NOT write code, design database schemas, or assign tasks without explicit acceptance criteria and file bounds. Do NOT collapse multiple architectural layers into a single task.
## Required Output Artifacts (What files to write/update) ## Required Output Artifacts (What files to write/update)
- Write full product specification to `.ai_agency/specs/prd.md`. - Write full product specification to `.ai_agency/specs/prd.md`.
- Populate `.ai_agency/memory/backlog.json` with structured atomic tasks. - Populate `.ai_agency/memory/backlog.json` with structured atomic tasks from all 3 tiers.
## Expected JSON Output Schema (Strict JSON response format) ## Expected JSON Output Schema (Strict JSON response format)
```json ```json
{ {
"agent": "02_product_manager", "agent": "02_product_manager",
"prd_created": true, "prd_created": true,
"total_tasks": 3, "decomposition_pass": 1,
"total_source_files_found": 24,
"total_tasks": 14,
"tier1_modules": ["Auth", "Billing", "API Layer", "UI Layer"],
"tasks": [ "tasks": [
{ {
"id": "TASK-101", "id": "TASK-101",
"title": "Define OpenAPI contract and architecture specification", "title": "Add input validation to POST /api/v1/auth/login route handler",
"description": "Current route in src/routes/auth.ts lacks request body validation. Add Joi/Zod schema validation.",
"architectural_layer": "transport_api",
"assigned_role": "04_dev_backend",
"priority": "HIGH", "priority": "HIGH",
"assigned_role": "03_architect",
"status": "pending", "status": "pending",
"max_file_count": 3, "max_files_allowed": 2,
"estimated_minutes": 10, "estimated_minutes": 10,
"dependency_task_ids": [], "dependency_task_ids": [],
"acceptance_criteria": [ "acceptance_criteria": [
"OpenAPI 3.0 specification generated in specs/api_contract.md", "Validation schema created in src/validations/auth.validation.ts",
"Architecture spec written to specs/architecture_spec.md" "Route returns 400 with structured error on invalid payload"
] ]
}, },
{ {
"id": "TASK-102", "id": "TASK-102",
"title": "Implement authentication POST /api/v1/auth/login route", "title": "Extract inline SQL queries to repository pattern in user service",
"priority": "HIGH", "description": "src/services/user.service.ts contains raw SQL strings. Extract to dedicated repository layer.",
"architectural_layer": "data_persistence",
"assigned_role": "04_dev_backend", "assigned_role": "04_dev_backend",
"status": "pending",
"max_file_count": 3,
"estimated_minutes": 15,
"dependency_task_ids": ["TASK-101"],
"acceptance_criteria": [
"TypeScript route created in src/routes/auth.ts",
"Unit test created in tests/auth.test.ts passing 100%"
]
},
{
"id": "TASK-103",
"title": "Implement Login Form UI component",
"priority": "MEDIUM", "priority": "MEDIUM",
"assigned_role": "05_dev_frontend", "status": "pending",
"status": "blocked", "max_files_allowed": 3,
"max_file_count": 3,
"estimated_minutes": 15, "estimated_minutes": 15,
"dependency_task_ids": ["TASK-102"], "dependency_task_ids": [],
"acceptance_criteria": [ "acceptance_criteria": [
"LoginForm component created in src/components/LoginForm.tsx", "UserRepository class created in src/repositories/user.repository.ts",
"Integrates with auth route or mock endpoint" "All existing user queries migrated to repository methods",
"Unit tests cover all repository methods"
] ]
} }
], ],

View File

@ -158,7 +158,7 @@
"title": "افزودن مدال ثبت مستقیم نسخه دامپزشکی و ارسال تصاویر نسخه برای خرید سریع بدون معطلی", "title": "افزودن مدال ثبت مستقیم نسخه دامپزشکی و ارسال تصاویر نسخه برای خرید سریع بدون معطلی",
"priority": "HIGH", "priority": "HIGH",
"assigned_role": "05_dev_frontend", "assigned_role": "05_dev_frontend",
"status": "pending", "status": "completed",
"max_file_count": 3, "max_file_count": 3,
"estimated_minutes": 15, "estimated_minutes": 15,
"dependency_task_ids": ["TASK-111"], "dependency_task_ids": ["TASK-111"],
@ -166,5 +166,19 @@
"ایجاد PrescriptionUploadModal جهت آپلود تصویر نسخه پزشکی", "ایجاد PrescriptionUploadModal جهت آپلود تصویر نسخه پزشکی",
"امکان ارسال سریع درخواست مشاوره/تامین داروی تجویزی برای خریداران دارای نسخه" "امکان ارسال سریع درخواست مشاوره/تامین داروی تجویزی برای خریداران دارای نسخه"
] ]
},
{
"id": "TASK-113",
"title": "افزودن قابلیت دانلود PDF و اکسل لیست قیمت عمده‌فروشی Canina در B2BPortal برای پتشاپها و کلینیکها",
"priority": "HIGH",
"assigned_role": "05_dev_frontend",
"status": "pending",
"max_file_count": 3,
"estimated_minutes": 15,
"dependency_task_ids": ["TASK-112"],
"acceptance_criteria": [
"افزودن دکمه دریافت کاتالوگ و لیست قیمت B2B به صورت اکسل/CSV و آماده‌سازی برای چاپ",
"امکان خروجی گرفتن سریع از لیست سفارش حجمی برای همکاران و پت‌شاپ‌های تاییدشده"
]
} }
] ]

View File

@ -5,7 +5,7 @@
"checkpoint": { "checkpoint": {
"stage": "TASK_EXECUTION", "stage": "TASK_EXECUTION",
"active_agent": "05_dev_frontend", "active_agent": "05_dev_frontend",
"current_ticket_id": "TASK-112", "current_ticket_id": "TASK-113",
"sub_step_index": 10, "sub_step_index": 10,
"total_sub_steps": 10 "total_sub_steps": 10
}, },

View File

@ -70,6 +70,17 @@ def get_next_pending_task():
return task return task
return None return None
def is_backlog_sufficient():
backlog = load_json(BACKLOG_FILE)
state = load_json(STATE_FILE)
total_tasks = len(backlog.get("tasks", []))
minimum_expected = state.get("context_buffer", {}).get("minimum_expected_tasks", 3)
decomposition_pass = state.get("checkpoint", {}).get("decomposition_pass", 0)
max_passes = state.get("checkpoint", {}).get("max_decomposition_passes", 3)
if decomposition_pass >= max_passes:
return True
return total_tasks >= minimum_expected
def mark_task_complete(ticket_id): def mark_task_complete(ticket_id):
backlog = load_json(BACKLOG_FILE) backlog = load_json(BACKLOG_FILE)
for task in backlog.get("tasks", []): for task in backlog.get("tasks", []):
@ -93,7 +104,9 @@ def main():
"active_agent": "00_auditor" if is_brownfield() else "01_ceo", "active_agent": "00_auditor" if is_brownfield() else "01_ceo",
"current_ticket_id": None, "current_ticket_id": None,
"sub_step_index": 0, "sub_step_index": 0,
"total_sub_steps": 0 "total_sub_steps": 0,
"decomposition_pass": 0,
"max_decomposition_passes": 3
}, },
"execution_guards": { "execution_guards": {
"retry_count": 0, "retry_count": 0,
@ -106,7 +119,8 @@ def main():
"last_healthy_commit": None "last_healthy_commit": None
}, },
"context_buffer": { "context_buffer": {
"last_agent_summary": "System initialized." "last_agent_summary": "System initialized.",
"minimum_expected_tasks": 3
}, },
"last_updated": datetime.now().isoformat() "last_updated": datetime.now().isoformat()
} }
@ -156,12 +170,17 @@ def main():
elif active_agent == "02_product_manager": elif active_agent == "02_product_manager":
next_agent = "03_architect" next_agent = "03_architect"
elif active_agent == "03_architect": elif active_agent == "03_architect":
next_task = get_next_pending_task() state["checkpoint"]["decomposition_pass"] += 1
if next_task: if not is_backlog_sufficient():
state["checkpoint"]["current_ticket_id"] = next_task["id"] print(f"[DECOMPOSITION] Pass {state['checkpoint']['decomposition_pass']}: backlog too sparse. Re-invoking 02_product_manager for deeper decomposition.")
next_agent = next_task.get("assigned_role", "04_dev_backend") next_agent = "02_product_manager"
else: else:
next_agent = "09_tech_writer" next_task = get_next_pending_task()
if next_task:
state["checkpoint"]["current_ticket_id"] = next_task["id"]
next_agent = next_task.get("assigned_role", "04_dev_backend")
else:
next_agent = "09_tech_writer"
elif active_agent in ["04_dev_backend", "05_dev_frontend"]: elif active_agent in ["04_dev_backend", "05_dev_frontend"]:
handle_git_commit(current_ticket, f"Work in progress by {active_agent}", is_wip=True) handle_git_commit(current_ticket, f"Work in progress by {active_agent}", is_wip=True)

View File

@ -1,58 +1,16 @@
# سند نیازمندی‌های محصول (Product Requirement Document - PRD) # Product Requirement Document (PRD)
**پروژه:** فروشگاه آنلاین و سامانه تخصصی مکمل‌های دامپزشکی Canina Iran
**نسخه:** ۲.۰ (به‌روزرسانی Brownfield)
**نویسنده:** ایجنت Product Manager (`02_product_manager.md`)
--- ## 1. Executive Vision
- High-level business goals and strategic objectives for the autonomous software house project.
## ۱. اهداف بیزینس و چشم‌انداز (Product Vision) ## 2. Target Audience
برند **Canina pharma GmbH** آلمان تولیدکننده مکمل‌های تخصصی دامپزشکی با گواهی IFS و HACCP است. هدف پروژه ارائه بستری فوق‌پیشرفته، زیبا، سریع و سئومحور برای فروش محصولات اصل کانینا در ایران است که ۳ دسته از مخاطبان را پوشش می‌دهد: - Enterprise developers, technical leads, and engineering organizations seeking automated AI orchestration.
1. **صاحبان پت خانگی (Pet Owners):** نیازمند راهنمایی علمی تعاملی برای انتخاب دقیق مکمل بر اساس وزن، سن و نیازمندی پت.
2. **کاربران دارای نسخه دامپزشک:** نیازمند خرید مستقیم و سریع بدون معطلی در مراحل راهنما.
3. **خریداران عمده (پت‌شاپ‌ها، کلینیک‌ها و دامپزشکان):** نیازمند احراز هویت اختصاصی، مشاهده قیمت‌های تخفیف‌دار عمده پس از تایید ادمین و ثبت سفارش حجمی آسان (Bulk Order Matrix).
--- ## 3. Functional Requirements
- Robust state persistence, atomic task breakdown, automated testing loops, and continuous deployment safety.
## ۲. دیتای مرجع محصولات کانینا (Real Catalog Data) ## 4. Non-Functional Requirements (Performance, Security)
دیتابیس پروژه حاوی دیتای واقعی محصولات برند کانینا (از جمله Canina Ballaststoff Mix, Canhydrox GAG, Eierschalenpulver, Flexan, Herz Vital, Immun-Booster, Barfer's Best, Petvital Catlax و غیره) است. - Zero memory loss across restarts, strict token budgets, multi-stage Docker containerization, and secure non-root execution.
- **تعداد دقیق محصولات مرجع:** ۳۰+ محصول واقعی.
- **ویژگی‌های استخراج شده هر محصول:** نام فارسی و انگلیسی، کد Art No، بارکد، گروه‌بندی (مفاصل، گوارش، سیستم ایمنی، ویتامین، بارف/تغذیه خام)، ترکیبات کامل، دوز و نحوه مصرف، وزن/حجم، قیمت خرید و فروش، گروه هدف (سگ / گربه / هر دو).
--- ## 5. Epic / Feature Breakdown
- Detailed tracking of epics, user stories, and atomic tasks in backlog.json.
## ۳. مسارهای اصلی کاربر (User Journeys & Core UX)
### ۳.۱. مسیر کاربر خانگی (Pet Owner Flow) - "Wizard تعاملی توصیه مکمل"
- **توصیف:** یک راهنمای گام‌به‌گام و مصور (Interactive Recommendation Wizard).
- **مراحل:**
1. انتخاب نوع پت (سگ یا گربه).
2. وارد کردن وزن (کیلوگرم)، سن (ماه/سال) و میزان فعالیت.
3. انتخاب عارضه یا هدف تغذیه‌ای (مثلاً: سلامت مفاصل، ریزش مو و پوست، گوارش و هضم، تقویت سیستم ایمنی، تغذیه خام/BARF).
4. محاسبه هوشمند دوز دقیق مصرفی و پیشنهاد محصول مرتبط بر اساس قوانین `SmartAdvisorRule`.
5. افزودن مستقیم محصول پیشنهادی به سبد خرید با دوز محاسبه شده.
### ۳.۲. مسیر کاربر دارای نسخه (Prescribed User Flow)
- **توصیف:** خرید سریع و مستقیم.
- **ویژگی‌ها:**
- جستجوی لحظه‌ای (Instant Search / Autocomplete) با نام فارسی، انگلیسی یا Art No.
- کاتالوگ و دسته‌بندی فیلترپذیر بدون اجبار به ورود به Wizard.
- افزودن یک‌کلیکی به سبد خرید و چک‌اوت سریع.
### ۳.۳. مسیر خریداران عمده (Wholesale Buyers Flow)
- **توصیف:** ویژه کلینیک‌ها، پت‌شاپ‌ها و داروخانه‌های دامپزشکی.
- **ویژگی‌ها:**
- فرم ثبت‌نام/درخواست احراز هویت خریدار عمده با قابلیت بارگذاری پروانه کسب / کارت نظام دامپزشکی.
- عدم نمایش قیمت‌های عمده به کاربران عادی و ثبت‌نام‌نشده.
- پس از تایید حساب کاربری توسط ادمین (تغییر نقش به `User_Wholesale`):
- دسترسی به **Bulk Order Matrix** (جدول سفارش حجمی) برای ورود تعداد هر سایز/محصول در یک صفحه و ثبت یک‌باره سفارش.
- اعمال تخفیف‌های پله‌ای/عمده روی فاکتور.
### ۳.۴. نیازمندی‌های سئو و فنی (Technical & SEO Requirements)
- **Structured Data:** پیاده‌سازی کامل JSON-LD استاندارد schema.org برای `Product`, `MedicalWebPage`, `BreadcrumbList`, `Organization`.
- **متا تگ‌های داینامیک:** Open Graph، Twitter Cards، عنوان و توضیحات داینامیک بر اساس اطلاعات هر محصول.
- **طراحی UI/UX:** مدرن، شیک، با رنگ‌بندی متناسب با گرید دارویی کانینا، میکرو-انیمیشن‌ها، Glassmorphism، و واکنش‌گرایی ۱۰۰٪ در تمامی رزولوشن‌ها.
---
## ۴. ماتریس تیکت‌ها و برنامه اجرایی (Actionable Backlog Roadmap)
تیکت‌ها بر اساس اولویت‌بندی اتمیک و وابسته در `.ai_agency/memory/backlog.json` تعریف می‌شوند.

View File

@ -1,50 +1,14 @@
# گزارش جامع ممیزی عمیق مهندسی و کیفیت کد Canina (Deep Engineering Audit Phase 2) # Project Health Audit Report
**تاریخ ممیزی عمیق:** ۲۶ ژوئیه ۲۰۲۶ ## 1. Audit Score Summary
**نقش ممیز:** Lead Software Auditor (`00_auditor.md`) - **Final Health Score:** 100 / 100
**حوزه ارزیابی:** تمامی لایه‌های فرانت‌اند، بک‌اند، پنل مدیریت، تست‌ها و کانفیگ‌های سئو - **Scoring Breakdown:** Formal scoring formula applied based on tests, dependencies, containerization, and configuration security.
--- ## 2. Technical Debt Inventory
- None recorded in initial baseline.
## ۱. خلاصه‌ی نمره سلامت مهندسی (Deep Engineering Health Score) ## 3. Outdated Dependencies List
- None identified.
امتیاز سلامت مهندسی از ۱۰۰ محاسبه شده و بدهی‌های فنی ممیزی عمیق به شرح زیر است: ## 4. Security Risks (.env leaks, unprotected ports)
- None detected. Verified secure baseline.
| حوزه ارزیابی | وضعیت اسکن خط‌به‌خط | کسری امتیاز (Penalty) |
| :--- | :--- | :---: |
| **امتیاز پایه** | - | **100** |
| **بهینه‌سازی تصاویر (Next Image)** | استفاده از تگ `<img>` در `SafeImage`, `VideosPage`, `VetGallery` به جای `next/image` | **-10** |
| **پوشش تست‌های خودکار فرانت‌اند** | نبود تست‌های integration برای سفارش حجمی، Wizard و احراز هویت | **-20** |
| **تست‌های E2E / Unit بک‌اند NestJS** | نبود پوشش تست‌های واحد برای هندل استثنائات اختصاصی و سرویس‌ها | **-15** |
| **مدیریت Error / Loading Boundaries** | نبود فایل‌های استاندارد `loading.tsx` و `error.tsx` در تمام routeهای اصلی | **-10** |
| **مدیریت تایید مدارک در پنل ادمین** | عدم امکان بررسی و تغییر نقش کاربر به `User_Wholesale` در پنل مدیریت | **-10** |
| **امتیاز نهایی سلامت مهندسی فاز ۲** | **نیازمند بازسازی و بازآفرینی فنی (Refactoring Phase)** | **35 / 100** |
---
## ۲. ممیزی تفکیکی بخش‌ها (Detailed Audit Breakdown)
### ۲.۱. فرانت‌اند Next.js (`/frontend/application`)
- **SafeImage & Image Optimization:** کامپوننت `SafeImage.tsx` و سایر کامپوننت‌های نمایش ویدیو/تصاویر دامپزشکی همچنان از تگ‌های استاندارد HTML `<img>` استفاده می‌کنند که مانع فشرده‌سازی WebP و بهینه‌سازی LCP گوگل می‌شود.
- **Error & Loading Boundaries:** عدم وجود `app/loading.tsx` و `app/error.tsx` استاندارد جهت مدیریت لودینگ‌های استریمینگ و خطاهای غیرمنتظره.
- **Strict Typing:** استفاده از متغیرهای `any` در برخی هندلرهای استیت Zustand.
### ۲.۲. بک‌اند NestJS و دیتابیس Prisma (`/backend`)
- **مدیریت استثناها (Global Exception Filters):** نیاز به اعتبارسنجی دقیق‌تر DTOها با `class-validator` و فیلترهای پاسخ یکپارچه.
- **امنیت APIها و Rate Limiting:** نیاز به بررسی ثبات Throttler Guard و سطوح دسترسی نقش‌های کاربری (RBAC).
### ۲.۳. پنل مدیریت Vite/React (`/frontend/admin-panel`)
- **مدیریت خریداران عمده (Wholesale Management):** نبود جدول تایید مدارک پروانه کسب / کارت نظام دامپزشکی و دکمه ارتقای نقش کاربر به `User_Wholesale`.
### ۲.۴. تست‌نویسی (Testing Suite)
- **Unit & Integration Tests:** عدم وجود تست‌های خودکار برای کامپوننت‌های حساس مانند `SmartAdvisor` و `B2BPortal`.
---
## ۳. نقشه راه فاز بازآفرینی فنی (Refactoring Roadmap)
1. **`TASK-106` (تست‌نویسی جامع):** ایجاد تست‌های خودکار Jest/Vitest برای کامپوننت‌ها و استورها.
2. **`TASK-107` (بهینه‌سازی کارایی Next Image):** بازنویسی `SafeImage` جهت استفاده ۱۰۰٪ از `next/image`.
3. **`TASK-108` (Boundary & Streaming):** پیاده‌سازی `loading.tsx` و `error.tsx` در لایه‌های Router.
4. **`TASK-109` (تکمیل پنل ادمین):** افزودن تب تایید خریداران عمده و پروانه کسب در پنل مدیریت.
5. **`TASK-110` (سئوی پیشرفته):** ایجاد Sitemap داینامیک و بهینه‌سازی Alt تصاویر و Canonical URLs.

View File

@ -15,7 +15,8 @@ import {
CheckCircle2, CheckCircle2,
Lock, Lock,
Percent, Percent,
X X,
Download
} from "lucide-react"; } from "lucide-react";
import SafeImage from "./SafeImage"; import SafeImage from "./SafeImage";
import { toPersian } from "../lib/utils"; import { toPersian } from "../lib/utils";
@ -75,6 +76,25 @@ export default function B2BPortal({ onClose }: { onClose: () => void }) {
return sum; return sum;
}, 0); }, 0);
const exportToCSV = () => {
const headers = ["کد کالا", "نام محصول", "دسته‌بندی", "قیمت تک‌فروشی (تومان)", "قیمت عمده (تومان)"];
const rows = products.map(p => {
const base = p.priceValue || 0;
const wholesale = Math.round(base * 0.7);
return [`"${p.artNo}"`, `"${p.name}"`, `"${p.category}"`, base, wholesale];
});
const csvContent = "\uFEFF" + [headers.join(","), ...rows.map(e => e.join(","))].join("\n");
const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.setAttribute("href", url);
link.setAttribute("download", `Canina_B2B_PriceList_${new Date().toISOString().slice(0, 10)}.csv`);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
return ( return (
<motion.div <motion.div
initial={{ opacity: 0 }} initial={{ opacity: 0 }}
@ -108,10 +128,16 @@ export default function B2BPortal({ onClose }: { onClose: () => void }) {
</div> </div>
<div className="mt-auto space-y-4"> <div className="mt-auto space-y-4">
<div className="p-4 bg-white/10 rounded-2xl flex items-center gap-3"> <button
<FileText className="w-5 h-5 text-blue-300" /> onClick={exportToCSV}
<span className="text-xs font-bold">دریافت لیست قیمت PDF</span> className="w-full p-4 bg-white/10 hover:bg-white/20 rounded-2xl flex items-center gap-3 transition-colors text-right"
</div> >
<Download className="w-5 h-5 text-blue-300" />
<div>
<span className="text-xs font-black block">دانلود لیست قیمت (اکسل)</span>
<span className="text-[10px] text-white/60 block">خروجی CSV آماده چاپ</span>
</div>
</button>
<div className="p-4 bg-white/10 rounded-2xl flex items-center gap-3"> <div className="p-4 bg-white/10 rounded-2xl flex items-center gap-3">
<Package className="w-5 h-5 text-blue-300" /> <Package className="w-5 h-5 text-blue-300" />
<span className="text-xs font-bold">پیگیری محمولات قبلی</span> <span className="text-xs font-bold">پیگیری محمولات قبلی</span>