Files
meezi/MEEZI_CURSOR_GUIDE.md
T

763 lines
23 KiB
Markdown
Raw Normal View History

# راهنمای کامل توسعه Meezi با Cursor
> از صفر تا اولین سفارش واقعی — گام به گام
---
## پیش‌نیازها — قبل از هر چیز نصب کن
```bash
# 1. Node.js 20+
node --version # باید v20 یا بالاتر باشد
# دانلود: https://nodejs.org
# 2. .NET 10 SDK
dotnet --version # باید 8.x باشد
# دانلود: https://dotnet.microsoft.com/download/dotnet/8.0
# 3. Flutter 3.x
flutter --version
# دانلود: https://docs.flutter.dev/get-started/install
# 4. Docker Desktop (برای PostgreSQL و Redis محلی)
docker --version
# دانلود: https://www.docker.com/products/docker-desktop
# 5. pnpm
npm install -g pnpm
# 6. Cursor
# دانلود: https://cursor.com
```
---
## مرحله ۱ — ساختار پروژه را بساز
```bash
# یک پوشه اصلی بساز
mkdir meezi && cd meezi
# Git راه‌اندازی کن
git init
echo "node_modules/\n.next/\nbuild/\n*.user\n.env*\n!.env.example" > .gitignore
```
---
## مرحله ۲ — فایل‌های کلیدی را بریز
### `.cursorrules` — در ریشه پروژه
```
You are building Meezi (میزی) — a Persian-first SaaS POS and community
platform for Iranian cafés in Tehran and Karaj.
CONTEXT: Read MEEZI_PRD.md for full product details before any task.
STACK:
- Backend: ASP.NET Core 10 (C#) in src/Meezi.API
- Web: Next.js 14 TypeScript in web/dashboard
- Mobile: Flutter 3 Dart in mobile/meezi_app
- DB: PostgreSQL + Redis
- ORM: Entity Framework Core 10
PRODUCT:
- Brand: Meezi (میزی) | میزت منتظرته
- Markets: Tehran + Karaj (V1)
- Languages: Farsi (default) + Arabic + English
- Competitor: Sepidz (legacy license, no SaaS)
- Pricing: Free / Pro 1.49M / Business 3.49M / Enterprise
C# RULES:
- Async/await everywhere — never .Result or .Wait()
- EVERY EF query filters by CafeId (multi-tenant)
- Return ApiResponse<T> always: { bool Success, T? Data, ApiError? Error }
- Use record types for DTOs
- FluentValidation for all inputs
- Hangfire for background jobs
- SignalR for real-time KDS
- Never Console.WriteLine — use ILogger<T>
NEXT.JS RULES:
- next-intl for i18n — ALL strings in messages/fa.json, ar.json, en.json
- RTL for fa/ar — LTR for en
- ms-* me-* ps-* pe-* for spacing (never ml mr pl pr)
- TanStack Query v5 for server state
- Zustand for cart and UI state
- date-fns-jalali for ALL dates — never show Gregorian
- Numbers: .toLocaleString('fa-IR')
- Currency: n.toLocaleString('fa-IR') + ' ت'
- shadcn/ui components always
FLUTTER RULES:
- Riverpod 2 for all state
- GoRouter for navigation
- Drift SQLite for offline
- shamsi_date for all dates
- 3 locales: fa (RTL), ar (RTL), en (LTR)
- Feature-first: lib/features/{feature}/
SECURITY:
- Validate CafeId ownership on every protected endpoint
- Rate limit OTP: 5/hour per phone via Redis
- Never log phone, national ID, or payment tokens
- Soft delete only — never hard delete
API FORMAT:
Success: { "success": true, "data": {...} }
Error: { "success": false, "error": { "code": "...", "message": "..." } }
List: { "success": true, "data": [...], "meta": { "total": 0, "page": 1 } }
```
### `docker-compose.yml` — در ریشه پروژه
```yaml
version: '3.8'
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: meezi
POSTGRES_USER: meezi
POSTGRES_PASSWORD: meezi_local_pass
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
postgres_data:
```
---
## مرحله ۳ — Backend راه‌اندازی کن
```bash
# پوشه backend
mkdir src && cd src
# پروژه‌های .NET بساز
dotnet new webapi -n Meezi.API --use-controllers
dotnet new classlib -n Meezi.Core
dotnet new classlib -n Meezi.Infrastructure
dotnet new classlib -n Meezi.Shared
# Solution بساز
cd ..
dotnet new sln -n Meezi
dotnet sln add src/Meezi.API
dotnet sln add src/Meezi.Core
dotnet sln add src/Meezi.Infrastructure
dotnet sln add src/Meezi.Shared
# Reference ها
cd src/Meezi.API
dotnet add reference ../Meezi.Core
dotnet add reference ../Meezi.Infrastructure
dotnet add reference ../Meezi.Shared
cd ../Meezi.Infrastructure
dotnet add reference ../Meezi.Core
dotnet add reference ../Meezi.Shared
```
### حالا Cursor را باز کن و این prompt را بده:
```
I'm building Meezi.API — ASP.NET Core 10 Web API for a SaaS POS system.
Read .cursorrules for full context.
Add these NuGet packages to Meezi.API:
- Npgsql.EntityFrameworkCore.PostgreSQL
- Microsoft.EntityFrameworkCore.Design
- FluentValidation + FluentValidation.DependencyInjectionExtensions
- AutoMapper.Extensions.Microsoft.DependencyInjection
- Hangfire.AspNetCore + Hangfire.PostgreSql
- Serilog.AspNetCore + Serilog.Sinks.Console
- StackExchange.Redis
- Microsoft.AspNetCore.Authentication.JwtBearer
- Microsoft.AspNetCore.SignalR
- QuestPDF (for PDF generation)
- EPPlus (for Excel export)
- CsvHelper
Add these to Meezi.Infrastructure:
- Npgsql.EntityFrameworkCore.PostgreSQL
- Microsoft.EntityFrameworkCore.Tools
Then create this folder structure inside Meezi.API:
Controllers/ Services/ Jobs/ Middleware/ Hubs/ Extensions/
And this in Meezi.Core:
Entities/ Enums/ Interfaces/ Constants/
And this in Meezi.Infrastructure:
Data/ Data/Migrations/ Repositories/ ExternalServices/
Create the base ApiResponse<T> record in Meezi.Shared/ApiResponse.cs
Create Program.cs with full middleware pipeline setup.
```
---
## مرحله ۴ — Database Schema
در Cursor بده:
```
Create all EF Core entity classes in Meezi.Core/Entities/ based on this schema:
Cafe: Id(string/cuid), Name, NameAr, NameEn, Slug(unique), Phone,
Address, City, LogoUrl, PlanTier(enum), PlanExpiresAt, IsVerified,
PreferredLanguage, CreatedAt
Branch: Id, CafeId(FK), Name, Address, City
Table: Id, CafeId, BranchId(nullable), Number, Capacity(default 4),
Floor, QrCode(unique), IsActive
Employee: Id, CafeId, Name, Phone, NationalId, Role(enum EmployeeRole),
BaseSalary, PinCode, CreatedAt
MenuCategory: Id, CafeId, Name, NameAr, NameEn, SortOrder, TaxId,
DiscountPercent, IsActive
MenuItem: Id, CafeId, CategoryId(FK), Name, NameAr, NameEn,
Description, Price, ImageUrl, IsAvailable
Order: Id, CafeId, BranchId, TableId, CustomerId, EmployeeId,
OrderType(enum), Status(enum), CouponId, DiscountAmount,
Subtotal, TaxTotal, Total, SnappfoodOrderId, CreatedAt
OrderItem: Id, OrderId(FK), MenuItemId(FK), Quantity, UnitPrice, Notes
Payment: Id, OrderId(FK), Method(enum PaymentMethod), Amount,
Status(enum), Reference
Customer: Id, CafeId, Name, Phone, NationalId, BirthDateJalali,
Group(enum CustomerGroup), LoyaltyPoints, ReferredBy, CreatedAt
Coupon: Id, CafeId, Code, Type(enum CouponType), Value, MinOrderAmount,
MaxDiscount, UsageLimit, UsedCount, TargetGroup,
StartsAt, ExpiresAt, IsActive
Tax: Id, CafeId, Name, Rate, IsDefault, IsRequired, IsCompound
EmployeeSalary: Id, EmployeeId(FK), MonthYear(string YYYY-MM),
BaseSalary, OvertimePay, Deductions, NetSalary, IsPaid
Attendance: Id, EmployeeId(FK), Date, ClockIn, ClockOut, Notes
Shift: Id, EmployeeId(FK), DayOfWeek(int), ShiftType(enum: Morning/Evening/Off)
LeaveRequest: Id, EmployeeId(FK), StartDate, EndDate, Reason,
Status(enum: Pending/Approved/Rejected), ReviewedBy
Enums to create in Meezi.Core/Enums/:
PlanTier: Free, Pro, Business, Enterprise
OrderType: DineIn, Takeaway, Delivery
OrderStatus: Pending, Confirmed, Preparing, Ready, Delivered, Cancelled
PaymentMethod: Cash, Card, Credit
EmployeeRole: Owner, Manager, Cashier, Waiter, Chef, Delivery
CustomerGroup: Regular, VIP, New, Employee
CouponType: Percentage, FixedAmount, FreeItem
ShiftType: Morning, Evening, DayOff
Then create AppDbContext in Meezi.Infrastructure/Data/AppDbContext.cs
with all DbSets and proper relationships.
Create the initial EF migration called "InitialCreate".
```
---
## مرحله ۵ — Auth System
```
Build the complete auth system for Meezi:
1. In Meezi.Infrastructure/ExternalServices/KavenegarSmsService.cs:
- HTTP client calling Kavenegar REST API
- Method: SendOtpAsync(string phone, string otp)
- Read API key from IConfiguration
2. In Meezi.API/Services/AuthService.cs:
- SendOtpAsync(string phone):
* Generate 6-digit OTP
* Store in Redis with key "otp:{phone}" TTL 5 minutes
* Store attempt counter "otp:attempts:{phone}" TTL 1 hour
* Block if attempts > 5 (return error RATE_LIMITED)
* Call KavenegarSmsService
- VerifyOtpAsync(string phone, string code, string cafeId):
* Check Redis for code
* If valid: generate JWT with claims { userId, cafeId, role, planTier, lang }
* Delete OTP from Redis
* Return token + refresh token
3. In Meezi.API/Controllers/AuthController.cs:
POST /api/auth/send-otp → body: { phone }
POST /api/auth/verify-otp → body: { phone, code }
POST /api/auth/refresh → body: { refreshToken }
4. In Meezi.API/Middleware/TenantMiddleware.cs:
- Extract cafeId from JWT claims
- Inject ITenantContext into request scope
- Return 401 if cafeId missing on protected routes
5. In Meezi.API/Middleware/PlanLimitMiddleware.cs:
- Read planTier from JWT
- Check against PlanLimits constants
- Return PLAN_LIMIT_REACHED error if exceeded
JWT claims: { sub: userId, cafeId, role, planTier, lang, iat, exp }
Token expiry: 7 days access, 30 days refresh
```
---
## مرحله ۶ — Core POS APIs
```
Build these API endpoints in Meezi.API/Controllers/:
MenuController.cs:
GET /api/cafes/{cafeId}/menu/categories
POST /api/cafes/{cafeId}/menu/categories
PATCH /api/cafes/{cafeId}/menu/categories/{id}
DELETE /api/cafes/{cafeId}/menu/categories/{id}
GET /api/cafes/{cafeId}/menu/items
POST /api/cafes/{cafeId}/menu/items
PATCH /api/cafes/{cafeId}/menu/items/{id}
PATCH /api/cafes/{cafeId}/menu/items/{id}/availability
TablesController.cs:
GET /api/cafes/{cafeId}/tables
POST /api/cafes/{cafeId}/tables → auto-generate QR code URL
GET /api/q/{qrCode} → public, returns cafeSlug + tableId
OrdersController.cs:
GET /api/cafes/{cafeId}/orders → with status filter
POST /api/cafes/{cafeId}/orders → create + check plan limits
PATCH /api/cafes/{cafeId}/orders/{id}/status
POST /api/cafes/{cafeId}/orders/{id}/payments → record payment(s)
GET /api/cafes/{cafeId}/orders/live → SSE or SignalR for KDS
Every controller must:
- Use [Authorize] attribute
- Validate CafeId matches JWT claim
- Use FluentValidation for request body
- Return ApiResponse<T> format
- Use async/await throughout
```
---
## مرحله ۷ — Next.js Dashboard
```bash
# از ریشه پروژه
mkdir web && cd web
npx create-next-app@latest dashboard --typescript --tailwind --app --src-dir
cd dashboard
# پکیج‌های اضافی
pnpm add @tanstack/react-query zustand next-intl date-fns-jalali
pnpm add @hookform/resolvers react-hook-form zod
pnpm add recharts lucide-react
pnpm add -D @types/node
```
### در Cursor:
```
Set up the Next.js 14 dashboard for Meezi with these steps:
1. Configure next-intl for 3 locales: fa (default, RTL), ar (RTL), en (LTR)
- Create messages/fa.json, messages/ar.json, messages/en.json
- Wrap app in [locale] dynamic route
- Set dir="rtl" for fa/ar, dir="ltr" for en
- Load Vazirmatn font for fa/ar, Inter for en
2. Install and configure shadcn/ui:
npx shadcn-ui@latest init
Add components: button, input, card, dialog, table, select,
badge, skeleton, toast, sheet, dropdown-menu
3. Create the app layout at app/[locale]/(dashboard)/layout.tsx:
- Sidebar with icons for: POS, CRM, Coupons, Inventory, HR,
Reports, Reservations, SMS, Taxes, Settings
- Top bar with: cafe name, plan badge, language switcher, user menu
- RTL-aware: sidebar on RIGHT for fa/ar, LEFT for en
4. Create Zustand store at lib/stores/cart.store.ts:
State: { items: CartItem[], couponCode, appliedCoupon, tableId }
Actions: addItem, removeItem, updateQty, applyCoupon, clearCart
5. Create API client at lib/api/client.ts:
- Axios instance with baseURL from env
- JWT interceptor (attach token from localStorage)
- 401 interceptor (redirect to login)
- Response unwrapper (extract .data from ApiResponse<T>)
6. Create the main POS page at app/[locale]/(dashboard)/pos/page.tsx:
- Left panel (60%): category tabs + item grid (3 cols)
- Right panel (40%): order items + coupon + tax + split payment
- All text from fa.json translation keys
- Farsi numbers everywhere
- Toman currency format
```
---
## مرحله ۸ — Flutter App
```bash
# از ریشه پروژه
mkdir mobile && cd mobile
flutter create meezi_app --org ir.meezi --platforms android,ios,windows
cd meezi_app
```
### `pubspec.yaml` — جایگزین کن:
```yaml
name: meezi_app
description: Meezi - میزی - سیستم کافه و رستوران
environment:
sdk: '>=3.3.0 <4.0.0'
flutter: ">=3.19.0"
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
# State
flutter_riverpod: ^2.5.1
riverpod_annotation: ^2.3.5
# Navigation
go_router: ^14.2.0
# HTTP
dio: ^5.4.3
retrofit: ^4.3.0
# Local DB (offline)
drift: ^2.18.0
sqlite3_flutter_libs: ^0.5.24
path_provider: ^2.1.3
path: ^1.9.0
# i18n
intl: ^0.19.0
# Shamsi date
shamsi_date: ^1.1.1
# QR
qr_flutter: ^4.1.0
mobile_scanner: ^5.2.3
# Printer
esc_pos_utils_plus: ^2.0.1
bluetooth_print: ^4.4.0
# Notifications
firebase_messaging: ^15.1.0
flutter_local_notifications: ^17.2.3
# Storage
flutter_secure_storage: ^9.2.2
shared_preferences: ^2.3.2
# UI
cached_network_image: ^3.3.1
image_picker: ^1.1.2
shimmer: ^3.0.0
flutter_svg: ^2.0.10+1
# Utils
freezed_annotation: ^2.4.1
json_annotation: ^4.9.0
equatable: ^2.0.5
uuid: ^4.4.2
dev_dependencies:
flutter_test:
sdk: flutter
build_runner: ^2.4.11
freezed: ^2.5.2
json_serializable: ^6.8.0
retrofit_generator: ^8.1.0
riverpod_generator: ^2.4.0
drift_dev: ^2.18.0
```
### در Cursor:
```
Set up the Flutter app structure for Meezi following feature-first architecture.
Create this folder structure in lib/:
app/
router.dart → GoRouter with all routes
providers.dart → Riverpod ProviderScope setup
features/
auth/ → OTP login screen
pos/ → Owner POS tablet view
menu/ → Customer menu browse
cart/ → Cart + checkout
track/ → Order tracking
reserve/ → Table reservation
discover/ → کافه‌یاب discovery
hr/ → Employee clock-in + leave request
profile/ → Customer profile + history
core/
api/
api_client.dart → Dio + Retrofit setup
interceptors.dart → JWT + error interceptors
db/
app_database.dart → Drift database
daos/ → Data access objects
sync/
sync_engine.dart → Offline queue + sync logic
i18n/
app_localizations.dart
utils/
jalali_utils.dart → shamsi_date helpers
currency_utils.dart → Toman formatting
shared/
widgets/
theme/
app_theme.dart → RTL-aware theme
Routes to create in router.dart:
/ → redirect to /discover or /pos based on user role
/login → OTP auth screen
/discover → Café discovery (public)
/cafe/:slug → Café public profile
/cafe/:slug/menu → Menu (reads tableId from QR)
/cafe/:slug/cart → Checkout
/order/:id/track → Delivery tracking
/reserve/:slug → Table reservation
/pos → Owner POS (requires OWNER/MANAGER/CASHIER role)
/profile → Customer profile
Configure localization for fa (RTL), ar (RTL), en (LTR).
Create MaterialApp.router with locale switching support.
```
---
## مرحله ۹ — Docker و اجرای محلی
```bash
# از ریشه پروژه
docker-compose up -d
# PostgreSQL روی port 5432 بالا می‌آید
# Redis روی port 6379
# Migration اجرا کن
cd src/Meezi.API
dotnet ef database update
# Backend اجرا کن
dotnet run
# روی https://localhost:7001 بالا می‌آید
# Dashboard اجرا کن (terminal جدید)
cd web/dashboard
pnpm dev
# روی http://localhost:3000 بالا می‌آید
# Flutter اجرا کن (terminal جدید)
cd mobile/meezi_app
flutter run -d chrome # برای تست وب
flutter run # برای اندروید/شبیه‌ساز
```
---
## مرحله ۱۰ — Prompt های آماده برای هر ماژول
### CRM + جستجو با کد ملی:
```
Build the CRM module:
- GET /api/cafes/{cafeId}/customers?q={search}
Search by name, phone, or nationalId (10-digit)
- POST /api/cafes/{cafeId}/customers
Fields: name, phone, nationalId, birthDateJalali (YYYY/MM/DD), group
- Check FREE plan limit: max 50 customers → return PLAN_LIMIT_REACHED
- Next.js page: /crm with search input, customer cards, add modal
- All in Farsi with RTL layout
```
### HR + حضور و غیاب Flutter:
```
Build the HR attendance feature in Flutter:
- Screen: features/hr/attendance_screen.dart
- Show employee's today shift (Morning 8-16 / Evening 16-00 / DayOff)
- Clock In button: POST /api/employees/{id}/attendance/clock-in
- Clock Out button: POST /api/employees/{id}/attendance/clock-out
- Leave request form: reason + date range in Shamsi calendar
- Works OFFLINE: queue attendance locally, sync when online
- Shamsi date display throughout
- Farsi UI with RTL layout
```
### KDS آشپزخانه realtime:
```
Build the Kitchen Display System:
- SignalR Hub in Meezi.API/Hubs/KdsHub.cs
- Group orders by cafeId
- Broadcast new orders to kitchen screen
- Broadcast status changes
- Next.js page: /kds
- Connect to SignalR hub
- Show live order cards (Pending → Preparing → Ready)
- Color coded: yellow=Pending, blue=Preparing, green=Ready
- Each card: table number, items list, time elapsed
- Click to advance status
- Auto-refresh every 30s as fallback
- All Farsi, RTL layout
```
### گزارش مالی + Excel خروجی:
```
Build the reports API:
GET /api/cafes/{cafeId}/reports/daily?date=1403-10-16
Returns: totalOrders, newCustomers, returningCustomers,
revenue, taxTotal, discountTotal, topItems(5)
GET /api/cafes/{cafeId}/reports/monthly?month=1403-10
Returns: daily breakdown, totalRevenue, totalCosts breakdown
(salary from EmployeeSalary, plus manual cost entries)
netProfit = revenue - costs
GET /api/cafes/{cafeId}/reports/export?month=1403-10&format=excel
Returns: Excel file using EPPlus
Sheets: Sales, Items, Customers, Employees
Next.js page /reports:
- Stats cards: today customers (new vs returning)
- Bar chart (Recharts): 7-day revenue vs cost
- Top items list
- Monthly P&L table
- Export button
All Farsi, RTL, Toman currency, Shamsi dates
```
### پرداخت ZarinPal:
```
Build ZarinPal subscription payment in C#:
1. PaymentService.cs:
- InitiateSubscriptionAsync(cafeId, planTier, months):
* Call ZarinPal /pg/v4/payment/request.json
* Store pending payment record
* Return payment URL
- VerifyPaymentAsync(authority, status):
* Call ZarinPal /pg/v4/payment/verify.json
* On success: update cafe PlanTier + PlanExpiresAt
* Send confirmation SMS via Kavenegar
2. BillingController.cs:
POST /api/billing/subscribe → body: { planTier, months }
→ returns { paymentUrl }
GET /api/billing/verify?Authority=...&Status=OK
→ ZarinPal callback, redirect to dashboard
GET /api/billing/status
→ current plan, expiry, usage stats
3. Hangfire job: SubscriptionRenewalReminderJob
- Run daily
- Find cafes expiring in 3 days
- Send SMS reminder via Kavenegar
```
### Snappfood Integration:
```
Build Snappfood webhook receiver:
POST /api/webhooks/snappfood (no auth, verify with HMAC secret)
- Parse Snappfood order payload
- Map to Meezi Order:
* OrderType = Delivery
* Status = Confirmed (already paid via Snappfood)
* SnappfoodOrderId = external ID
* Items mapped from Snappfood items to MenuItems by name match
- Save order to DB
- Broadcast to KDS via SignalR
- Return 200 OK within 5 seconds
Also:
PATCH /api/cafes/{cafeId}/orders/{id}/status
- When status → Delivered: notify Snappfood API if SnappfoodOrderId exists
```
---
## مرحله ۱۱ — اشتباهات رایج که باید از آن‌ها بپرهیزی
```
❌ نکن:
- Console.WriteLine در C# → از ILogger<T> استفاده کن
- ml-4 یا mr-4 در Next.js → از ms-4 و me-4 استفاده کن
- new Date() برای نمایش تاریخ → از date-fns-jalali استفاده کن
- متن فارسی hardcode در کامپوننت → همه در fa.json باشد
- query بدون .Where(x => x.CafeId == cafeId) → داده tenant دیگر برمی‌گرداند
- setState در Flutter برای business logic → از Riverpod استفاده کن
- .Result یا .Wait() در C# → deadlock می‌دهد
✅ بکن:
- هر mutation در Flutter اول به Drift ذخیره کن، بعد sync کن
- هر endpoint با [Authorize] + validate CafeId شروع کن
- هر string قابل نمایش را در fa.json/ar.json/en.json بریز
- تمام اعداد نمایشی را با .toLocaleString('fa-IR') فرمت کن
- هر job background را در Hangfire بریز، نه await inline
```
---
## مرحله ۱۲ — ترتیب توسعه پیشنهادی (Solo با Cursor)
```
هفته ۱-۲: Backend foundation (auth + schema + tenant middleware)
هفته ۳-۴: POS core (menu + orders + tables + QR + payments)
هفته ۵-۶: Dashboard Next.js (POS screen + KDS + basic reports)
هفته ۷-۸: CRM + Coupons + SMS marketing (Kavenegar)
هفته ۹-۱۰: HR module (shifts + attendance + payroll)
هفته ۱۱-۱۲: Flutter customer app (QR + menu + cart + reservation)
هفته ۱۳-۱۴: Discovery platform (کافه‌یاب) + Reviews
هفته ۱۵-۱۶: ZarinPal billing + Taraz + Snappfood + production deploy
اولین beta: 5 کافه در شمال تهران — هفته ۸
اولین پول: هفته ۱۶
```
---
## چک‌لیست شروع روز اول
```
[ ] Node 20+ نصب است
[ ] .NET 10 SDK نصب است
[ ] Flutter 3.x نصب است
[ ] Docker Desktop در حال اجرا است
[ ] Cursor نصب است و باز است
[ ] پوشه meezi/ ساخته شده
[ ] .cursorrules در ریشه قرار دارد
[ ] MEEZI_PRD.md در ریشه قرار دارد
[ ] docker-compose up -d اجرا شده
[ ] در Cursor: Cmd+L → "Read .cursorrules and MEEZI_PRD.md,
then start Sprint 1: create the .NET solution structure"
```