# Obsolete Material Policy Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Exclude obsolete materials from operational selection and reject them in new or edited warehouse operations while preserving administrative management, historical records, and readable disabled selections when editing old documents. **Architecture:** `GET /materials` gains a validated status scope that defaults to active records. The material-management UI requests all records, while shared operational options keep the active default. A distinct active-status check is applied at server-side operation boundaries; historical queries remain status-agnostic. **Tech Stack:** Go 1.21, Gin, MySQL, Vue 3, Pinia, Vitest, sqlmock. **Spec:** User-approved table in this conversation: operational selectors return active materials; material management returns all; historical documents remain readable; new and edited operations require active materials. ## Global Constraints - Do not delete or mutate historical document records. - Keep `Exists` as an existence check; use a new active-status check for operational validation. - Default list scope is `active`; only material management requests `all`. - Use test-first development for each behavior change. --- ### Task 1: Status-scoped material lists **Files:** - Modify: `internal/handler/api.go`, `internal/service/material.go`, `internal/repository/material.go` - Modify: `internal/repository/material_test.go` - Modify: `frontend/src/stores/materials.js`, `frontend/src/views/Materials.vue`, `docs/api.md` **Interfaces:** - Produces: `MaterialService.List(search, status string, limit, offset int)` and repository equivalent. - Produces: `GET /materials` defaults to `status=active`; `status=all` returns active and obsolete records. - [ ] Write sqlmock tests for active and all list SQL predicates. - [ ] Run the focused repository tests and observe missing status-aware query behavior. - [ ] Add a `status` filter to the count and result queries; accept `active`, `obsolete`, and `all` in the handler. - [ ] Make `fetchMaterials` accept a status argument and have `Materials.vue` request `all`; leave `fetchMaterialOptions` on the active default. - [ ] Update API documentation and run focused backend/frontend tests. ### Task 2: Server-side active material validation **Files:** - Modify: `internal/service/material.go`, `internal/service/errors.go` - Modify: `internal/service/inbound.go`, `internal/service/outbound.go`, `internal/service/application.go` - Modify: `internal/handler/api.go`, `internal/service/material_test.go` **Interfaces:** - Produces: `MaterialService.IsActive(id int64) (bool, error)` and `ErrMaterialObsolete`. - Consumes: active check in inbound, outbound, and application create/edit validation. - [ ] Write a failing service test for a material whose status is `obsolete`. - [ ] Run it and observe that existence currently passes without evaluating status. - [ ] Implement `IsActive` and use it before transaction work in inbound/outbound/application workflows. - [ ] Map `ErrMaterialObsolete` to a clear 400 API response. - [ ] Run related service/handler tests. ### Task 3: Cache and regression verification **Files:** - Modify: `frontend/src/stores/materials.js`, `frontend/src/stores/materials.test.js` - Modify: `docs/api.md` - [ ] Write a failing frontend store test proving obsolete/restore refreshes operational options. - [ ] Refresh `materialOptions` after obsolete and restore calls. - [ ] Run the full frontend test suite and `go test ./...`. - [ ] Confirm historical document detail queries remain unfiltered by material status. ### Task 4: Read-only representation of obsolete historical selections **Files:** - Modify: `internal/model/model.go`, `internal/repository/inbound.go`, `internal/repository/outbound.go` - Modify: `frontend/src/views/Inbound.vue`, `frontend/src/views/Outbound.vue` - Modify: `frontend/src/views/Inbound.test.js` **Interfaces:** - Produces: inbound/outbound item responses that include the material status used by editing forms. - Produces: selected obsolete items are kept in their edit-form options with `disabled: true`. - [ ] Write a failing view test that opens a historical document containing an obsolete material and expects its code/name to remain visible in a disabled select option. - [ ] Include `m.status` in document item detail queries and responses without filtering the historical join. - [ ] Merge an obsolete item from the document detail into that edit row's options only; mark it disabled and do not add it to shared active options. - [ ] Verify save remains blocked server-side by Task 2 when the old obsolete material is retained.