Set up repository with legacy .NET Framework 4.8 source (OLD/), new .NET 10 Blazor solution (NEW/), OpenSpec specifications, documentation, and project configuration.
12 KiB
SQL Business Logic Specification
Purpose
This specification documents stored procedures and functions that implement database-level business logic for the search processing workflow. These SQL objects manage the lifecycle of search requests (submission, execution, completion) and provide complex matching logic for Manufacturing Information System (MIS) data.
Source Reference
| Legacy File | Purpose |
|---|---|
| OLD/Database/StoredProcedures/SubmitSearch.sql | Create new search record with Queued status |
| OLD/Database/StoredProcedures/StartSearch.sql | Transition search to Processing status |
| OLD/Database/StoredProcedures/CompleteSearch.sql | Finalize search with results or failure |
| OLD/Database/StoredProcedures/ResetPartialSearches.sql | Recovery procedure for stuck searches |
| OLD/Database/Functions/MatchMis.sql | MIS data matching based on routing/master |
Requirements
Requirement: Submit search procedure
The system SHALL provide a SubmitSearch stored procedure that creates new search records in the database.
Inputs
- @p_UserName (VARCHAR(128)) - Username of the person submitting the search
- @p_Name (VARCHAR(128)) - User-provided name/description for the search
- @p_Criteria (VARCHAR(MAX)) - JSON-serialized search criteria
Outputs
- @o_SearchID (INT OUTPUT) - The auto-generated ID of the newly created search record
Business Rules
- The procedure SHALL insert a new record into the Search table
- Status SHALL be set to 1 (Queued) for all new searches
- SubmitDT SHALL be set to the current date/time via GETDATE()
- The new SearchId SHALL be retrieved using SCOPE_IDENTITY() to ensure the correct ID in concurrent scenarios
Scenario: Submit new search
- WHEN SubmitSearch is called with valid username, search name, and criteria
- THEN a new Search record is inserted with Status = 1 (Queued)
- AND SubmitDT is set to the current timestamp
- AND the new SearchId is returned via the @o_SearchID OUTPUT parameter
Scenario: Concurrent search submissions
- WHEN multiple users submit searches simultaneously
- THEN each call returns the correct SearchId via SCOPE_IDENTITY()
- AND no cross-session ID contamination occurs
Requirement: Start search procedure
The system SHALL provide a StartSearch stored procedure that marks a search as being actively processed.
Inputs
- @p_SearchID (INT) - The ID of the search to start processing
Outputs
- None (procedure updates record in place)
Business Rules
- The procedure SHALL update the Status to 2 (Processing)
- The procedure SHALL set StartDT to the current date/time via GETDATE()
- Only the search record matching the provided ID SHALL be updated
Scenario: Start processing a queued search
- WHEN StartSearch is called with a valid SearchID
- THEN the search Status is updated to 2 (Processing)
- AND StartDT is set to the current timestamp
Requirement: Complete search procedure
The system SHALL provide a CompleteSearch stored procedure that finalizes a search with results or failure status.
Inputs
- @p_SearchID (INT) - The ID of the search to complete
- @p_WasSuccessful (BIT) - Flag indicating success (1) or failure (0)
- @p_Results (VARBINARY(MAX)) - Binary Excel file data (may be NULL on failure)
Outputs
- None (procedure updates record in place)
Business Rules
- When @p_WasSuccessful = 1, Status SHALL be set to 3 (Complete)
- When @p_WasSuccessful = 0, Status SHALL be set to 4 (Failed)
- The Results column SHALL be updated with the provided binary data
- EndDT SHALL be set to the current date/time via GETDATE()
Scenario: Complete successful search
- WHEN CompleteSearch is called with WasSuccessful = 1 and Excel binary data
- THEN the search Status is updated to 3 (Complete)
- AND the Results column contains the Excel binary
- AND EndDT is set to the current timestamp
Scenario: Complete failed search
- WHEN CompleteSearch is called with WasSuccessful = 0
- THEN the search Status is updated to 4 (Failed)
- AND EndDT is set to the current timestamp
Requirement: Reset partial searches procedure
The system SHALL provide a ResetPartialSearches stored procedure that recovers searches stuck in a processing state.
Inputs
- None (parameterless procedure)
Outputs
- None (procedure updates records in place)
Business Rules
- The procedure SHALL identify searches where StartDT IS NOT NULL AND EndDT IS NULL
- These searches represent work that was started but never completed (e.g., service crash)
- Status SHALL be reset to 1 (Queued) for all identified searches
- StartDT SHALL be set to NULL to allow re-processing
Scenario: Service restart recovery
- WHEN the worker service starts and calls ResetPartialSearches
- THEN all searches with StartDT set but EndDT NULL are reset
- AND Status is changed back to 1 (Queued)
- AND StartDT is cleared to NULL
- AND these searches become eligible for re-processing
Scenario: No stuck searches
- WHEN ResetPartialSearches is called with no searches in partial state
- THEN no records are modified
Requirement: MIS matching function
The system SHALL provide a MatchMIS table-valued function that correlates work order operations with Manufacturing Information System (MIS) quality documents.
Inputs
- @workOrderNumber (BIGINT) - Work order number to match
- @itemNumber (VARCHAR(25)) - Item/part number
- @branchCode (VARCHAR(12)) - Branch/plant code
- @routingType (VARCHAR(3)) - Routing type identifier
- @issueDate (DATETIME) - Issue date for routing validity
- @workCenterCode (VARCHAR(12)) - Work center identifier
- @sequenceNumber (DECIMAL(7,2)) - Operation sequence number
- @steptimestamp (DATETIME) - Timestamp of the operation step
- @functionCode (VARCHAR(15)) - Function/operation code
- @functionOperationDescription (VARCHAR(80)) - Description of the operation
Outputs
Returns a table with the following columns:
- WorkOrderNumber, ItemNumber, ItemDescription, BranchCode, WorkCenterCode
- StepTimestamp, SequenceNumber, FunctionCode, FunctionOperationDescription
- MatchedSequenceNumber (DECIMAL(7,2)) - Sequence number used for MIS lookup
- RoutingMatch (BIT) - Whether match came from work order routing
- MasterMatch (BIT) - Whether match came from route master
- MisNumber, RevID, CharNumber, MisSequenceNumber (VARCHAR(32)) - MIS document identifiers
- TestDescription, ToolsGauges, WorkInstructions (VARCHAR(2000)) - MIS content
- SamplingType, SamplingValue, Status (VARCHAR(32)) - MIS metadata
- ReleaseDate (DATETIME) - MIS document release date
Business Rules
-
Parent Work Order Resolution: The function SHALL resolve to the parent work order number if available (using TRY_CONVERT to handle non-numeric parent references)
-
Sequence Number Alias Discovery: The function SHALL find alias sequence numbers using a two-tier approach:
- First, check WorkOrderRouting (F3112Z1) for matches on work center and function code using the earliest transaction date
- If no routing matches exist, check RouteMaster (F3003) for matches within the issue date validity range
-
MIS Matching Priority: The function SHALL attempt MIS matching in priority order:
- First priority: Match MisData records with Status = 'Current' where steptimestamp falls within ReleaseDate to ObsoleteDate
- Second priority: Match MisData records with Status = 'BackLevel' where ReleaseDate falls between issueDate and steptimestamp
- Third priority: Return alias information without MIS data if aliases exist but no MIS match
- Fourth priority: Return input parameters with NULL matched sequence and both match flags = 0
-
Item Description Lookup: The function SHALL lookup and include the item description from the Item table
-
Date Range Handling: NULL ReleaseDate SHALL be treated as '1970-01-01', NULL ObsoleteDate SHALL be treated as '2029-01-01'
Scenario: Match via work order routing with current MIS
- WHEN MatchMIS is called for a work order with routing data
- AND a current MIS document exists for the matched sequence
- THEN results include RoutingMatch = 1 and full MIS details
- AND MasterMatch indicates whether route master also matched
Scenario: Match via route master when no routing exists
- WHEN MatchMIS is called for a work order without specific routing
- AND a route master entry exists for the item/branch/work center
- THEN results include MasterMatch = 1 and RoutingMatch = 0
- AND MIS details are included if available
Scenario: BackLevel MIS fallback
- WHEN no current MIS document matches
- AND a BackLevel MIS document exists with ReleaseDate in the valid range
- THEN results include the BackLevel MIS details with Status = 'BackLevel'
Scenario: No MIS match found
- WHEN no MIS documents match the routing or master sequence
- THEN results include the input parameters with alias information
- AND MIS-specific columns are NULL
Scenario: No routing or master match
- WHEN no work order routing or route master entries match
- THEN results include input parameters only
- AND MatchedSequenceNumber is NULL
- AND RoutingMatch = 0 and MasterMatch = 0
Search Status Codes
| Code | Name | Description |
|---|---|---|
| 1 | Queued | Search submitted, awaiting processing |
| 2 | Processing | Search actively being executed |
| 3 | Complete | Search finished successfully with results |
| 4 | Failed | Search encountered an error |
State Transition Diagram
[New Search]
|
v
SubmitSearch
|
v
+-------+
|Queued |<---------+
| (1) | |
+---+---+ |
| |
v |
StartSearch ResetPartialSearches
| |
v |
+----------+ |
|Processing|-------+
| (2) |
+----+-----+
|
v
CompleteSearch
|
+---------------+
| |
v v
+--------+ +------+
|Complete| |Failed|
| (3) | | (4) |
+--------+ +------+
Migration Notes
| Legacy Pattern | New Pattern | Rationale |
|---|---|---|
| Status as INT codes (1,2,3,4) | Consider enum type or constants | Improves readability and type safety |
| SCOPE_IDENTITY() for new ID | EF Core auto-populates Id on SaveChanges | Framework handles identity retrieval |
| Stored procedures for state transitions | Entity state management with domain events | Enables better testability and event sourcing |
| VARBINARY(MAX) for Excel storage | Consider cloud blob storage reference | Reduces database size, enables streaming |
| Table-valued function for MIS matching | LINQ query or stored procedure | Evaluate performance tradeoffs |
Decisions Made
- MatchMIS migration: Keep as SQL function - proven logic, better performance for large datasets
- Domain events: Yes, emit events on status transitions - enables audit trail and future event sourcing
- Excel storage: Keep in database VARBINARY - match legacy, simpler deployment
- Reset timeout: No timeout - match legacy behavior, reset any search with StartDT but no EndDT
Codex Review Findings
Medium Priority
- State transitions lack validation: Legacy procedures update by ID without checking current Status. ResetPartialSearches uses StartDT/EndDT presence, not Status value. The spec's state diagram implies stricter transitions than implemented.
- MatchMIS alias discovery incomplete: RouteMaster is still merged when routing aliases exist (to set MasterMatch on existing sequences). Routing uses earliest transaction date for entire work order which may skip later matches.
- MatchMIS truncation: Alias sequence numbers are cast to INT before string compare, which is a lossy conversion not documented in the spec.
Low Priority
- CompleteSearch NULL behavior: When @Success is NULL, SQL treats it as failure (Status=4) and still overwrites Results. This edge case is undocumented.
- Output column order: MatchMIS columns in spec differ from SQL (SamplingType/SamplingValue vs ToolsGauges/WorkInstructions position) - may matter for ordinal access.