35d98c16e9
- 新增 ApiKeyAuth 中间件(hash_equals 防时序攻击) - 新增 PublicApiController(piList/vinList 两个只读接口) - 仅返回已审批通过(approval_status=2)的数据,支持分页和模糊搜索 - LIKE 通配符已转义,异常信息不暴露内部细节 - 附对接文档 docs/public-stock-api.md Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
108 lines
2.5 KiB
Markdown
108 lines
2.5 KiB
Markdown
# Public Stock Order API Design
|
|
|
|
## Goal
|
|
|
|
Provide two read-only public APIs for internal systems to query approved stock order PI numbers and VIN numbers, with API Key authentication.
|
|
|
|
## Data Model
|
|
|
|
- `stock_orders.approval_status = 2` means approved
|
|
- `stock_orders.pi_no` — PI number (string)
|
|
- `stock_order_items.vin` — VIN/chassis number (string)
|
|
- `stock_order_items.model_snapshot` — car model name (plain string)
|
|
- `stock_order_items.order_id` → `stock_orders.id`
|
|
|
|
## Authentication
|
|
|
|
New middleware `ApiKeyAuth`:
|
|
|
|
- Read `Fdesk-Api-Key` header
|
|
- Compare against key stored in `.env` (`API_KEY`) or `config/app.php`
|
|
- Reject with 401 on mismatch or missing key
|
|
- Bypass both `AuthCheck` (JWT) and `BasicData` middleware
|
|
|
|
## Endpoints
|
|
|
|
### A. PI Number List
|
|
|
|
```
|
|
GET /common/public/pi/list
|
|
Headers: Fdesk-Api-Key: <key>
|
|
Query: page, page_size, pi_no (optional filter)
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"code": 200,
|
|
"data": {
|
|
"total": 150,
|
|
"per_page": 20,
|
|
"current_page": 1,
|
|
"data": [
|
|
{
|
|
"pi_no": "PI20250601001",
|
|
"vins": ["LSVAU2A39N2123456", "LSVAU2A39N2123457"],
|
|
"model_names": ["Model Y", "Model 3"]
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
Logic:
|
|
1. Query `stock_orders` where `approval_status = 2` and `pi_no IS NOT NULL` and `pi_no != ''`
|
|
2. Optional filter by `pi_no` (LIKE match)
|
|
3. Paginate
|
|
4. For each order, eager-load `items` → collect `vin` and `model_snapshot`
|
|
5. Return aggregated result
|
|
|
|
### B. VIN Number List
|
|
|
|
```
|
|
GET /common/public/vin/list
|
|
Headers: Fdesk-Api-Key: <key>
|
|
Query: page, page_size, vin (optional filter)
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"code": 200,
|
|
"data": {
|
|
"total": 500,
|
|
"per_page": 20,
|
|
"current_page": 1,
|
|
"data": [
|
|
{
|
|
"vin": "LSVAU2A39N2123456",
|
|
"model_name": "Model Y"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
Logic:
|
|
1. Query `stock_order_items` via `stock_orders` where `approval_status = 2`
|
|
2. Optional filter by `vin` (LIKE match)
|
|
3. Paginate
|
|
4. Return `vin` + `model_snapshot` per item
|
|
|
|
## File Changes
|
|
|
|
| Action | File | Description |
|
|
|--------|------|-------------|
|
|
| New | `app/middleware/ApiKeyAuth.php` | API Key auth middleware |
|
|
| New | `app/common/controller/PublicApiController.php` | Two endpoints |
|
|
| Modify | `config/route.php` | Add `/common/public/*` route group with ApiKeyAuth |
|
|
|
|
## Constraints
|
|
|
|
- Read-only, no write operations
|
|
- Only `approval_status = 2` records
|
|
- Pagination required (default page_size = 20)
|
|
- No JWT / BasicData middleware for these routes
|