@nivora/matrix 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -1
- package/.next/app-path-routes-manifest.json +4 -4
- package/.next/build-manifest.json +2 -2
- package/.next/prerender-manifest.json +3 -3
- package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_global-error.html +2 -2
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +1 -1
- package/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/builder/page.js +3 -3
- package/.next/server/app/builder/page_client-reference-manifest.js +1 -1
- package/.next/server/app/guide/page_client-reference-manifest.js +1 -1
- package/.next/server/app/matrix/page_client-reference-manifest.js +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/releases/[id]/page.js +15 -15
- package/.next/server/app/releases/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/releases/page.js +2 -2
- package/.next/server/app/releases/page_client-reference-manifest.js +1 -1
- package/.next/server/app/specs/[id]/page.js +2 -2
- package/.next/server/app/specs/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +4 -4
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +2 -2
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/app/builder/{page-e10754eb65a4f784.js → page-e0a24ae820fa2c06.js} +2 -2
- package/.next/static/chunks/app/releases/[id]/page-ea66642a6a557b42.js +1 -0
- package/.next/static/chunks/app/releases/page-fc527101f56b36c5.js +1 -0
- package/.next/static/chunks/app/specs/[id]/page-49293bb634997108.js +1 -0
- package/.next/trace +11 -0
- package/.next/trace-build +1 -1
- package/README.md +220 -134
- package/package.json +1 -1
- package/.next/static/chunks/app/releases/[id]/page-d8069a1802686478.js +0 -1
- package/.next/static/chunks/app/releases/page-26a520d9789e69f5.js +0 -1
- package/.next/static/chunks/app/specs/[id]/page-7065af5d4d103f16.js +0 -1
- /package/.next/static/{8ZUFcYHRSRlY1FYWZ33gH → zmL75rl5Hq4TyiNVaXe8R}/_buildManifest.js +0 -0
- /package/.next/static/{8ZUFcYHRSRlY1FYWZ33gH → zmL75rl5Hq4TyiNVaXe8R}/_ssgManifest.js +0 -0
package/.next/trace-build
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
[{"name":"run-webpack","duration":
|
|
1
|
+
[{"name":"run-webpack","duration":6301956,"timestamp":1343499,"id":17,"parentId":1,"tags":{},"startTime":1768687151856,"traceId":"f1000a6551d797b7"},{"name":"run-typescript","duration":3617044,"timestamp":7758580,"id":1243,"parentId":1,"tags":{},"startTime":1768687158271,"traceId":"f1000a6551d797b7"},{"name":"static-check","duration":468693,"timestamp":11505520,"id":1246,"parentId":1,"tags":{},"startTime":1768687162018,"traceId":"f1000a6551d797b7"},{"name":"collect-build-traces","duration":6955911,"timestamp":12068136,"id":1269,"parentId":1,"tags":{},"startTime":1768687162581,"traceId":"f1000a6551d797b7"},{"name":"static-generation","duration":7114483,"timestamp":12076512,"id":1272,"parentId":1,"tags":{},"startTime":1768687162589,"traceId":"f1000a6551d797b7"},{"name":"telemetry-flush","duration":178,"timestamp":19204480,"id":1281,"parentId":1,"tags":{},"startTime":1768687169717,"traceId":"f1000a6551d797b7"},{"name":"next-build","duration":18323302,"timestamp":881376,"id":1,"tags":{"buildMode":"default","version":"16.1.1","bundler":"webpack","has-custom-webpack-config":"true","use-build-worker":"false"},"startTime":1768687151394,"traceId":"f1000a6551d797b7"}]
|
package/README.md
CHANGED
|
@@ -1,35 +1,78 @@
|
|
|
1
|
-
# GAMP 5
|
|
1
|
+
# Matrix - GAMP 5 Traceability System
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A **spec-as-code** requirements traceability system for regulated environments. Write Gherkin specs, run them as tests, and maintain automatic audit-ready traceability.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- [**User Guide**](./USER_GUIDE.md): How to use the dashboard and CLI.
|
|
7
|
-
- [**Developer Guide**](./DEVELOPER_GUIDE.md): Architecture, setup, and development workflow.
|
|
8
|
-
- [**Philosophy & Approach**](./GAMP_AND_V_MODEL.md): GAMP 5 principles, V-Model, and "Spec-as-Code" reasoning.
|
|
5
|
+
## Quickstart
|
|
9
6
|
|
|
7
|
+
```bash
|
|
8
|
+
bun add @nivora/matrix
|
|
9
|
+
bunx matrix init
|
|
10
|
+
bunx matrix serve
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Dashboard available at: http://localhost:3000
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
---
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
## Core Concepts
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
|----------|--------|----------|---------|
|
|
17
|
-
| **URS** | Database | SQLite Table `urs` | High-level business requirements |
|
|
18
|
-
| **FS** | Gherkin | `specs/fs/*.requirement` | Functional specs + embedded test scenarios |
|
|
19
|
-
| **RISK** | Database | SQLite Table `risks` | Risk assessments linked to FS |
|
|
19
|
+
This system implements **GAMP 5** and **V-Model** compliance by making specifications executable:
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
| Artifact | Storage | Purpose |
|
|
22
|
+
|----------|---------|---------|
|
|
23
|
+
| **URS** | SQLite DB | High-level business requirements |
|
|
24
|
+
| **FS** | Gherkin `.requirement` files | Functional specs + test scenarios |
|
|
25
|
+
| **Risk** | SQLite DB | Risk assessments & mitigations |
|
|
26
|
+
| **Release** | SQLite DB | Version management & test results |
|
|
22
27
|
|
|
23
|
-
|
|
28
|
+
**Key Insight**: The Gherkin Feature file IS the Functional Spec AND the test. No duplication.
|
|
24
29
|
|
|
25
30
|
```gherkin
|
|
26
31
|
@URS-001 @RISK-001
|
|
27
|
-
Feature: FS-001 User Login
|
|
28
|
-
The system shall
|
|
29
|
-
|
|
32
|
+
Feature: FS-001 User Login
|
|
33
|
+
The system shall authenticate users against stored credentials.
|
|
34
|
+
|
|
35
|
+
Scenario: Successful login
|
|
36
|
+
Given I am on the login page
|
|
37
|
+
When I enter valid credentials
|
|
38
|
+
Then I should see my dashboard
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Workflow
|
|
44
|
+
|
|
45
|
+
### 1. Create User Requirements (URS)
|
|
46
|
+
|
|
47
|
+
**Option A: Dashboard UI**
|
|
48
|
+
1. Navigate to http://localhost:3000/specs
|
|
49
|
+
2. Click "New Specification"
|
|
50
|
+
3. Fill in Title, Business Need, Acceptance Criteria
|
|
51
|
+
4. Save
|
|
52
|
+
|
|
53
|
+
**Option B: Stub Generation (Recommended)**
|
|
54
|
+
|
|
55
|
+
Reference URS IDs in your Gherkin files before they exist:
|
|
56
|
+
|
|
57
|
+
```gherkin
|
|
58
|
+
@URS-011
|
|
59
|
+
Feature: FS-009 Password Reset
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Run `matrix sync` and the system creates a placeholder `URS-011` record. Fill in details via the dashboard later.
|
|
63
|
+
|
|
64
|
+
### 2. Write Functional Specs (FS)
|
|
65
|
+
|
|
66
|
+
Create `.requirement` files in `specs/fs/`:
|
|
67
|
+
|
|
68
|
+
```gherkin
|
|
69
|
+
@URS-001 @URS-002 @RISK-005
|
|
70
|
+
Feature: FS-001 User Authentication
|
|
71
|
+
The system shall authenticate users against stored credentials
|
|
72
|
+
and establish a secure session.
|
|
30
73
|
|
|
31
74
|
Requirements:
|
|
32
|
-
- FR-001.1: Display login form with email and password
|
|
75
|
+
- FR-001.1: Display login form with email and password
|
|
33
76
|
- FR-001.2: Validate credentials against stored hash
|
|
34
77
|
- FR-001.3: Rate limit after 5 failed attempts
|
|
35
78
|
|
|
@@ -37,149 +80,192 @@ Feature: FS-001 User Login Authentication
|
|
|
37
80
|
Given I am on the login page
|
|
38
81
|
When I enter valid credentials
|
|
39
82
|
Then I should be redirected to my dashboard
|
|
83
|
+
|
|
84
|
+
Scenario: Failed login locks account after 5 attempts
|
|
85
|
+
Given I have failed login 4 times
|
|
86
|
+
When I enter invalid credentials
|
|
87
|
+
Then I should see "Account locked"
|
|
40
88
|
```
|
|
41
89
|
|
|
42
|
-
**
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
- **Clear traceability**: `@URS-xxx` and `@RISK-xxx` tags create automatic links
|
|
46
|
-
- **Executable specs**: The `.requirement` files can be run by Cucumber
|
|
90
|
+
**Linking Tags:**
|
|
91
|
+
- `@URS-xxx` — Links to User Requirement
|
|
92
|
+
- `@RISK-xxx` — Links to Risk Assessment
|
|
47
93
|
|
|
48
|
-
|
|
94
|
+
### 3. Create Risk Assessments
|
|
49
95
|
|
|
50
|
-
|
|
51
|
-
docs/
|
|
52
|
-
├── specs/
|
|
53
|
-
│ └── fs/ # Functional Specs (Gherkin)
|
|
54
|
-
│ ├── FS-001-login.requirement
|
|
55
|
-
│ ├── FS-002-session.requirement
|
|
56
|
-
│ ├── FS-003-registration.requirement
|
|
57
|
-
│ ├── FS-004-booking.requirement
|
|
58
|
-
│ ├── FS-005-waitlist.requirement
|
|
59
|
-
│ ├── FS-006-schedule.requirement
|
|
60
|
-
│ └── FS-007-instructor.requirement
|
|
61
|
-
└── src/ # Next.js Dashboard
|
|
62
|
-
```
|
|
96
|
+
**Option A: Dashboard UI** — Same flow as URS
|
|
63
97
|
|
|
64
|
-
|
|
98
|
+
**Option B: Stub Generation** — Reference `@RISK-xxx` in Gherkin, run sync, fill in details later
|
|
65
99
|
|
|
66
|
-
###
|
|
67
|
-
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
Feature: FS-001 User Login
|
|
100
|
+
### 4. Sync to Database
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
matrix sync
|
|
71
104
|
```
|
|
72
105
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
106
|
+
**What sync does:**
|
|
107
|
+
1. Parses all `.requirement` files in `specs/fs/`
|
|
108
|
+
2. Updates database with Feature titles, descriptions, and scenarios
|
|
109
|
+
3. Extracts `@URS` and `@RISK` tags
|
|
110
|
+
4. Auto-creates stub records for any referenced IDs that don't exist
|
|
111
|
+
|
|
112
|
+
> **Tip:** Write Gherkin first with new IDs, run sync, then fill in URS/Risk details via the dashboard.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Release Management
|
|
117
|
+
|
|
118
|
+
### 1. Create a Release
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
matrix release create -v 1.0.0 -n "MVP Launch" --notes "Initial release"
|
|
78
122
|
```
|
|
79
123
|
|
|
80
|
-
|
|
81
|
-
- **
|
|
82
|
-
- **
|
|
83
|
-
- **
|
|
124
|
+
Creates a release with:
|
|
125
|
+
- **Version**: Semantic version (e.g., 1.0.0)
|
|
126
|
+
- **Name**: Human-readable name
|
|
127
|
+
- **Status**: Defaults to "planning"
|
|
128
|
+
- **Notes**: Optional release notes
|
|
84
129
|
|
|
85
|
-
|
|
130
|
+
### 2. Tag Features to Release
|
|
86
131
|
|
|
87
132
|
```bash
|
|
88
|
-
|
|
89
|
-
bun install
|
|
90
|
-
bun run dev
|
|
133
|
+
matrix release tag REL-001 --fs FS-001 FS-002 FS-003
|
|
91
134
|
```
|
|
92
135
|
|
|
93
|
-
|
|
136
|
+
### 3. Run Tests
|
|
94
137
|
|
|
95
|
-
|
|
138
|
+
Execute Cucumber tests and export results:
|
|
96
139
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
| `/` | Dashboard with stats, coverage, and traceability summary |
|
|
100
|
-
| `/specs` | Browse URS (YAML), FS (Gherkin), and Risk (YAML) |
|
|
101
|
-
| `/matrix` | Full traceability matrix: URS → FS → Scenarios → Risks |
|
|
102
|
-
| `/builder` | Visual editor for creating new FS .requirement files |
|
|
103
|
-
| `/search` | Search across all artifacts |
|
|
104
|
-
|
|
105
|
-
## Creating New Artifacts
|
|
106
|
-
|
|
107
|
-
### New URS (via Dashboard or manually)
|
|
108
|
-
Create `specs/urs/URS-xxx.yaml`:
|
|
109
|
-
```yaml
|
|
110
|
-
id: URS-004
|
|
111
|
-
type: urs
|
|
112
|
-
title: New Business Requirement
|
|
113
|
-
status: draft
|
|
114
|
-
priority: high
|
|
115
|
-
owner: Product Team
|
|
116
|
-
category: Core
|
|
117
|
-
business_need: |
|
|
118
|
-
Description of the business need...
|
|
119
|
-
intended_use: |
|
|
120
|
-
How the system will be used...
|
|
121
|
-
acceptance_criteria:
|
|
122
|
-
- Criterion 1
|
|
123
|
-
- Criterion 2
|
|
124
|
-
regulatory_refs:
|
|
125
|
-
- GAMP 5
|
|
140
|
+
```bash
|
|
141
|
+
npx cucumber-js specs/fs/**/*.requirement --format json:results.json
|
|
126
142
|
```
|
|
127
143
|
|
|
128
|
-
###
|
|
129
|
-
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
Requirements:
|
|
136
|
-
- FR-xxx.1: First requirement
|
|
137
|
-
- FR-xxx.2: Second requirement
|
|
144
|
+
### 4. Import Test Results
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
matrix release import-results results.json --releaseId REL-001
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Or use the test command:
|
|
138
151
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
When ...
|
|
142
|
-
Then ...
|
|
152
|
+
```bash
|
|
153
|
+
matrix test import results.json -r REL-001
|
|
143
154
|
```
|
|
144
155
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
- FS-001
|
|
156
|
-
impact: high
|
|
157
|
-
probability: medium
|
|
158
|
-
risk_level: high
|
|
159
|
-
risks:
|
|
160
|
-
- id: R-004.1
|
|
161
|
-
description: Risk description
|
|
162
|
-
impact: high
|
|
163
|
-
probability: medium
|
|
164
|
-
mitigations:
|
|
165
|
-
- risk_id: R-004.1
|
|
166
|
-
control: Control measure
|
|
167
|
-
test: How to test
|
|
168
|
-
residual_risk: acceptable
|
|
156
|
+
The import process:
|
|
157
|
+
- Creates a test run record
|
|
158
|
+
- Stores individual scenario results (pass/fail)
|
|
159
|
+
- Warns if any tests failed
|
|
160
|
+
- Updates release status to "testing"
|
|
161
|
+
|
|
162
|
+
### 5. View Test Results
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
matrix test list REL-001
|
|
169
166
|
```
|
|
170
167
|
|
|
171
|
-
|
|
168
|
+
### 6. Handle Test Failures
|
|
169
|
+
|
|
170
|
+
If tests fail, you have two GAMP-compliant options:
|
|
171
|
+
|
|
172
|
+
**Option A: Fix the Code**
|
|
173
|
+
1. Fix the failing functionality
|
|
174
|
+
2. Re-run tests
|
|
175
|
+
3. Import the new results
|
|
176
|
+
|
|
177
|
+
**Option B: Log a Defect/Deviation**
|
|
178
|
+
1. Go to Release Detail page: `http://localhost:3000/releases/REL-001`
|
|
179
|
+
2. Find the **Defects & Deviations** section
|
|
180
|
+
3. Click **Log Defect** for the failing scenario
|
|
181
|
+
4. Provide:
|
|
182
|
+
- **Description**: What failed and why
|
|
183
|
+
- **Justification**: Why it's acceptable (workaround exists, low impact, etc.)
|
|
184
|
+
- **Status**: Open, Investigating, Resolved, or Accepted
|
|
172
185
|
|
|
173
|
-
|
|
186
|
+
> [!IMPORTANT]
|
|
187
|
+
> You cannot mark a release as "Released" if it has failing tests without corresponding Defect records.
|
|
188
|
+
|
|
189
|
+
### 7. Update Release Status
|
|
174
190
|
|
|
175
191
|
```bash
|
|
176
|
-
#
|
|
177
|
-
|
|
192
|
+
# Move to testing phase
|
|
193
|
+
matrix release status REL-001 --status testing
|
|
194
|
+
|
|
195
|
+
# Mark as released (requires all tests pass or defects logged)
|
|
196
|
+
matrix release status REL-001 --status released
|
|
178
197
|
```
|
|
179
198
|
|
|
199
|
+
### 8. List All Releases
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
matrix release list
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## CLI Reference
|
|
208
|
+
|
|
209
|
+
### Core Commands
|
|
210
|
+
|
|
211
|
+
| Command | Description |
|
|
212
|
+
|---------|-------------|
|
|
213
|
+
| `matrix init` | Initialize a new specs directory |
|
|
214
|
+
| `matrix serve` | Start the dashboard server |
|
|
215
|
+
| `matrix sync` | Parse `.requirement` files and update database |
|
|
216
|
+
| `matrix search <query>` | Semantic search across specs |
|
|
217
|
+
|
|
218
|
+
### Release Commands
|
|
219
|
+
|
|
220
|
+
| Command | Description |
|
|
221
|
+
|---------|-------------|
|
|
222
|
+
| `matrix release list` | List all releases |
|
|
223
|
+
| `matrix release create` | Create a new release |
|
|
224
|
+
| `matrix release tag <id>` | Tag FS records to a release |
|
|
225
|
+
| `matrix release status <id>` | Update release status |
|
|
226
|
+
| `matrix release import-results <file>` | Import Cucumber JSON results |
|
|
227
|
+
|
|
228
|
+
### Test Commands
|
|
229
|
+
|
|
230
|
+
| Command | Description |
|
|
231
|
+
|---------|-------------|
|
|
232
|
+
| `matrix test import <file> -r <releaseId>` | Import Cucumber JSON results |
|
|
233
|
+
| `matrix test list <releaseId>` | List test runs for a release |
|
|
234
|
+
|
|
235
|
+
### Common Options
|
|
236
|
+
|
|
237
|
+
| Option | Description |
|
|
238
|
+
|--------|-------------|
|
|
239
|
+
| `-p, --port <port>` | Port for serve (default: 3000) |
|
|
240
|
+
| `-s, --specs <dir>` | Specs directory (default: ./specs) |
|
|
241
|
+
| `-d, --db <path>` | Database path (default: ./matrix.db) |
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## Dashboard Pages
|
|
246
|
+
|
|
247
|
+
| Page | URL | Description |
|
|
248
|
+
|------|-----|-------------|
|
|
249
|
+
| Home | `/` | Stats, coverage, and traceability overview |
|
|
250
|
+
| Specs | `/specs` | Browse and edit URS, FS, and Risks |
|
|
251
|
+
| Matrix | `/matrix` | Full traceability matrix: URS → FS → Scenarios → Risks |
|
|
252
|
+
| Releases | `/releases` | Release management and test results |
|
|
253
|
+
| Builder | `/builder` | Visual editor for creating FS files |
|
|
254
|
+
| Search | `/search` | Search across all artifacts |
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
180
258
|
## GAMP 5 Compliance
|
|
181
259
|
|
|
182
|
-
- **
|
|
183
|
-
- **
|
|
184
|
-
- **
|
|
185
|
-
- **
|
|
260
|
+
- **V-Model Integration**: FS files serve as both specification (FS) and test protocol (OQ)
|
|
261
|
+
- **Risk-Based Testing**: `@RISK-xxx` tags prioritize validation effort
|
|
262
|
+
- **Automatic Traceability**: Tag-based linking generates audit-ready matrices
|
|
263
|
+
- **Defect Management**: Failed tests require formal deviation records before release
|
|
264
|
+
- **21 CFR Part 11 Ready**: Full audit trail of changes and test results
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Additional Documentation
|
|
269
|
+
|
|
270
|
+
- [Developer Guide](./DEVELOPER_GUIDE.md) - Architecture and development setup
|
|
271
|
+
- [GAMP & V-Model Philosophy](./GAMP_AND_V_MODEL.md) - Design rationale
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[41],{4926:(e,t,r)=>{Promise.resolve().then(r.bind(r,6717))},6717:(e,t,r)=>{"use strict";r.d(t,{ReleaseDetailClient:()=>h});var s=r(5155),i=r(2115),a=r(8500),l=r.n(a),n=r(9339);let o=(0,n.createServerReference)("60b2b1ac09aa309cd62336a9a181a22f6a565110e8",n.callServer,void 0,n.findSourceMapURL,"updateReleaseAction"),d=(0,n.createServerReference)("60a507c03894e522051c1ddbaa648c22f3145f6f7b",n.callServer,void 0,n.findSourceMapURL,"tagFSToReleaseAction"),c=(0,n.createServerReference)("600920c1121365a4e4a2b74f81a2832b96fbcadc12",n.callServer,void 0,n.findSourceMapURL,"untagFSFromReleaseAction"),m=(0,n.createServerReference)("4098c7d1c9ece378d5dbdd69bf4aa352b2d12a9669",n.callServer,void 0,n.findSourceMapURL,"createDefectAction");function h({release:e,taggedFS:t,availableFS:r,testRuns:a,defects:n}){let[h,p]=(0,i.useState)(!1),[g,x]=(0,i.useState)(!1),[v,u]=(0,i.useState)([]),[y,j]=(0,i.useState)(null),[f,b]=(0,i.useState)({isOpen:!1}),[S,N]=(0,i.useState)({title:"",description:"",status:"open"}),[C,k]=(0,i.useState)({titleError:!1,descriptionError:!1}),[R,w]=(0,i.useTransition)(),[B,W]=(0,i.useState)({version:e.version,name:e.name,status:e.status,notes:e.notes||""}),_={planning:{bg:"rgba(168, 85, 247, 0.1)",color:"#a855f7"},testing:{bg:"rgba(59, 130, 246, 0.1)",color:"#3b82f6"},released:{bg:"rgba(34, 197, 94, 0.1)",color:"#22c55e"}}[e.status];return(0,s.jsxs)("div",{style:{maxWidth:"1200px",margin:"0 auto",padding:"2rem"},children:[(0,s.jsx)("div",{style:{marginBottom:"1.5rem"},children:(0,s.jsx)(l(),{href:"/releases",style:{color:"var(--text-secondary)",textDecoration:"none"},children:"← Back to Releases"})}),(0,s.jsxs)("header",{style:{marginBottom:"2rem"},children:[(0,s.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:"1rem",marginBottom:"0.5rem"},children:[(0,s.jsxs)("code",{style:{fontSize:"1.5rem",fontWeight:700,color:_.color},children:[" ",e.id," "]}),(0,s.jsxs)("span",{style:{fontSize:"1.25rem",fontWeight:600},children:["v",e.version]}),(0,s.jsx)("span",{className:"badge",style:{background:_.bg,color:_.color,padding:"0.5rem 1rem"},children:e.status}),(0,s.jsx)("button",{onClick:()=>p(!h),className:"btn btn-primary",style:{marginLeft:"auto"},children:h?"Cancel":"✏️ Edit"})]}),(0,s.jsx)("h1",{style:{fontSize:"2rem",fontWeight:700},children:e.name}),(0,s.jsxs)("p",{style:{color:"var(--text-secondary)"},children:["Created ",e.created_at,e.released_at&&` • Released ${e.released_at}`]})]}),h&&(0,s.jsxs)("div",{className:"card",style:{marginBottom:"1.5rem"},children:[(0,s.jsx)("h2",{className:"card-title",children:"Edit Release"}),(0,s.jsxs)("div",{style:{display:"grid",gridTemplateColumns:"1fr 2fr 1fr",gap:"1rem",marginBottom:"1rem"},children:[(0,s.jsxs)("div",{children:[(0,s.jsx)("label",{style:{display:"block",fontWeight:500,marginBottom:"0.5rem"},children:"Version"}),(0,s.jsx)("input",{type:"text",value:B.version,onChange:e=>W({...B,version:e.target.value}),className:"input"})]}),(0,s.jsxs)("div",{children:[(0,s.jsx)("label",{style:{display:"block",fontWeight:500,marginBottom:"0.5rem"},children:"Name"}),(0,s.jsx)("input",{type:"text",value:B.name,onChange:e=>W({...B,name:e.target.value}),className:"input"})]}),(0,s.jsxs)("div",{children:[(0,s.jsx)("label",{style:{display:"block",fontWeight:500,marginBottom:"0.5rem"},children:"Status"}),(0,s.jsxs)("select",{value:B.status,onChange:e=>W({...B,status:e.target.value}),className:"input",children:[(0,s.jsx)("option",{value:"planning",children:"Planning"}),(0,s.jsx)("option",{value:"testing",children:"Testing"}),(0,s.jsx)("option",{value:"released",children:"Released"})]})]})]}),(0,s.jsxs)("div",{style:{marginBottom:"1rem"},children:[(0,s.jsx)("label",{style:{display:"block",fontWeight:500,marginBottom:"0.5rem"},children:"Notes"}),(0,s.jsx)("textarea",{value:B.notes,onChange:e=>W({...B,notes:e.target.value}),rows:3,className:"input",style:{resize:"vertical"}})]}),(0,s.jsx)("button",{onClick:()=>{w(async()=>{await o(e.id,B),p(!1)})},className:"btn btn-primary",disabled:R,children:R?"Saving...":"Save Changes"})]}),e.notes&&!h&&(0,s.jsxs)("div",{className:"card",style:{marginBottom:"1.5rem"},children:[(0,s.jsx)("h2",{className:"card-title",children:"\uD83D\uDCDD Notes"}),(0,s.jsx)("p",{style:{color:"var(--text-secondary)",whiteSpace:"pre-wrap"},children:e.notes})]}),(0,s.jsxs)("div",{className:"card",style:{marginBottom:"1.5rem",borderLeft:"4px solid var(--error)"},children:[(0,s.jsxs)("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"1rem"},children:[(0,s.jsxs)("h2",{className:"card-title",children:["\uD83D\uDEA8 Defects & Deviations (",n.length,")"]}),(0,s.jsx)("button",{className:"btn",onClick:()=>{b({isOpen:!0,testResultId:void 0,fsId:void 0,scenarioName:void 0}),N({title:"",description:"",status:"open"})},children:"+ Log Defect"})]}),0===n.length?(0,s.jsx)("p",{style:{color:"var(--text-secondary)"},children:"No defects logged. Any failed tests must be resolved or logged as a defect."}):(0,s.jsx)("div",{style:{display:"grid",gap:"0.75rem"},children:n.map(e=>(0,s.jsxs)("div",{style:{padding:"1rem",background:"var(--bg-hover)",borderRadius:"8px",borderLeft:"open"===e.status?"3px solid red":"3px solid green"},children:[(0,s.jsxs)("div",{style:{display:"flex",justifyContent:"space-between",marginBottom:"0.5rem"},children:[(0,s.jsxs)("div",{style:{fontWeight:600},children:[e.id,": ",e.title]}),(0,s.jsx)("div",{className:"badge",style:{background:"open"===e.status?"rgba(239, 68, 68, 0.1)":"rgba(34, 197, 94, 0.1)",color:"open"===e.status?"var(--error)":"var(--success)"},children:e.status.toUpperCase()})]}),(0,s.jsx)("div",{style:{fontSize:"0.875rem",color:"var(--text-secondary)",whiteSpace:"pre-wrap"},children:e.description}),e.test_result_id&&(0,s.jsxs)("div",{style:{marginTop:"0.5rem",fontSize:"0.75rem",color:"var(--warning)"},children:["Linked to failed test result #",e.test_result_id]})]},e.id))})]}),(0,s.jsxs)("div",{className:"card",style:{marginBottom:"1.5rem"},children:[(0,s.jsxs)("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"1rem"},children:[(0,s.jsxs)("h2",{className:"card-title",style:{margin:0},children:["⚙️ Features (",t.length,")"]}),(0,s.jsx)("button",{onClick:()=>x(!0),className:"btn",disabled:0===r.length,children:"+ Add Features"})]}),g&&(0,s.jsxs)("div",{style:{marginBottom:"1rem",padding:"1rem",background:"var(--bg-hover)",borderRadius:"8px"},children:[(0,s.jsx)("div",{style:{marginBottom:"0.5rem",fontWeight:500},children:"Select features to add:"}),(0,s.jsx)("div",{style:{display:"flex",flexWrap:"wrap",gap:"0.5rem",marginBottom:"1rem"},children:r.map(e=>(0,s.jsxs)("label",{style:{display:"flex",alignItems:"center",gap:"0.5rem",cursor:"pointer"},children:[(0,s.jsx)("input",{type:"checkbox",checked:v.includes(e.id),onChange:t=>{t.target.checked?u([...v,e.id]):u(v.filter(t=>t!==e.id))}}),(0,s.jsx)("code",{style:{color:"var(--warning)"},children:e.id}),(0,s.jsx)("span",{children:e.title})]},e.id))}),(0,s.jsxs)("div",{style:{display:"flex",gap:"0.5rem"},children:[(0,s.jsx)("button",{onClick:()=>{x(!1),u([])},className:"btn",children:"Cancel"}),(0,s.jsx)("button",{onClick:()=>{0!==v.length&&w(async()=>{await d(e.id,v),x(!1),u([])})},className:"btn btn-primary",disabled:R||0===v.length,children:R?"Adding...":`Add ${v.length} Feature${1!==v.length?"s":""}`})]})]}),0===t.length?(0,s.jsx)("p",{style:{color:"var(--text-secondary)"},children:"No features tagged yet. Add features to track them in this release."}):(0,s.jsx)("div",{style:{display:"grid",gap:"0.5rem"},children:t.map(t=>(0,s.jsxs)("div",{style:{display:"flex",alignItems:"center",padding:"0.75rem 1rem",background:"var(--bg-hover)",borderRadius:"8px"},children:[(0,s.jsxs)(l(),{href:`/specs/${t.id}`,style:{flex:1,textDecoration:"none"},children:[(0,s.jsx)("code",{style:{fontWeight:600,color:"var(--warning)",marginRight:"0.75rem"},children:t.id}),(0,s.jsx)("span",{style:{color:"var(--text-primary)"},children:t.title}),(0,s.jsxs)("span",{style:{marginLeft:"0.75rem",color:"var(--text-secondary)",fontSize:"0.875rem"},children:[t.scenario_count," scenarios"]})]}),(0,s.jsx)("button",{onClick:()=>{var r;return r=t.id,void w(async()=>{await c(e.id,r)})},className:"btn",style:{padding:"0.25rem 0.5rem",fontSize:"0.75rem"},disabled:R,children:"\xd7"})]},t.id))})]}),(0,s.jsxs)("div",{className:"card",children:[(0,s.jsxs)("h2",{className:"card-title",children:["\uD83E\uDDEA Test Runs (",a.length,")"]}),0===a.length?(0,s.jsxs)("p",{style:{color:"var(--text-secondary)"},children:["No test runs yet. Import Cucumber results: ",(0,s.jsxs)("code",{children:["machine release import-results results.json -r ",e.id]})]}):(0,s.jsx)("div",{style:{display:"grid",gap:"0.75rem"},children:a.map(e=>{let t=e.total>0?e.passed/e.total*100:0,r=y===e.id;return(0,s.jsxs)("div",{style:{padding:"1rem",background:"var(--bg-hover)",borderRadius:"8px"},children:[(0,s.jsxs)("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",cursor:"pointer"},onClick:()=>j(r?null:e.id),children:[(0,s.jsxs)("div",{children:[(0,s.jsxs)("div",{style:{fontWeight:600,marginBottom:"0.25rem"},children:[e.failed>0?"❌":"✅"," Run #",e.id," ",r?"\uD83D\uDD3D":"▶"]}),(0,s.jsxs)("div",{style:{fontSize:"0.875rem",color:"var(--text-secondary)"},children:[e.run_date," • ",e.source]})]}),(0,s.jsxs)("div",{style:{display:"flex",gap:"1rem",textAlign:"center"},children:[(0,s.jsxs)("div",{children:[(0,s.jsx)("div",{style:{fontWeight:700,color:"var(--success)"},children:e.passed}),(0,s.jsx)("div",{style:{fontSize:"0.75rem",color:"var(--text-secondary)"},children:"Passed"})]}),(0,s.jsxs)("div",{children:[(0,s.jsx)("div",{style:{fontWeight:700,color:"var(--error)"},children:e.failed}),(0,s.jsx)("div",{style:{fontSize:"0.75rem",color:"var(--text-secondary)"},children:"Failed"})]}),(0,s.jsxs)("div",{children:[(0,s.jsxs)("div",{style:{fontWeight:700,color:100===t?"var(--success)":t>=80?"var(--warning)":"var(--error)"},children:[t.toFixed(0),"%"]}),(0,s.jsx)("div",{style:{fontSize:"0.75rem",color:"var(--text-secondary)"},children:"Pass Rate"})]})]})]}),r&&(0,s.jsx)("div",{style:{marginTop:"1rem",paddingTop:"1rem",borderTop:"1px solid var(--border)"},children:(0,s.jsx)("p",{style:{fontStyle:"italic",color:"var(--text-secondary)"},children:"Detailed results view would go here. For now, check the console logs or database for failure details."})})]},e.id)})})]}),f.isOpen&&(0,s.jsx)("div",{style:{position:"fixed",top:0,left:0,right:0,bottom:0,background:"rgba(0,0,0,0.5)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:100},children:(0,s.jsxs)("div",{className:"card",style:{width:"500px",maxWidth:"90%"},children:[(0,s.jsx)("h2",{className:"card-title",children:"Log Defect / Deviation"}),(0,s.jsxs)("div",{style:{marginBottom:"1rem"},children:[(0,s.jsxs)("label",{style:{display:"block",marginBottom:"0.5rem"},children:["Title ",(0,s.jsx)("span",{style:{color:"var(--error)"},children:"*"})]}),(0,s.jsx)("input",{className:"input",value:S.title,onChange:e=>{N({...S,title:e.target.value}),e.target.value&&k(e=>({...e,titleError:!1}))},placeholder:"Defect summary",style:C.titleError?{borderColor:"var(--error)",boxShadow:"0 0 0 2px rgba(239, 68, 68, 0.2)"}:{}}),C.titleError&&(0,s.jsx)("div",{style:{color:"var(--error)",fontSize:"0.75rem",marginTop:"0.25rem"},children:"Title is required"})]}),(0,s.jsxs)("div",{style:{marginBottom:"1rem"},children:[(0,s.jsxs)("label",{style:{display:"block",marginBottom:"0.5rem"},children:["Description & Root Cause ",(0,s.jsx)("span",{style:{color:"var(--error)"},children:"*"})]}),(0,s.jsx)("textarea",{className:"input",rows:5,value:S.description,onChange:e=>{N({...S,description:e.target.value}),e.target.value&&k(e=>({...e,descriptionError:!1}))},placeholder:"Describe the failure, root cause, and why it is acceptable (if deviating) or mitigation plan.",style:C.descriptionError?{borderColor:"var(--error)",boxShadow:"0 0 0 2px rgba(239, 68, 68, 0.2)"}:{}}),C.descriptionError&&(0,s.jsx)("div",{style:{color:"var(--error)",fontSize:"0.75rem",marginTop:"0.25rem"},children:"Description is required"})]}),(0,s.jsxs)("div",{style:{marginBottom:"1rem"},children:[(0,s.jsx)("label",{style:{display:"block",marginBottom:"0.5rem"},children:"Status"}),(0,s.jsxs)("select",{className:"input",value:S.status,onChange:e=>N({...S,status:e.target.value}),children:[(0,s.jsx)("option",{value:"open",children:"Open (Needs Fix)"}),(0,s.jsx)("option",{value:"resolved",children:"Resolved (Fixed)"}),(0,s.jsx)("option",{value:"accepted",children:"Accepted (Permanent Deviation)"})]})]}),(0,s.jsxs)("div",{style:{display:"flex",gap:"0.5rem",justifyContent:"flex-end"},children:[(0,s.jsx)("button",{className:"btn",onClick:()=>{b({isOpen:!1}),k({titleError:!1,descriptionError:!1})},children:"Cancel"}),(0,s.jsx)("button",{className:"btn btn-primary",onClick:()=>{let t=!S.title.trim(),r=!S.description.trim();t||r?k({titleError:t,descriptionError:r}):w(async()=>{try{await m({releaseId:e.id,testResultId:f.testResultId,title:S.title,description:S.description,status:S.status}),b({isOpen:!1}),N({title:"",description:"",status:"open"})}catch(e){console.error("Failed to create defect:",e),alert("Failed to create defect. Check console for details.")}})},disabled:R,children:R?"Logging...":"Log Defect"})]})]})})]})}},9339:(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});var s={callServer:function(){return a.callServer},createServerReference:function(){return n.createServerReference},findSourceMapURL:function(){return l.findSourceMapURL}};for(var i in s)Object.defineProperty(t,i,{enumerable:!0,get:s[i]});let a=r(7304),l=r(4060),n=r(7197)}},e=>{e.O(0,[500,441,794,358],()=>e(e.s=4926)),_N_E=e.O()}]);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[549],{4815:(e,t,r)=>{"use strict";r.d(t,{ReleasesClient:()=>c});var s=r(5155),a=r(2115),l=r(8500),n=r.n(l),i=r(9339);let o=(0,i.createServerReference)("40d511dc3a76cac7d4c145452256536f04babc742d",i.callServer,void 0,i.findSourceMapURL,"createReleaseAction");function c({releases:e}){let[t,r]=(0,a.useState)(!1),[l,n]=(0,a.useState)(""),[i,c]=(0,a.useState)(""),[m,x]=(0,a.useState)(""),[h,g]=(0,a.useTransition)();return(0,s.jsxs)("div",{style:{maxWidth:"1200px",margin:"0 auto",padding:"2rem"},children:[(0,s.jsx)("header",{style:{marginBottom:"2rem"},children:(0,s.jsxs)("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center"},children:[(0,s.jsxs)("div",{children:[(0,s.jsx)("h1",{style:{fontSize:"2rem",fontWeight:700,marginBottom:"0.5rem"},children:"\uD83D\uDCE6 Releases"}),(0,s.jsx)("p",{style:{color:"var(--text-secondary)"},children:"Manage releases, track test execution, and compare changes"})]}),(0,s.jsx)("button",{onClick:()=>r(!0),className:"btn btn-primary",children:"+ New Release"})]})}),t&&(0,s.jsxs)("div",{className:"card",style:{marginBottom:"1.5rem"},children:[(0,s.jsx)("h2",{className:"card-title",children:"Create New Release"}),(0,s.jsxs)("div",{style:{display:"grid",gridTemplateColumns:"1fr 2fr",gap:"1rem",marginBottom:"1rem"},children:[(0,s.jsxs)("div",{children:[(0,s.jsx)("label",{style:{display:"block",fontWeight:500,marginBottom:"0.5rem"},children:"Version"}),(0,s.jsx)("input",{type:"text",value:l,onChange:e=>n(e.target.value),placeholder:"1.0.0",className:"input"})]}),(0,s.jsxs)("div",{children:[(0,s.jsx)("label",{style:{display:"block",fontWeight:500,marginBottom:"0.5rem"},children:"Name"}),(0,s.jsx)("input",{type:"text",value:i,onChange:e=>c(e.target.value),placeholder:"Initial Release",className:"input"})]})]}),(0,s.jsxs)("div",{style:{marginBottom:"1rem"},children:[(0,s.jsx)("label",{style:{display:"block",fontWeight:500,marginBottom:"0.5rem"},children:"Notes (optional)"}),(0,s.jsx)("textarea",{value:m,onChange:e=>x(e.target.value),placeholder:"Release notes...",rows:3,className:"input",style:{resize:"vertical"}})]}),(0,s.jsxs)("div",{style:{display:"flex",gap:"0.5rem"},children:[(0,s.jsx)("button",{onClick:()=>r(!1),className:"btn",disabled:h,children:"Cancel"}),(0,s.jsx)("button",{onClick:()=>{g(async()=>{await o({version:l,name:i,notes:m||void 0}),r(!1),n(""),c(""),x("")})},className:"btn btn-primary",disabled:h||!l||!i,children:h?"Creating...":"Create Release"})]})]}),0===e.length?(0,s.jsxs)("div",{className:"card",style:{textAlign:"center",padding:"3rem"},children:[(0,s.jsx)("p",{style:{fontSize:"3rem",marginBottom:"1rem"},children:"\uD83D\uDCE6"}),(0,s.jsx)("h2",{style:{marginBottom:"0.5rem"},children:"No Releases Yet"}),(0,s.jsx)("p",{style:{color:"var(--text-secondary)",marginBottom:"1rem"},children:"Create your first release to start tracking features and test results."}),(0,s.jsx)("button",{onClick:()=>r(!0),className:"btn btn-primary",children:"Create First Release"})]}):(0,s.jsx)("div",{style:{display:"grid",gap:"1rem"},children:e.map(e=>(0,s.jsx)(d,{release:e},e.id))})]})}function d({release:e}){let t={planning:{bg:"rgba(168, 85, 247, 0.1)",color:"#a855f7"},testing:{bg:"rgba(59, 130, 246, 0.1)",color:"#3b82f6"},released:{bg:"rgba(34, 197, 94, 0.1)",color:"#22c55e"}}[e.status];return(0,s.jsx)(n(),{href:`/releases/${e.id}`,style:{textDecoration:"none"},children:(0,s.jsx)("div",{className:"card",style:{borderLeft:`4px solid ${t.color}`,transition:"transform 0.15s, box-shadow 0.15s",cursor:"pointer"},children:(0,s.jsxs)("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"flex-start"},children:[(0,s.jsxs)("div",{style:{flex:1},children:[(0,s.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:"0.75rem",marginBottom:"0.5rem"},children:[(0,s.jsx)("code",{style:{fontSize:"1.25rem",fontWeight:700,color:t.color},children:e.id}),(0,s.jsxs)("span",{style:{fontSize:"1rem",fontWeight:600,color:"var(--text-primary)"},children:["v",e.version]}),(0,s.jsx)("span",{className:"badge",style:{background:t.bg,color:t.color},children:e.status})]}),(0,s.jsx)("h3",{style:{fontSize:"1.125rem",fontWeight:600,marginBottom:"0.5rem",color:"var(--text-primary)"},children:e.name}),(0,s.jsxs)("p",{style:{fontSize:"0.875rem",color:"var(--text-secondary)"},children:["Created ",e.created_at,e.released_at&&` • Released ${e.released_at}`]})]}),(0,s.jsxs)("div",{style:{display:"flex",gap:"1.5rem",textAlign:"center"},children:[(0,s.jsxs)("div",{children:[(0,s.jsx)("div",{style:{fontSize:"1.5rem",fontWeight:700,color:"var(--warning)"},children:e.fs_count}),(0,s.jsx)("div",{style:{fontSize:"0.75rem",color:"var(--text-secondary)"},children:"Features"})]}),(0,s.jsxs)("div",{children:[(0,s.jsx)("div",{style:{fontSize:"1.5rem",fontWeight:700,color:"var(--accent)"},children:e.test_runs}),(0,s.jsx)("div",{style:{fontSize:"0.75rem",color:"var(--text-secondary)"},children:"Test Runs"})]}),null!==e.latest_pass_rate&&(0,s.jsxs)("div",{children:[(0,s.jsxs)("div",{style:{fontSize:"1.5rem",fontWeight:700,color:100===e.latest_pass_rate?"var(--success)":e.latest_pass_rate>=80?"var(--warning)":"var(--error)"},children:[e.latest_pass_rate.toFixed(0),"%"]}),(0,s.jsx)("div",{style:{fontSize:"0.75rem",color:"var(--text-secondary)"},children:"Pass Rate"})]})]})]})})})}},5411:(e,t,r)=>{Promise.resolve().then(r.bind(r,4815))},9339:(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});var s={callServer:function(){return l.callServer},createServerReference:function(){return i.createServerReference},findSourceMapURL:function(){return n.findSourceMapURL}};for(var a in s)Object.defineProperty(t,a,{enumerable:!0,get:s[a]});let l=r(7304),n=r(4060),i=r(7197)}},e=>{e.O(0,[500,441,794,358],()=>e(e.s=5411)),_N_E=e.O()}]);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[385],{275:(e,t,a)=>{"use strict";a.d(t,{URSDetailClient:()=>d});var r=a(5155),i=a(2115),s=a(8500),l=a.n(s),n=a(9339);let c=(0,n.createServerReference)("603c9bda0fbb0e0ca172cad506bef77f133f0f1640",n.callServer,void 0,n.findSourceMapURL,"updateURSAction");function d({urs:e,linkedFS:t,linkedRisks:a}){let[s,n]=(0,i.useState)(!1),[d,p]=(0,i.useTransition)(),[m,h]=(0,i.useState)({title:e.title,status:e.status,priority:e.priority,owner:e.owner,category:e.category,business_need:e.business_need,intended_use:e.intended_use,acceptance_criteria:e.acceptance_criteria}),u=e.title.includes("(Undefined)"),g=({value:e,onChange:t,multiline:a,placeholder:i})=>s?a?(0,r.jsx)("textarea",{value:e,onChange:e=>t(e.target.value),rows:4,className:"input",style:{width:"100%",resize:"vertical"}}):(0,r.jsx)("input",{type:"text",value:e,onChange:e=>t(e.target.value),className:"input",style:{width:"100%"}}):(0,r.jsx)("span",{style:{whiteSpace:"pre-wrap",color:"var(--text-secondary)",fontStyle:e?"normal":"italic"},children:e||i||"Not defined"}),x=({value:e,onChange:t,options:a})=>s?(0,r.jsx)("select",{value:e,onChange:e=>t(e.target.value),className:"input",children:a.map(e=>(0,r.jsx)("option",{value:e.value,children:e.label},e.value))}):(0,r.jsx)("span",{style:{textTransform:"capitalize"},children:e});return(0,r.jsxs)("div",{children:[(0,r.jsxs)("header",{className:"page-header",children:[(0,r.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:"1rem",marginBottom:"0.5rem",flexWrap:"wrap"},children:[(0,r.jsx)("code",{style:{fontSize:"1.5rem",fontWeight:700,color:"var(--success)",background:"rgba(16, 185, 129, 0.1)",padding:"0.5rem 1rem",borderRadius:"8px"},children:e.id}),s?(0,r.jsx)(x,{value:m.status,onChange:e=>h({...m,status:e}),options:[{value:"draft",label:"Draft"},{value:"review",label:"Review"},{value:"approved",label:"Approved"}]}):(0,r.jsx)("span",{className:`badge ${"approved"===e.status?"badge-success":"badge-warning"}`,children:m.status}),s?(0,r.jsx)(x,{value:m.priority,onChange:e=>h({...m,priority:e}),options:[{value:"critical",label:"Critical"},{value:"high",label:"High"},{value:"medium",label:"Medium"},{value:"low",label:"Low"}]}):(0,r.jsx)("span",{className:"badge",style:{background:"var(--bg-hover)"},children:m.priority}),u&&!s&&(0,r.jsx)("span",{className:"badge",style:{background:"rgba(239, 68, 68, 0.2)",color:"var(--error)"},children:"Needs Definition"}),(0,r.jsx)("div",{style:{marginLeft:"auto",display:"flex",gap:"0.5rem"},children:s?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("button",{onClick:()=>{h({title:e.title,status:e.status,priority:e.priority,owner:e.owner,category:e.category,business_need:e.business_need,intended_use:e.intended_use,acceptance_criteria:e.acceptance_criteria}),n(!1)},className:"btn",disabled:d,children:"Cancel"}),(0,r.jsx)("button",{onClick:()=>{p(async()=>{await c(e.id,m),n(!1)})},className:"btn btn-primary",disabled:d,children:d?"Saving...":"\uD83D\uDCBE Save"})]}):(0,r.jsx)("button",{onClick:()=>n(!0),className:"btn btn-primary",children:"✏️ Edit"})})]}),s?(0,r.jsx)("input",{type:"text",value:m.title,onChange:e=>h({...m,title:e.target.value}),className:"input",style:{fontSize:"1.5rem",fontWeight:700,width:"100%",marginBottom:"0.5rem"}}):(0,r.jsx)("h1",{className:"page-title",children:m.title}),(0,r.jsxs)("p",{className:"page-subtitle",children:["User Requirement Specification • Owner: ",s?(0,r.jsx)("input",{type:"text",value:m.owner,onChange:e=>h({...m,owner:e.target.value}),className:"input",style:{width:"200px",display:"inline-block"}}):m.owner]})]}),u&&!s&&(0,r.jsx)("div",{className:"card",style:{marginBottom:"1.5rem",background:"rgba(239, 68, 68, 0.1)",borderLeft:"4px solid var(--error)"},children:(0,r.jsxs)("p",{style:{margin:0,color:"var(--error)"},children:["⚠️ This URS was auto-created from FS references. Click ",(0,r.jsx)("strong",{children:"Edit"})," to define its details."]})}),(0,r.jsxs)("div",{className:"card",style:{marginBottom:"1.5rem"},children:[(0,r.jsx)("h2",{className:"card-title",children:"\uD83D\uDD17 Traceability"}),(0,r.jsxs)("div",{style:{display:"flex",gap:"2rem",flexWrap:"wrap"},children:[(0,r.jsx)(o,{label:"Functional Specs",count:t.length,color:"var(--warning)"}),(0,r.jsx)(o,{label:"Test Scenarios",count:t.reduce((e,t)=>e+t.scenarios.length,0),color:"var(--accent)"}),(0,r.jsx)(o,{label:"Risk Assessments",count:a.length,color:"#f97316"})]})]}),(0,r.jsxs)("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"1.5rem"},children:[(0,r.jsxs)("div",{className:"card",children:[(0,r.jsx)("h2",{className:"card-title",children:"\uD83D\uDCCB Business Need"}),(0,r.jsx)("div",{style:{lineHeight:1.7},children:(0,r.jsx)(g,{value:m.business_need,onChange:e=>h({...m,business_need:e}),multiline:!0,placeholder:"Not defined"})})]}),(0,r.jsxs)("div",{className:"card",children:[(0,r.jsx)("h2",{className:"card-title",children:"\uD83C\uDFAF Intended Use"}),(0,r.jsx)("div",{style:{lineHeight:1.7},children:(0,r.jsx)(g,{value:m.intended_use,onChange:e=>h({...m,intended_use:e}),multiline:!0,placeholder:"Not defined"})})]})]}),(0,r.jsxs)("div",{className:"card",style:{marginTop:"1.5rem"},children:[(0,r.jsxs)("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"1rem"},children:[(0,r.jsx)("h2",{className:"card-title",style:{margin:0},children:"✅ Acceptance Criteria"}),s&&(0,r.jsx)("button",{onClick:()=>h({...m,acceptance_criteria:[...m.acceptance_criteria,""]}),className:"btn",style:{padding:"0.25rem 0.75rem"},children:"+ Add"})]}),0===m.acceptance_criteria.length?(0,r.jsx)("p",{style:{color:"var(--text-secondary)",fontStyle:"italic"},children:"No acceptance criteria defined"}):s?(0,r.jsx)("div",{style:{display:"grid",gap:"0.5rem"},children:m.acceptance_criteria.map((e,t)=>(0,r.jsxs)("div",{style:{display:"flex",gap:"0.5rem"},children:[(0,r.jsx)("input",{type:"text",value:e,onChange:e=>{let a=[...m.acceptance_criteria];a[t]=e.target.value,h({...m,acceptance_criteria:a})},className:"input",style:{flex:1},placeholder:`Criterion ${t+1}`}),(0,r.jsx)("button",{onClick:()=>h({...m,acceptance_criteria:m.acceptance_criteria.filter((e,a)=>a!==t)}),className:"btn",style:{padding:"0.5rem"},children:"\xd7"})]},t))}):(0,r.jsx)("ul",{style:{margin:0,paddingLeft:"1.5rem"},children:m.acceptance_criteria.map((e,t)=>(0,r.jsx)("li",{style:{marginBottom:"0.5rem",color:"var(--text-secondary)"},children:e},t))})]}),(0,r.jsxs)("div",{className:"card",style:{marginTop:"1.5rem"},children:[(0,r.jsx)("h2",{className:"card-title",children:"⚙️ Linked Functional Specifications"}),0===t.length?(0,r.jsx)("p",{style:{color:"var(--text-secondary)"},children:"No FS linked yet"}):(0,r.jsx)("div",{style:{display:"grid",gap:"1rem"},children:t.map(e=>(0,r.jsx)(l(),{href:`/specs/${e.id}`,style:{textDecoration:"none"},children:(0,r.jsx)("div",{style:{padding:"1rem",background:"var(--bg-hover)",borderRadius:"8px",borderLeft:"4px solid var(--warning)"},children:(0,r.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:"0.75rem"},children:[(0,r.jsx)("code",{style:{fontWeight:600,color:"var(--warning)"},children:e.id}),(0,r.jsx)("span",{style:{color:"var(--text-primary)"},children:e.title}),(0,r.jsxs)("span",{className:"badge badge-success",style:{marginLeft:"auto"},children:[e.scenario_count," tests"]})]})})},e.id))})]})]})}function o({label:e,count:t,color:a}){return(0,r.jsxs)("div",{children:[(0,r.jsx)("div",{style:{fontSize:"0.75rem",color:"var(--text-secondary)",marginBottom:"0.25rem"},children:e}),(0,r.jsx)("div",{style:{fontSize:"1.5rem",fontWeight:700,color:a},children:t})]})}},6164:(e,t,a)=>{Promise.resolve().then(a.t.bind(a,8500,23)),Promise.resolve().then(a.bind(a,8220)),Promise.resolve().then(a.bind(a,8169)),Promise.resolve().then(a.bind(a,275))},8169:(e,t,a)=>{"use strict";a.d(t,{ScenarioList:()=>l});var r=a(5155),i=a(2115);function s({scenario:e,isHighlighted:t}){return(0,r.jsxs)("div",{style:{padding:"1rem",background:t?"rgba(96, 165, 250, 0.1)":"var(--bg-hover)",borderRadius:"8px",border:t?"2px solid var(--accent)":"1px solid var(--border)"},children:[(0,r.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:"0.75rem",marginBottom:"0.75rem"},children:[(0,r.jsx)("span",{style:{color:"var(--accent)"},children:"\uD83E\uDDEA"}),(0,r.jsx)("span",{style:{fontWeight:600},children:e.name}),e.tags.length>0&&(0,r.jsx)("span",{style:{marginLeft:"auto",fontSize:"0.75rem",color:"var(--text-secondary)"},children:e.tags.join(" ")})]}),(0,r.jsx)("div",{style:{fontFamily:"monospace",fontSize:"0.8125rem",lineHeight:1.6},children:e.steps.map((e,t)=>{var a;return(0,r.jsx)("div",{style:{color:(a=e).startsWith("Given")?"#a78bfa":a.startsWith("When")?"#60a5fa":a.startsWith("Then")?"#34d399":"var(--text-secondary)"},children:e},t)})})]})}function l({scenarios:e,highlightScenario:t}){let a=(0,i.useRef)(null);return(0,i.useEffect)(()=>{t&&a.current&&setTimeout(()=>{a.current?.scrollIntoView({behavior:"smooth",block:"center"})},100)},[t]),(0,r.jsx)("div",{style:{display:"grid",gap:"0.75rem"},children:e.map((e,i)=>{let l=t===e.name;return(0,r.jsx)("div",{ref:l?a:void 0,children:(0,r.jsx)(s,{scenario:e,isHighlighted:l})},i)})})}a(8500)},8220:(e,t,a)=>{"use strict";a.d(t,{RiskDetailClient:()=>d});var r=a(5155),i=a(2115),s=a(8500),l=a.n(s),n=a(9339);let c=(0,n.createServerReference)("6019bc063222ae2970a4725211376e4841d01aea8b",n.callServer,void 0,n.findSourceMapURL,"updateRiskAction");function d({risk:e,linkedFS:t}){let[a,s]=(0,i.useState)(!1),[n,d]=(0,i.useTransition)(),[m,h]=(0,i.useState)({title:e.title,status:e.status,category:e.category,impact:e.impact,probability:e.probability,risk_level:e.risk_level,residual_risk:e.residual_risk}),u=e.title.includes("(Undefined)");return(0,r.jsxs)("div",{children:[(0,r.jsxs)("header",{className:"page-header",children:[(0,r.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:"1rem",marginBottom:"0.5rem",flexWrap:"wrap"},children:[(0,r.jsx)("code",{style:{fontSize:"1.5rem",fontWeight:700,color:"#f97316",background:"rgba(249, 115, 22, 0.1)",padding:"0.5rem 1rem",borderRadius:"8px"},children:e.id}),a?(0,r.jsx)(({value:e,onChange:t,options:i})=>a?(0,r.jsx)("select",{value:e,onChange:e=>t(e.target.value),className:"input",children:i.map(e=>(0,r.jsx)("option",{value:e.value,children:e.label},e.value))}):(0,r.jsx)("span",{style:{textTransform:"capitalize"},children:e}),{value:m.status,onChange:e=>h({...m,status:e}),options:[{value:"draft",label:"Draft"},{value:"review",label:"Review"},{value:"approved",label:"Approved"}]}):(0,r.jsx)("span",{className:`badge ${"approved"===e.status?"badge-success":"badge-warning"}`,children:m.status}),(0,r.jsx)(p,{level:m.risk_level}),u&&!a&&(0,r.jsx)("span",{className:"badge",style:{background:"rgba(239, 68, 68, 0.2)",color:"var(--error)"},children:"Needs Definition"}),(0,r.jsx)("div",{style:{marginLeft:"auto",display:"flex",gap:"0.5rem"},children:a?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("button",{onClick:()=>{h({title:e.title,status:e.status,category:e.category,impact:e.impact,probability:e.probability,risk_level:e.risk_level,residual_risk:e.residual_risk}),s(!1)},className:"btn",disabled:n,children:"Cancel"}),(0,r.jsx)("button",{onClick:()=>{d(async()=>{await c(e.id,m),s(!1)})},className:"btn btn-primary",disabled:n,children:n?"Saving...":"\uD83D\uDCBE Save"})]}):(0,r.jsx)("button",{onClick:()=>s(!0),className:"btn btn-primary",children:"✏️ Edit"})})]}),a?(0,r.jsx)("input",{type:"text",value:m.title,onChange:e=>h({...m,title:e.target.value}),className:"input",style:{fontSize:"1.5rem",fontWeight:700,width:"100%",marginBottom:"0.5rem"}}):(0,r.jsx)("h1",{className:"page-title",children:m.title}),(0,r.jsxs)("p",{className:"page-subtitle",children:["Risk Assessment • Category: ",a?(0,r.jsx)("input",{type:"text",value:m.category,onChange:e=>h({...m,category:e.target.value}),className:"input",style:{width:"200px",display:"inline-block"}}):m.category," • GAMP Category ",e.gamp_category]})]}),u&&!a&&(0,r.jsx)("div",{className:"card",style:{marginBottom:"1.5rem",background:"rgba(239, 68, 68, 0.1)",borderLeft:"4px solid var(--error)"},children:(0,r.jsxs)("p",{style:{margin:0,color:"var(--error)"},children:["⚠️ This Risk was auto-created from FS references. Click ",(0,r.jsx)("strong",{children:"Edit"})," to define its details."]})}),(0,r.jsx)("div",{className:"card",style:{marginBottom:"1.5rem"},children:(0,r.jsxs)("div",{style:{display:"grid",gridTemplateColumns:"repeat(4, 1fr)",gap:"1rem"},children:[(0,r.jsx)(o,{label:"Impact",value:m.impact,isEditing:a,onChange:e=>h({...m,impact:e}),options:["low","medium","high","critical"]}),(0,r.jsx)(o,{label:"Probability",value:m.probability,isEditing:a,onChange:e=>h({...m,probability:e}),options:["low","medium","high"]}),(0,r.jsx)(o,{label:"Risk Level",value:m.risk_level,isEditing:a,onChange:e=>h({...m,risk_level:e}),options:["low","medium","high","critical"]}),(0,r.jsx)(o,{label:"Residual Risk",value:m.residual_risk,isEditing:a,onChange:e=>h({...m,residual_risk:e}),options:["acceptable","unacceptable","pending"]})]})}),(0,r.jsxs)("div",{className:"card",style:{marginBottom:"1.5rem"},children:[(0,r.jsx)("h2",{className:"card-title",children:"⚙️ Linked Functional Specifications"}),(0,r.jsx)("div",{style:{display:"flex",gap:"0.5rem",flexWrap:"wrap"},children:t.map(e=>(0,r.jsx)(l(),{href:`/specs/${e.id}`,children:(0,r.jsxs)("span",{className:"badge",style:{background:"rgba(245, 158, 11, 0.15)",color:"var(--warning)",padding:"0.5rem 1rem"},children:[e.id," - ",e.title]})},e.id))})]}),(0,r.jsxs)("div",{className:"card",style:{marginBottom:"1.5rem"},children:[(0,r.jsx)("h2",{className:"card-title",children:"\uD83D\uDD34 Identified Risks"}),0===e.risks.length?(0,r.jsx)("p",{style:{color:"var(--text-secondary)",fontStyle:"italic"},children:"No risks defined yet"}):(0,r.jsx)("div",{style:{display:"grid",gap:"0.5rem"},children:e.risks.map((e,t)=>(0,r.jsxs)("div",{style:{padding:"0.75rem 1rem",background:"var(--bg-hover)",borderRadius:"6px",display:"flex",alignItems:"center",gap:"1rem"},children:[(0,r.jsx)("code",{style:{fontWeight:600,color:"#f97316"},children:e.id}),(0,r.jsx)("span",{style:{flex:1,color:"var(--text-secondary)"},children:e.description}),(0,r.jsx)(p,{level:e.impact,small:!0})]},t))})]}),(0,r.jsxs)("div",{className:"card",children:[(0,r.jsx)("h2",{className:"card-title",children:"\uD83D\uDEE1️ Mitigations"}),0===e.mitigations.length?(0,r.jsx)("p",{style:{color:"var(--text-secondary)",fontStyle:"italic"},children:"No mitigations defined yet"}):(0,r.jsxs)("table",{className:"table",children:[(0,r.jsx)("thead",{children:(0,r.jsxs)("tr",{children:[(0,r.jsx)("th",{children:"Risk"}),(0,r.jsx)("th",{children:"Control"}),(0,r.jsx)("th",{children:"Test"})]})}),(0,r.jsx)("tbody",{children:e.mitigations.map((e,t)=>(0,r.jsxs)("tr",{children:[(0,r.jsx)("td",{children:(0,r.jsx)("code",{children:e.risk_id})}),(0,r.jsx)("td",{children:e.control}),(0,r.jsx)("td",{style:{color:"var(--text-secondary)"},children:e.test})]},t))})]})]})]})}function o({label:e,value:t,isEditing:a,onChange:i,options:s}){let l=m(t);return(0,r.jsxs)("div",{style:{textAlign:"center",padding:"1rem",background:"var(--bg-hover)",borderRadius:"8px"},children:[(0,r.jsx)("div",{style:{fontSize:"0.75rem",color:"var(--text-secondary)",marginBottom:"0.25rem"},children:e}),a?(0,r.jsx)("select",{value:t,onChange:e=>i(e.target.value),className:"input",style:{width:"100%",textAlign:"center"},children:s.map(e=>(0,r.jsx)("option",{value:e,style:{textTransform:"capitalize"},children:e},e))}):(0,r.jsx)("div",{style:{fontSize:"1.25rem",fontWeight:700,color:l,textTransform:"capitalize"},children:t})]})}function p({level:e,small:t}){let a=m(e);return(0,r.jsx)("span",{className:"badge",style:{background:`${a}20`,color:a,padding:t?"0.25rem 0.5rem":"0.5rem 1rem",fontSize:t?"0.75rem":"0.875rem",textTransform:"capitalize"},children:e})}function m(e){switch(e){case"critical":case"unacceptable":return"#dc2626";case"high":return"#f97316";case"medium":case"pending":return"#eab308";case"low":case"acceptable":return"#22c55e";default:return"var(--text-secondary)"}}},9339:(e,t,a)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r={callServer:function(){return s.callServer},createServerReference:function(){return n.createServerReference},findSourceMapURL:function(){return l.findSourceMapURL}};for(var i in r)Object.defineProperty(t,i,{enumerable:!0,get:r[i]});let s=a(7304),l=a(4060),n=a(7197)}},e=>{e.O(0,[500,441,794,358],()=>e(e.s=6164)),_N_E=e.O()}]);
|
|
File without changes
|
|
File without changes
|