Files
jdescopingtool/openspec/specs/sql-business-logic/spec.md
T
Joseph Doherty 26ff8d9b4f Initial commit: JDE Scoping Tool migration project
Set up repository with legacy .NET Framework 4.8 source (OLD/),
new .NET 10 Blazor solution (NEW/), OpenSpec specifications,
documentation, and project configuration.
2026-01-02 07:43:29 -05:00

303 lines
12 KiB
Markdown

# 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
1. **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)
2. **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
3. **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
4. **Item Description Lookup**: The function SHALL lookup and include the item description from the Item table
5. **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
1. **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.
2. **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.
3. **MatchMIS truncation**: Alias sequence numbers are cast to INT before string compare, which is a lossy conversion not documented in the spec.
### Low Priority
1. **CompleteSearch NULL behavior**: When @Success is NULL, SQL treats it as failure (Status=4) and still overwrites Results. This edge case is undocumented.
2. **Output column order**: MatchMIS columns in spec differ from SQL (SamplingType/SamplingValue vs ToolsGauges/WorkInstructions position) - may matter for ordinal access.