# NFC BD API v1 — Web ar Mobile App-er jonno

Ek API diye React web, admin panel, ar Android/iOS app (React Native, Flutter, Kotlin, Swift) sob cholbe.

- **Base URL:** `https://api.yourdomain.com/api/v1` (local: `http://127.0.0.1:8000/api/v1`)
- **Format:** JSON. Protiti request-e `Accept: application/json` header din.
- **Auth:** Laravel Sanctum token. Login/register-e `token` pabe, tarpor protiti request-e:
  `Authorization: Bearer <token>`
- Token-er meyad nei; logout korle ba admin block korle bati hoy.
- Postman: `docs/NFCBD.postman_collection.json` import korun. Login korle token automatic save hoy.

## Mobile app-er jonno note
- `device_name` pathan (`"android"`, `"ios"`) — ek user ek-adhik device-e login thakte pare.
- Token phone-er secure storage-e rakhun (Android Keystore / iOS Keychain / `expo-secure-store`).
- Mobile app-e CORS lage na; shudhu browser-er jonno `CORS_ALLOWED_ORIGINS`.
- 401 pele token muche login screen-e pathan.
- **Payment:** `POST my/card/purchase` → `redirect_url` WebView ba in-app browser-e khulun. Shesh hole server redirect kore
  `{FRONTEND_URL}/payment/result?tran_id=...&status=success|failed|cancelled`. App ei URL dhore WebView bondho kore
  `GET my/payments/{tran_id}` diye nishchit hobe (query param-e bharsha korben na).
- **QR:** `GET my/card/qr` → `payload` string QR banan, proti 30 second-e abar call korun (QR 90 second valid).

## Error format
| Status | Mane | Body |
|---|---|---|
| 401 | Login lagbe / token bati | `{"message": "Login korun"}` |
| 403 | Permission nei / blocked | `{"message": "..."}` |
| 404 | Pawa jayni | `{"message": "..."}` |
| 409 | Duplicate (1 min-e ek card-e 2 bar discount) | `{"message": "..."}` |
| 422 | Validation | `{"message": "...", "errors": {"field": ["..."]}}` |
| 429 | Onek request / OTP ekhono valid | `{"message": "...", "errors": {...}}` |

List endpoint gulo paginated: `{"data": [...], "current_page": 1, "last_page": 3, "total": 52, ...}` — `?page=2` diye next page.

## Registration (Field officer referral code + OTP)
Field officer-er referral code **optional**. Na dile customer kono officer chara register hoy. Dile code thik hote hobe — bhul ba blocked officer-er code-e OTP jay na, ar thik code-e customer oi officer-er nam-e save hoy.
```
GET  auth/referral/FO1001     → {"code":"FO1001","officer_name":"Karim"}   (404 = code thik nei)

POST auth/register/send-otp   {"phone":"01712345678","referral_code":"FO1001"}
→ 200 {"message":"OTP pathano hoyeche","officer_name":"Karim","expires_in":120,"resend_in":120}
   (SMS_DRIVER=log ar APP_DEBUG=true hole "debug_otp" o ashe — sudhu test-e)

POST auth/register  {"name","phone","password","password_confirmation","referral_code","otp","device_name"}
→ 201 {"token":"1|abc...","user":{...}}
```
OTP-r meyad thakte abar `send-otp` dile 429. Meyad shesh hole notun OTP chawa jay. 5 bar bhul OTP dile notun lagbe.

## Login
```
POST auth/login {"phone":"01900000000","password":"customer123","device_name":"android"}
→ {"token":"...","user":{"id":3,"name":"...","phone":"...","role":"customer|merchant|admin","card":{...}|null,"merchant":{...}|null}}
```
`role` dekhe app thik screen dekhabe: customer → card app, merchant → scanner, field_officer → officer panel.
Field officer-er `user.referral_code`-e tar code thake.

## Endpoints

## Package ar service kivabe kaj kore
- **Service** (`categories`) = Restaurant, Pharmacy, Hospital... Protiti shop ekta service-er.
- **Package** (`card-plans`) = je card customer kene (Classic / Premium / Gold). Protiti package-e kichu service thake,
  ar **protiti service-er alada rate**: `discount_percent`, `max_discount` (protiti bill-e sorbochcho ৳, null = sima nei), `details`.
- Shop-e discount = customer-er package-e oi shop-er service-er rate. Package-e service na thakle discount nei
  (`merchant/verify` → 422 "package-e ei service-er discount nei").
- Shop list-e `discount_upto` = chalu package gulor moddhe oi service-er sorbochcho rate ("X% porjonto").

### Public (token lage na)
| Method | Path | Kaj |
|---|---|---|
| GET | `home` | banners, categories, featured, top_discounts, plans — home screen ek call-e |
| GET | `categories` | service list + `discount_upto` + shop count |
| GET | `categories/{slug}` | service details: `service` (description, image) + `packages` [{plan, discount_percent, max_discount, details}] |
| GET | `merchants` | `?category=slug&search=&area=&featured=1&sort=discount|new&page=` ; kache: `?lat=&lng=` (MySQL) |
| GET | `merchants/{slug}` | shop detail + `discount_upto` + `package_rates` (protiti package-e ei shop-e koto) |
| GET | `card-plans` | package list, protitir `services` [{category, discount_percent, max_discount, details}] |
| GET | `card-plans/{slug}` | package details (image_url, badge, details, benefits, services + shop count) |

### Customer (token)
| Method | Path | Kaj |
|---|---|---|
| GET | `auth/me` | user + active card |
| PUT | `profile` | `name`, `email` |
| PUT | `profile/password` | `current_password`, `password`, `password_confirmation` |
| POST | `auth/logout` | ei device-er token bati |
| GET | `my/summary` | card, total_saved, month_saved, total_visits |
| GET | `my/card` | sorbo-shesh card (meyad shesh holeo, renew dekhanor jonno) |
| GET | `my/card/qr` | `{"payload":"DC1....","expires_in":90}` |
| POST | `my/card/purchase` | `{"card_plan_id":1,"gateway":"bkash|sslcommerz"}` → `{"tran_id","redirect_url"}` |
| GET | `my/payments` , `my/payments/{tran_id}` | payment list / status |
| GET | `my/redemptions` | kothay koto chhar peyechen |

### Merchant (role = merchant)
| Method | Path | Kaj |
|---|---|---|
| GET | `merchant/dashboard` | aj/mash-er hishab, recent |
| POST | `merchant/verify` | `{"code":"<QR payload ba 16 digit card>","bill_amount":1500}` → customer, discount %, preview |
| POST | `merchant/redeem` | `{"code","bill_amount","note"}` → 201 redemption (payable_amount customer debe) |
| GET | `merchant/redemptions` | `?from=&to=` |

### Field officer (role = field_officer)
| Method | Path | Kaj |
|---|---|---|
| GET | `officer/dashboard` | code, aj / ei mash / sob shomoy: registered, bought_card, active_cards, revenue; recent |
| GET | `officer/customers` | tar registration kora customer `?search=&card=active|none&from=&to=&page=` |

Officer nijer phone theke customer register korle `auth/register` direct call korun ar ferot asha token rakhben na (officer login thakbe).

### Admin (role = admin)
| Method | Path |
|---|---|
| GET | `admin/dashboard` |
| CRUD | `admin/categories`, `admin/merchants`, `admin/card-plans`, `admin/banners` (GET list, POST, GET/PUT/DELETE `{id}`) |
| | `admin/card-plans` body: `name, slug, badge, price, duration_days, description, details, benefits[], color, image(file), is_active, services` — `services` = `[{"category_id":1,"discount_percent":15,"max_discount":800,"details":""}]` (multipart-e JSON string). Puro list pathale ager list replace hoy. |
| | `admin/categories` body: `name, name_bn, icon, description, image(file), sort, is_active` |
| GET/POST, GET/PUT `{id}` | `admin/users` (`status: blocked` dile shob device logout) |
| GET/POST, GET/PUT `{id}` | `admin/field-officers` (code na dile auto `FO1003`...; `show`-e summary + customer list `?from=&to=`) |
| GET | `admin/field-officers/report?from=&to=` — protiti officer: registered, bought_card, active_cards, revenue |
| GET | `admin/users?referred_by={officer_id}` — kon officer kake registration koriyeche |
| GET | `admin/subscriptions?state=active|expiring|expired|cancelled&search=` |
| POST | `admin/subscriptions/grant` `{"user_id","card_plan_id","days"}` |
| PUT | `admin/subscriptions/{id}` `{"expires_at","status","card_plan_id"}` |
| GET | `admin/payments?status=&gateway=&from=&to=&search=` , `admin/redemptions?merchant_id=&from=&to=` |

Image upload (merchant `logo`/`cover`, banner/package/service `image`): `multipart/form-data`. Edit-e `POST admin/merchants/{id}` + `_method=PUT` field (PHP multipart PUT pore na).
