Implement full-stack material trace feature enabling forward (LOT/工單 → 原物料) and reverse (原物料 → LOT) queries with wildcard support, safeguards (memory guard, IN-clause batching, Oracle slow-query channel), CSV export, and portal-shell integration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
121 lines
6.2 KiB
Markdown
121 lines
6.2 KiB
Markdown
## ADDED Requirements
|
|
|
|
### Requirement: Material Trace API SHALL provide forward query endpoint
|
|
The API SHALL accept LOT IDs or work order numbers and return corresponding material consumption records from `DW_MES_LOTMATERIALSHISTORY`.
|
|
|
|
#### Scenario: Forward query by LOT ID
|
|
- **WHEN** `POST /api/material-trace/query` is called with `mode: "lot"` and `values: ["GA25060001-A01", "GA25060502"]`
|
|
- **THEN** the API SHALL resolve LOT names to CONTAINERIDs via `DW_MES_CONTAINER`
|
|
- **THEN** the API SHALL return material consumption records matching those CONTAINERIDs
|
|
- **THEN** each record SHALL include CONTAINERID, CONTAINERNAME, PJ_WORKORDER, WORKCENTERNAME, WORKCENTER_GROUP, MATERIALPARTNAME, MATERIALLOTNAME, VENDORLOTNUMBER, QTYREQUIRED, QTYCONSUMED, EQUIPMENTNAME, TXNDATE, PRIMARY_CATEGORY, SECONDARY_CATEGORY
|
|
|
|
#### Scenario: Forward query by work order
|
|
- **WHEN** `POST /api/material-trace/query` is called with `mode: "workorder"` and `values: ["WO-2025-001", "WO-2025-002"]`
|
|
- **THEN** the API SHALL query `DW_MES_LOTMATERIALSHISTORY` using `PJ_WORKORDER` index directly
|
|
- **THEN** the response format SHALL be identical to LOT ID mode
|
|
|
|
#### Scenario: Forward query with workcenter group filter
|
|
- **WHEN** `POST /api/material-trace/query` includes `workcenter_groups: ["焊接_DB"]`
|
|
- **THEN** the API SHALL resolve group names to WORKCENTERNAME list via `filter_cache.get_workcenter_mapping()`
|
|
- **THEN** the SQL query SHALL include `AND WORKCENTERNAME IN (...)` filter
|
|
- **THEN** results SHALL only contain records from workcenters belonging to the selected groups
|
|
|
|
#### Scenario: Forward query input limit
|
|
- **WHEN** `POST /api/material-trace/query` with `mode: "lot"` or `mode: "workorder"` contains more than 200 values
|
|
- **THEN** the API SHALL return HTTP 400 with error message indicating the 200-value limit
|
|
|
|
### Requirement: Material Trace API SHALL provide reverse query endpoint
|
|
The API SHALL accept material lot names and return LOTs that consumed those materials.
|
|
|
|
#### Scenario: Reverse query by material lot name
|
|
- **WHEN** `POST /api/material-trace/query` is called with `mode: "material_lot"` and `values: ["WIRE-LOT-20250101-A"]`
|
|
- **THEN** the API SHALL query `DW_MES_LOTMATERIALSHISTORY` using `MATERIALLOTNAME` index
|
|
- **THEN** each record SHALL include the same fields as forward query results
|
|
|
|
#### Scenario: Reverse query with workcenter group filter
|
|
- **WHEN** reverse query includes `workcenter_groups` parameter
|
|
- **THEN** the same workcenter group filtering logic as forward query SHALL apply
|
|
|
|
#### Scenario: Reverse query input limit
|
|
- **WHEN** `POST /api/material-trace/query` with `mode: "material_lot"` contains more than 50 values
|
|
- **THEN** the API SHALL return HTTP 400 with error message indicating the 50-value limit
|
|
|
|
#### Scenario: Reverse query result limit
|
|
- **WHEN** reverse query results exceed 10,000 rows
|
|
- **THEN** the API SHALL return exactly 10,000 rows
|
|
- **THEN** the response `meta` SHALL include `truncated: true` and `max_rows: 10000`
|
|
|
|
### Requirement: Material Trace API SHALL validate query parameters
|
|
The API SHALL validate input parameters before executing database queries.
|
|
|
|
#### Scenario: Missing required fields
|
|
- **WHEN** `POST /api/material-trace/query` is called without `mode` or `values`
|
|
- **THEN** the API SHALL return HTTP 400 with descriptive validation error
|
|
|
|
#### Scenario: Invalid mode
|
|
- **WHEN** `mode` is not one of `lot`, `workorder`, `material_lot`
|
|
- **THEN** the API SHALL return HTTP 400
|
|
|
|
#### Scenario: Empty values
|
|
- **WHEN** `values` is an empty array or all values are blank after trimming
|
|
- **THEN** the API SHALL return HTTP 400 with error message "請輸入至少一筆查詢條件"
|
|
|
|
#### Scenario: Unresolvable LOT IDs
|
|
- **WHEN** some LOT names cannot be resolved to CONTAINERIDs
|
|
- **THEN** the API SHALL proceed with the resolved subset
|
|
- **THEN** the response `meta` SHALL include `unresolved` array listing unresolvable LOT names
|
|
|
|
### Requirement: Material Trace API SHALL support paginated results
|
|
The API SHALL support server-side pagination for query results.
|
|
|
|
#### Scenario: Pagination parameters
|
|
- **WHEN** `POST /api/material-trace/query` includes `page` and `per_page`
|
|
- **THEN** results SHALL be paginated accordingly
|
|
- **THEN** response SHALL include `pagination: { page, per_page, total, total_pages }`
|
|
|
|
#### Scenario: Default pagination
|
|
- **WHEN** `page` or `per_page` is not provided
|
|
- **THEN** `page` SHALL default to 1
|
|
- **THEN** `per_page` SHALL default to 50
|
|
|
|
#### Scenario: Per-page cap
|
|
- **WHEN** `per_page` exceeds 200
|
|
- **THEN** `per_page` SHALL be capped at 200
|
|
|
|
### Requirement: Material Trace API SHALL provide CSV export endpoint
|
|
The API SHALL provide CSV export using the same query parameters as the query endpoint.
|
|
|
|
#### Scenario: Export request
|
|
- **WHEN** `POST /api/material-trace/export` is called with the same parameters as query
|
|
- **THEN** the response SHALL be a CSV file with UTF-8 BOM encoding
|
|
- **THEN** CSV headers SHALL be in Chinese
|
|
- **THEN** all matching records SHALL be included (no pagination, subject to result limits)
|
|
|
|
#### Scenario: Export result limit
|
|
- **WHEN** export results exceed 50,000 rows
|
|
- **THEN** the export SHALL be truncated at 50,000 rows
|
|
- **THEN** a warning header SHALL indicate truncation
|
|
|
|
### Requirement: Material Trace API SHALL enrich results with workcenter group
|
|
The API SHALL add WORKCENTER_GROUP to each result row based on `filter_cache.get_workcenter_mapping()`.
|
|
|
|
#### Scenario: Workcenter group enrichment
|
|
- **WHEN** query results are returned
|
|
- **THEN** each row SHALL include a `WORKCENTER_GROUP` field
|
|
- **THEN** the value SHALL be resolved from `filter_cache.get_workcenter_mapping()` using the row's `WORKCENTERNAME`
|
|
|
|
#### Scenario: Unknown workcenter
|
|
- **WHEN** a row's WORKCENTERNAME has no mapping in the workcenter cache
|
|
- **THEN** `WORKCENTER_GROUP` SHALL be empty string
|
|
|
|
### Requirement: Material Trace API SHALL apply rate limiting
|
|
The API SHALL rate-limit query and export endpoints to protect Oracle resources.
|
|
|
|
#### Scenario: Query rate limit
|
|
- **WHEN** `/api/material-trace/query` receives excessive requests
|
|
- **THEN** requests beyond 30 per 60 seconds SHALL be rejected with HTTP 429
|
|
|
|
#### Scenario: Export rate limit
|
|
- **WHEN** `/api/material-trace/export` receives excessive requests
|
|
- **THEN** requests beyond 10 per 60 seconds SHALL be rejected with HTTP 429
|