@dtlabs/ai-toolkit 0.8.0 → 0.10.0
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/.claude/agents/generate-work-breakdown.md +212 -192
- package/.claude/agents/install-toolkit.md +6 -1
- package/.claude/agents/validate-work-breakdown-semantic.md +96 -0
- package/.claude/scripts/.gitkeep +0 -0
- package/.claude/scripts/tests/fixtures/ac-table-format.md +48 -0
- package/.claude/scripts/tests/fixtures/test-feature/TEST-001-Work-Breakdown.json +234 -0
- package/.claude/scripts/tests/fixtures/test-feature/TEST-001-semantic-output.json +4 -0
- package/.claude/scripts/tests/fixtures/test-feature/feature.md +45 -0
- package/.claude/scripts/tests/fixtures/wb-invalid-bad-domain.json +39 -0
- package/.claude/scripts/tests/fixtures/wb-invalid-cycle.json +61 -0
- package/.claude/scripts/tests/fixtures/wb-invalid-duplicate-id.json +72 -0
- package/.claude/scripts/tests/fixtures/wb-invalid-missing-field.json +38 -0
- package/.claude/scripts/tests/fixtures/wb-valid.json +189 -0
- package/.claude/scripts/tests/helpers/buildWaves.js +21 -0
- package/.claude/scripts/tests/helpers/pm-phase2-flow.js +29 -0
- package/.claude/scripts/tests/helpers/pm-phase2-gate2.js +55 -0
- package/.claude/scripts/tests/helpers/pm-phase2-ledger.js +108 -0
- package/.claude/scripts/tests/installer.scripts-distribution.test.js +131 -0
- package/.claude/scripts/tests/pm-phase2.gate2-payload.test.js +353 -0
- package/.claude/scripts/tests/pm-phase2.ledger-transitions.test.js +346 -0
- package/.claude/scripts/tests/pm-phase2.orchestration-flow.test.js +276 -0
- package/.claude/scripts/tests/verify-us-01-t03.js +288 -0
- package/.claude/scripts/tests/verify-us-03-t04.js +262 -0
- package/.claude/scripts/tests/wb-render.checks-md-csv-deps.test.js +337 -0
- package/.claude/scripts/tests/wb-render.checks-sanitize-commit-paths.test.js +352 -0
- package/.claude/scripts/tests/wb-render.regression-pm-phase3-csv.test.js +219 -0
- package/.claude/scripts/tests/wb-validate.checks-1-7.test.js +330 -0
- package/.claude/scripts/tests/wb-validate.checks-11.test.js +166 -0
- package/.claude/scripts/tests/wb-validate.checks-12-14.test.js +222 -0
- package/.claude/scripts/tests/wb-validate.checks-15-18.test.js +359 -0
- package/.claude/scripts/tests/wb-validate.checks-19-21.test.js +362 -0
- package/.claude/scripts/tests/wb-validate.checks-22-23-report.test.js +297 -0
- package/.claude/scripts/tests/wb-validate.checks-8-10.test.js +243 -0
- package/.claude/scripts/wb-render.js +309 -0
- package/.claude/scripts/wb-validate.js +1007 -0
- package/.claude/workflows/pm-phase1.js +22 -13
- package/.claude/workflows/pm-phase2.js +304 -32
- package/.claude/workflows/pm-phase3.js +57 -21
- package/CHANGELOG.md +82 -0
- package/bin/cli.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Requirements — Sample Feature for AC Parser Tests
|
|
2
|
+
|
|
3
|
+
This file is a test fixture for the AC table parser (wb-validate.js, Section 3.2 contract).
|
|
4
|
+
It contains UC metadata tables with Priority fields and a ## 7. Acceptance Criteria section
|
|
5
|
+
with an AC table in the exact format the parser expects.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 5. Use Cases
|
|
10
|
+
|
|
11
|
+
### UC-01: Parse and validate work breakdown JSON
|
|
12
|
+
|
|
13
|
+
| Field | Value |
|
|
14
|
+
|-------|-------|
|
|
15
|
+
| ID | UC-01 |
|
|
16
|
+
| Actor | wb-validate.js |
|
|
17
|
+
| Priority | Must |
|
|
18
|
+
| Trigger | pm-phase2 invokes the validator CLI |
|
|
19
|
+
|
|
20
|
+
**Description:** The validator reads a Work-Breakdown.json file, parses it according to schema
|
|
21
|
+
v2, and emits a structured JSON report. It must detect all 23 categories of structural error
|
|
22
|
+
without invoking an LLM.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
### UC-02: Render human-readable and CSV output
|
|
27
|
+
|
|
28
|
+
| Field | Value |
|
|
29
|
+
|-------|-------|
|
|
30
|
+
| ID | UC-02 |
|
|
31
|
+
| Actor | wb-render.js |
|
|
32
|
+
| Priority | Should |
|
|
33
|
+
| Trigger | pm-phase2 invokes the renderer CLI after a successful validate pass |
|
|
34
|
+
|
|
35
|
+
**Description:** The renderer reads the validated JSON and produces a Markdown file for human
|
|
36
|
+
review and a pipe-separated CSV file for pm-phase3 consumption.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 7. Acceptance Criteria
|
|
41
|
+
|
|
42
|
+
| ID | Criterion | Related UC |
|
|
43
|
+
|----|-----------|------------|
|
|
44
|
+
| AC-01 | Given a valid Work-Breakdown.json when wb-validate.js runs then it exits 0 and emits a JSON report with valid=true | UC-01 |
|
|
45
|
+
| AC-02 | Given a JSON file with a duplicate task ID when wb-validate.js runs then it exits 1 and reports category unique_id_violation | UC-01 |
|
|
46
|
+
| AC-03 | Given a Work-Breakdown.json that passes structural validation when wb-render.js runs then it writes both a .md and a .csv file to the feature directory | UC-01, UC-02 |
|
|
47
|
+
| AC-04 | Given a CSV produced by wb-render.js when pm-phase3 parses it then all phases are scheduled in the correct wave order | UC-02 |
|
|
48
|
+
| AC-05 | Given any validator or renderer invocation when it completes then a ledger entry is written with the correct status and token count | All UCs |
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 2,
|
|
3
|
+
"feature": "TEST-001",
|
|
4
|
+
"phases": [
|
|
5
|
+
{
|
|
6
|
+
"id": "INFRA",
|
|
7
|
+
"type": "infrastructure",
|
|
8
|
+
"title": "Shared infrastructure setup for JWT authentication",
|
|
9
|
+
"commit": { "type": "feat", "subject": "shared infrastructure for JWT auth" },
|
|
10
|
+
"tasks": [
|
|
11
|
+
{
|
|
12
|
+
"id": "INFRA-TASK-DB-01",
|
|
13
|
+
"title": "Register database context and User entity",
|
|
14
|
+
"outcome": "User entity is mapped in the database context; schema includes users table with id, email, passwordHash columns",
|
|
15
|
+
"domain": "DB",
|
|
16
|
+
"agentType": "developer-database",
|
|
17
|
+
"dependsOn": [],
|
|
18
|
+
"acceptanceCriteria": [],
|
|
19
|
+
"verification": { "commands": ["npx tsc --noEmit"] },
|
|
20
|
+
"estimate": { "agentMinutes": 8, "tokens": 18000 },
|
|
21
|
+
"outputCount": 1,
|
|
22
|
+
"groupingRationale": null,
|
|
23
|
+
"commit": { "type": "feat", "subject": "add User entity and database context registration" }
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": "INFRA-TASK-DB-02",
|
|
27
|
+
"title": "Create RefreshToken entity and migration",
|
|
28
|
+
"outcome": "RefreshToken entity is mapped; migration creates refresh_tokens table with token, userId, expiresAt columns",
|
|
29
|
+
"domain": "DB",
|
|
30
|
+
"agentType": "developer-database",
|
|
31
|
+
"dependsOn": ["INFRA-TASK-DB-01"],
|
|
32
|
+
"acceptanceCriteria": [],
|
|
33
|
+
"verification": { "commands": ["npx tsc --noEmit"] },
|
|
34
|
+
"estimate": { "agentMinutes": 8, "tokens": 18000 },
|
|
35
|
+
"outputCount": 1,
|
|
36
|
+
"groupingRationale": null,
|
|
37
|
+
"commit": { "type": "feat", "subject": "add RefreshToken entity and migration" }
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"id": "INFRA-TASK-BE-01",
|
|
41
|
+
"title": "Configure JWT signing secret and token expiry constants",
|
|
42
|
+
"outcome": "JWT_SECRET, ACCESS_TOKEN_EXPIRY (15m), and REFRESH_TOKEN_EXPIRY (7d) constants are loaded from environment variables and exported",
|
|
43
|
+
"domain": "BE",
|
|
44
|
+
"agentType": "developer-backend",
|
|
45
|
+
"dependsOn": [],
|
|
46
|
+
"acceptanceCriteria": [],
|
|
47
|
+
"verification": { "commands": ["npx tsc --noEmit"] },
|
|
48
|
+
"estimate": { "agentMinutes": 5, "tokens": 10000 },
|
|
49
|
+
"outputCount": 1,
|
|
50
|
+
"groupingRationale": null,
|
|
51
|
+
"commit": { "type": "feat", "subject": "add JWT signing secret and expiry config constants" }
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"id": "INFRA-TASK-BE-02",
|
|
55
|
+
"title": "Implement JwtService — sign and verify helpers",
|
|
56
|
+
"outcome": "JwtService class exists with signAccessToken(userId) and verifyToken(token) methods; uses INFRA-TASK-BE-01 constants",
|
|
57
|
+
"domain": "BE",
|
|
58
|
+
"agentType": "developer-backend",
|
|
59
|
+
"dependsOn": ["INFRA-TASK-BE-01"],
|
|
60
|
+
"acceptanceCriteria": [],
|
|
61
|
+
"verification": { "commands": ["npx tsc --noEmit"] },
|
|
62
|
+
"estimate": { "agentMinutes": 10, "tokens": 22000 },
|
|
63
|
+
"outputCount": 1,
|
|
64
|
+
"groupingRationale": null,
|
|
65
|
+
"commit": { "type": "feat", "subject": "add JwtService sign and verify helpers" }
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"id": "INFRA-TASK-BE-03",
|
|
69
|
+
"title": "Implement PasswordService — hash and compare helpers",
|
|
70
|
+
"outcome": "PasswordService class exists with hashPassword(plain) and comparePassword(plain, hash) methods using bcrypt",
|
|
71
|
+
"domain": "BE",
|
|
72
|
+
"agentType": "developer-backend",
|
|
73
|
+
"dependsOn": [],
|
|
74
|
+
"acceptanceCriteria": [],
|
|
75
|
+
"verification": { "commands": ["npx tsc --noEmit"] },
|
|
76
|
+
"estimate": { "agentMinutes": 8, "tokens": 15000 },
|
|
77
|
+
"outputCount": 1,
|
|
78
|
+
"groupingRationale": null,
|
|
79
|
+
"commit": { "type": "feat", "subject": "add PasswordService bcrypt helpers" }
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"id": "US-01",
|
|
85
|
+
"type": "user-story",
|
|
86
|
+
"title": "As an anonymous user, I want to register with email and password, so that I can access the system",
|
|
87
|
+
"commit": { "type": "feat", "subject": "implement US-01 user registration" },
|
|
88
|
+
"tasks": [
|
|
89
|
+
{
|
|
90
|
+
"id": "US-01-TASK-BE-01",
|
|
91
|
+
"title": "Implement RegisterUserService",
|
|
92
|
+
"outcome": "RegisterUserService class exists with register(email, password) method; validates uniqueness, hashes password via PasswordService, persists User, returns user id and email",
|
|
93
|
+
"domain": "BE",
|
|
94
|
+
"agentType": "developer-backend",
|
|
95
|
+
"dependsOn": ["INFRA-TASK-DB-01", "INFRA-TASK-BE-03"],
|
|
96
|
+
"acceptanceCriteria": ["AC-01", "AC-02", "AC-03"],
|
|
97
|
+
"verification": { "commands": ["npx tsc --noEmit"] },
|
|
98
|
+
"estimate": { "agentMinutes": 13, "tokens": 30000 },
|
|
99
|
+
"outputCount": 1,
|
|
100
|
+
"groupingRationale": null,
|
|
101
|
+
"commit": { "type": "feat", "subject": "add RegisterUserService with uniqueness and hash validation" }
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"id": "US-01-TASK-BE-02",
|
|
105
|
+
"title": "Implement POST /auth/register endpoint",
|
|
106
|
+
"outcome": "POST /auth/register controller action exists; validates request body (email, password), delegates to RegisterUserService, returns 201 on success or 409 on duplicate email",
|
|
107
|
+
"domain": "BE",
|
|
108
|
+
"agentType": "developer-backend",
|
|
109
|
+
"dependsOn": ["US-01-TASK-BE-01"],
|
|
110
|
+
"acceptanceCriteria": ["AC-01", "AC-02"],
|
|
111
|
+
"verification": { "commands": ["npx tsc --noEmit"] },
|
|
112
|
+
"estimate": { "agentMinutes": 10, "tokens": 22000 },
|
|
113
|
+
"outputCount": 1,
|
|
114
|
+
"groupingRationale": null,
|
|
115
|
+
"commit": { "type": "feat", "subject": "add POST /auth/register endpoint" }
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"id": "US-01-TASK-TEST-01",
|
|
119
|
+
"title": "Tests: user registration — success, duplicate email, password hashing",
|
|
120
|
+
"outcome": "Jest test suite for RegisterUserService and POST /auth/register covering 201 success, 409 conflict, and bcrypt hash verification",
|
|
121
|
+
"domain": "TEST",
|
|
122
|
+
"agentType": "developer-testing",
|
|
123
|
+
"dependsOn": ["US-01-TASK-BE-01", "US-01-TASK-BE-02"],
|
|
124
|
+
"acceptanceCriteria": ["AC-01", "AC-02", "AC-03"],
|
|
125
|
+
"verification": { "commands": ["npx jest --testPathPattern=register"] },
|
|
126
|
+
"estimate": { "agentMinutes": 15, "tokens": 35000 },
|
|
127
|
+
"outputCount": 1,
|
|
128
|
+
"groupingRationale": null,
|
|
129
|
+
"commit": { "type": "test", "subject": "add registration unit and integration tests" }
|
|
130
|
+
}
|
|
131
|
+
]
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"id": "US-02",
|
|
135
|
+
"type": "user-story",
|
|
136
|
+
"title": "As a registered user, I want to log in with my credentials, so that I receive JWT access and refresh tokens",
|
|
137
|
+
"commit": { "type": "feat", "subject": "implement US-02 user login" },
|
|
138
|
+
"tasks": [
|
|
139
|
+
{
|
|
140
|
+
"id": "US-02-TASK-BE-01",
|
|
141
|
+
"title": "Implement LoginService",
|
|
142
|
+
"outcome": "LoginService class exists with login(email, password) method; validates credentials via PasswordService, signs access and refresh tokens via JwtService, persists RefreshToken, returns both tokens",
|
|
143
|
+
"domain": "BE",
|
|
144
|
+
"agentType": "developer-backend",
|
|
145
|
+
"dependsOn": ["INFRA-TASK-DB-01", "INFRA-TASK-DB-02", "INFRA-TASK-BE-02", "INFRA-TASK-BE-03"],
|
|
146
|
+
"acceptanceCriteria": ["AC-04", "AC-05"],
|
|
147
|
+
"verification": { "commands": ["npx tsc --noEmit"] },
|
|
148
|
+
"estimate": { "agentMinutes": 14, "tokens": 32000 },
|
|
149
|
+
"outputCount": 1,
|
|
150
|
+
"groupingRationale": null,
|
|
151
|
+
"commit": { "type": "feat", "subject": "add LoginService with credential validation and token issuance" }
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"id": "US-02-TASK-BE-02",
|
|
155
|
+
"title": "Implement POST /auth/login endpoint",
|
|
156
|
+
"outcome": "POST /auth/login controller action exists; validates request body, delegates to LoginService, returns 200 with accessToken and refreshToken or 401 on invalid credentials",
|
|
157
|
+
"domain": "BE",
|
|
158
|
+
"agentType": "developer-backend",
|
|
159
|
+
"dependsOn": ["US-02-TASK-BE-01"],
|
|
160
|
+
"acceptanceCriteria": ["AC-04", "AC-05"],
|
|
161
|
+
"verification": { "commands": ["npx tsc --noEmit"] },
|
|
162
|
+
"estimate": { "agentMinutes": 9, "tokens": 20000 },
|
|
163
|
+
"outputCount": 1,
|
|
164
|
+
"groupingRationale": null,
|
|
165
|
+
"commit": { "type": "feat", "subject": "add POST /auth/login endpoint" }
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"id": "US-02-TASK-TEST-01",
|
|
169
|
+
"title": "Tests: user login — success, invalid password, unknown email",
|
|
170
|
+
"outcome": "Jest test suite for LoginService and POST /auth/login covering 200 with tokens, 401 on bad password, and 401 on unknown email",
|
|
171
|
+
"domain": "TEST",
|
|
172
|
+
"agentType": "developer-testing",
|
|
173
|
+
"dependsOn": ["US-02-TASK-BE-01", "US-02-TASK-BE-02"],
|
|
174
|
+
"acceptanceCriteria": ["AC-04", "AC-05"],
|
|
175
|
+
"verification": { "commands": ["npx jest --testPathPattern=login"] },
|
|
176
|
+
"estimate": { "agentMinutes": 14, "tokens": 32000 },
|
|
177
|
+
"outputCount": 1,
|
|
178
|
+
"groupingRationale": null,
|
|
179
|
+
"commit": { "type": "test", "subject": "add login unit and integration tests" }
|
|
180
|
+
}
|
|
181
|
+
]
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"id": "US-03",
|
|
185
|
+
"type": "user-story",
|
|
186
|
+
"title": "As an authenticated client, I want to refresh my access token, so that I stay logged in without re-entering credentials",
|
|
187
|
+
"commit": { "type": "feat", "subject": "implement US-03 token refresh" },
|
|
188
|
+
"tasks": [
|
|
189
|
+
{
|
|
190
|
+
"id": "US-03-TASK-BE-01",
|
|
191
|
+
"title": "Implement TokenRefreshService",
|
|
192
|
+
"outcome": "TokenRefreshService class exists with refresh(refreshToken) method; validates token via JwtService, invalidates old RefreshToken, issues new access and refresh tokens, persists new RefreshToken",
|
|
193
|
+
"domain": "BE",
|
|
194
|
+
"agentType": "developer-backend",
|
|
195
|
+
"dependsOn": ["INFRA-TASK-DB-02", "INFRA-TASK-BE-02"],
|
|
196
|
+
"acceptanceCriteria": ["AC-06", "AC-07"],
|
|
197
|
+
"verification": { "commands": ["npx tsc --noEmit"] },
|
|
198
|
+
"estimate": { "agentMinutes": 13, "tokens": 30000 },
|
|
199
|
+
"outputCount": 1,
|
|
200
|
+
"groupingRationale": null,
|
|
201
|
+
"commit": { "type": "feat", "subject": "add TokenRefreshService with rotation logic" }
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"id": "US-03-TASK-BE-02",
|
|
205
|
+
"title": "Implement POST /auth/refresh endpoint",
|
|
206
|
+
"outcome": "POST /auth/refresh controller action exists; validates request body, delegates to TokenRefreshService, returns 200 with new accessToken and refreshToken or 401 on invalid/expired token",
|
|
207
|
+
"domain": "BE",
|
|
208
|
+
"agentType": "developer-backend",
|
|
209
|
+
"dependsOn": ["US-03-TASK-BE-01"],
|
|
210
|
+
"acceptanceCriteria": ["AC-06", "AC-07"],
|
|
211
|
+
"verification": { "commands": ["npx tsc --noEmit"] },
|
|
212
|
+
"estimate": { "agentMinutes": 9, "tokens": 20000 },
|
|
213
|
+
"outputCount": 1,
|
|
214
|
+
"groupingRationale": null,
|
|
215
|
+
"commit": { "type": "feat", "subject": "add POST /auth/refresh endpoint" }
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
"id": "US-03-TASK-TEST-01",
|
|
219
|
+
"title": "Tests: token refresh — success with rotation, expired token, reuse of invalidated token",
|
|
220
|
+
"outcome": "Jest test suite for TokenRefreshService and POST /auth/refresh covering 200 with rotated tokens, 401 on expired token, and 401 on reuse of already-invalidated token",
|
|
221
|
+
"domain": "TEST",
|
|
222
|
+
"agentType": "developer-testing",
|
|
223
|
+
"dependsOn": ["US-03-TASK-BE-01", "US-03-TASK-BE-02"],
|
|
224
|
+
"acceptanceCriteria": ["AC-06", "AC-07"],
|
|
225
|
+
"verification": { "commands": ["npx jest --testPathPattern=refresh"] },
|
|
226
|
+
"estimate": { "agentMinutes": 15, "tokens": 35000 },
|
|
227
|
+
"outputCount": 1,
|
|
228
|
+
"groupingRationale": null,
|
|
229
|
+
"commit": { "type": "test", "subject": "add token refresh unit and integration tests" }
|
|
230
|
+
}
|
|
231
|
+
]
|
|
232
|
+
}
|
|
233
|
+
]
|
|
234
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Feature: TEST-001 — JWT Authentication
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Add user authentication to the API using JSON Web Tokens (JWT). Users register with an email and password, log in to receive a signed access token, and present that token on protected endpoints. A token refresh flow is also supported.
|
|
6
|
+
|
|
7
|
+
## Goals
|
|
8
|
+
|
|
9
|
+
- Allow new users to register with a unique email address and a hashed password.
|
|
10
|
+
- Allow registered users to log in and receive a short-lived JWT access token and a long-lived refresh token.
|
|
11
|
+
- Allow clients to exchange a valid refresh token for a new access token without re-entering credentials.
|
|
12
|
+
- Protect designated API routes so that only requests bearing a valid JWT are accepted.
|
|
13
|
+
|
|
14
|
+
## Non-Goals
|
|
15
|
+
|
|
16
|
+
- OAuth / social login is out of scope.
|
|
17
|
+
- Role-based access control beyond "authenticated vs. anonymous" is out of scope.
|
|
18
|
+
|
|
19
|
+
## Actors
|
|
20
|
+
|
|
21
|
+
- **Anonymous user** — not yet authenticated; may register or log in.
|
|
22
|
+
- **Authenticated user** — holds a valid JWT; may call protected endpoints and refresh tokens.
|
|
23
|
+
|
|
24
|
+
## Use Cases
|
|
25
|
+
|
|
26
|
+
### UC-01: User Registration
|
|
27
|
+
An anonymous user submits an email and password. The system validates the input, checks the email is not already taken, hashes the password, persists a new user record, and returns a 201 response.
|
|
28
|
+
|
|
29
|
+
### UC-02: User Login
|
|
30
|
+
A registered user submits their email and password. The system validates credentials, signs a JWT access token (15-minute expiry) and a refresh token (7-day expiry), persists the refresh token, and returns both tokens.
|
|
31
|
+
|
|
32
|
+
### UC-03: Token Refresh
|
|
33
|
+
An authenticated client presents a valid refresh token. The system validates the token, rotates it (invalidates the old one, issues a new one), and returns a fresh access token and new refresh token.
|
|
34
|
+
|
|
35
|
+
## Acceptance Criteria
|
|
36
|
+
|
|
37
|
+
| ID | Priority | User Story | Description |
|
|
38
|
+
|-------|----------|-----------|-------------|
|
|
39
|
+
| AC-01 | Must | US-01 | POST /auth/register returns 201 with user id and email on valid input |
|
|
40
|
+
| AC-02 | Must | US-01 | POST /auth/register returns 409 when email already exists |
|
|
41
|
+
| AC-03 | Must | US-01 | Passwords are stored as bcrypt hashes; plain text is never persisted |
|
|
42
|
+
| AC-04 | Must | US-02 | POST /auth/login returns 200 with accessToken and refreshToken on valid credentials |
|
|
43
|
+
| AC-05 | Must | US-02 | POST /auth/login returns 401 on invalid credentials |
|
|
44
|
+
| AC-06 | Must | US-03 | POST /auth/refresh returns 200 with a new accessToken and rotated refreshToken |
|
|
45
|
+
| AC-07 | Must | US-03 | POST /auth/refresh returns 401 when refresh token is expired or invalid |
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 2,
|
|
3
|
+
"feature": "FTR-014",
|
|
4
|
+
"phases": [
|
|
5
|
+
{
|
|
6
|
+
"id": "INFRA",
|
|
7
|
+
"type": "infrastructure",
|
|
8
|
+
"title": "Shared infrastructure setup",
|
|
9
|
+
"commit": {
|
|
10
|
+
"type": "feat",
|
|
11
|
+
"subject": "add shared infrastructure"
|
|
12
|
+
},
|
|
13
|
+
"tasks": [
|
|
14
|
+
{
|
|
15
|
+
"id": "INFRA-TASK-INFRA-01",
|
|
16
|
+
"title": "Create scripts directory",
|
|
17
|
+
"outcome": "The .claude/scripts directory exists",
|
|
18
|
+
"domain": "BACKEND",
|
|
19
|
+
"agentType": "developer-backend",
|
|
20
|
+
"dependsOn": [],
|
|
21
|
+
"acceptanceCriteria": [],
|
|
22
|
+
"verification": {
|
|
23
|
+
"commands": ["ls .claude/scripts"]
|
|
24
|
+
},
|
|
25
|
+
"estimate": {
|
|
26
|
+
"agentMinutes": 5,
|
|
27
|
+
"tokens": 8000
|
|
28
|
+
},
|
|
29
|
+
"outputCount": 1,
|
|
30
|
+
"groupingRationale": null,
|
|
31
|
+
"commit": {
|
|
32
|
+
"type": "feat",
|
|
33
|
+
"subject": "create .claude/scripts directory"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 2,
|
|
3
|
+
"feature": "FTR-014",
|
|
4
|
+
"phases": [
|
|
5
|
+
{
|
|
6
|
+
"id": "INFRA",
|
|
7
|
+
"type": "infrastructure",
|
|
8
|
+
"title": "Shared infrastructure setup",
|
|
9
|
+
"commit": {
|
|
10
|
+
"type": "feat",
|
|
11
|
+
"subject": "add shared infrastructure"
|
|
12
|
+
},
|
|
13
|
+
"tasks": [
|
|
14
|
+
{
|
|
15
|
+
"id": "INFRA-TASK-INFRA-01",
|
|
16
|
+
"title": "Task A — depends on Task B (forms a cycle)",
|
|
17
|
+
"outcome": "Task A exists and triggers task_cycle_detected when validated",
|
|
18
|
+
"domain": "INFRA",
|
|
19
|
+
"agentType": "developer-backend",
|
|
20
|
+
"dependsOn": ["INFRA-TASK-INFRA-02"],
|
|
21
|
+
"acceptanceCriteria": [],
|
|
22
|
+
"verification": {
|
|
23
|
+
"commands": ["npm test"]
|
|
24
|
+
},
|
|
25
|
+
"estimate": {
|
|
26
|
+
"agentMinutes": 5,
|
|
27
|
+
"tokens": 8000
|
|
28
|
+
},
|
|
29
|
+
"outputCount": 1,
|
|
30
|
+
"groupingRationale": null,
|
|
31
|
+
"commit": {
|
|
32
|
+
"type": "feat",
|
|
33
|
+
"subject": "add task A"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"id": "INFRA-TASK-INFRA-02",
|
|
38
|
+
"title": "Task B — depends on Task A (forms a cycle)",
|
|
39
|
+
"outcome": "Task B exists and triggers task_cycle_detected when validated",
|
|
40
|
+
"domain": "INFRA",
|
|
41
|
+
"agentType": "developer-backend",
|
|
42
|
+
"dependsOn": ["INFRA-TASK-INFRA-01"],
|
|
43
|
+
"acceptanceCriteria": [],
|
|
44
|
+
"verification": {
|
|
45
|
+
"commands": ["npm test"]
|
|
46
|
+
},
|
|
47
|
+
"estimate": {
|
|
48
|
+
"agentMinutes": 5,
|
|
49
|
+
"tokens": 8000
|
|
50
|
+
},
|
|
51
|
+
"outputCount": 1,
|
|
52
|
+
"groupingRationale": null,
|
|
53
|
+
"commit": {
|
|
54
|
+
"type": "feat",
|
|
55
|
+
"subject": "add task B"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 2,
|
|
3
|
+
"feature": "FTR-014",
|
|
4
|
+
"phases": [
|
|
5
|
+
{
|
|
6
|
+
"id": "INFRA",
|
|
7
|
+
"type": "infrastructure",
|
|
8
|
+
"title": "Shared infrastructure setup",
|
|
9
|
+
"commit": {
|
|
10
|
+
"type": "feat",
|
|
11
|
+
"subject": "add shared infrastructure"
|
|
12
|
+
},
|
|
13
|
+
"tasks": [
|
|
14
|
+
{
|
|
15
|
+
"id": "INFRA-TASK-INFRA-01",
|
|
16
|
+
"title": "Create scripts directory",
|
|
17
|
+
"outcome": "The .claude/scripts directory exists",
|
|
18
|
+
"domain": "INFRA",
|
|
19
|
+
"agentType": "developer-backend",
|
|
20
|
+
"dependsOn": [],
|
|
21
|
+
"acceptanceCriteria": [],
|
|
22
|
+
"verification": {
|
|
23
|
+
"commands": ["ls .claude/scripts"]
|
|
24
|
+
},
|
|
25
|
+
"estimate": {
|
|
26
|
+
"agentMinutes": 5,
|
|
27
|
+
"tokens": 8000
|
|
28
|
+
},
|
|
29
|
+
"outputCount": 1,
|
|
30
|
+
"groupingRationale": null,
|
|
31
|
+
"commit": {
|
|
32
|
+
"type": "feat",
|
|
33
|
+
"subject": "create .claude/scripts directory"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"id": "US-01",
|
|
40
|
+
"type": "user-story",
|
|
41
|
+
"title": "Implement validator entry point",
|
|
42
|
+
"commit": {
|
|
43
|
+
"type": "feat",
|
|
44
|
+
"subject": "implement validator entry point"
|
|
45
|
+
},
|
|
46
|
+
"tasks": [
|
|
47
|
+
{
|
|
48
|
+
"id": "INFRA-TASK-INFRA-01",
|
|
49
|
+
"title": "Duplicate task ID — same as INFRA-TASK-INFRA-01 above",
|
|
50
|
+
"outcome": "This task intentionally reuses INFRA-TASK-INFRA-01 to trigger unique_id_violation",
|
|
51
|
+
"domain": "BE",
|
|
52
|
+
"agentType": "developer-backend",
|
|
53
|
+
"dependsOn": [],
|
|
54
|
+
"acceptanceCriteria": [],
|
|
55
|
+
"verification": {
|
|
56
|
+
"commands": ["npm test"]
|
|
57
|
+
},
|
|
58
|
+
"estimate": {
|
|
59
|
+
"agentMinutes": 8,
|
|
60
|
+
"tokens": 12000
|
|
61
|
+
},
|
|
62
|
+
"outputCount": 1,
|
|
63
|
+
"groupingRationale": null,
|
|
64
|
+
"commit": {
|
|
65
|
+
"type": "feat",
|
|
66
|
+
"subject": "add duplicate task"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 2,
|
|
3
|
+
"feature": "FTR-014",
|
|
4
|
+
"phases": [
|
|
5
|
+
{
|
|
6
|
+
"id": "INFRA",
|
|
7
|
+
"type": "infrastructure",
|
|
8
|
+
"title": "Shared infrastructure setup",
|
|
9
|
+
"commit": {
|
|
10
|
+
"type": "feat",
|
|
11
|
+
"subject": "add shared infrastructure"
|
|
12
|
+
},
|
|
13
|
+
"tasks": [
|
|
14
|
+
{
|
|
15
|
+
"id": "INFRA-TASK-INFRA-01",
|
|
16
|
+
"title": "Create scripts directory",
|
|
17
|
+
"domain": "INFRA",
|
|
18
|
+
"agentType": "developer-backend",
|
|
19
|
+
"dependsOn": [],
|
|
20
|
+
"acceptanceCriteria": [],
|
|
21
|
+
"verification": {
|
|
22
|
+
"commands": ["ls .claude/scripts"]
|
|
23
|
+
},
|
|
24
|
+
"estimate": {
|
|
25
|
+
"agentMinutes": 5,
|
|
26
|
+
"tokens": 8000
|
|
27
|
+
},
|
|
28
|
+
"outputCount": 1,
|
|
29
|
+
"groupingRationale": null,
|
|
30
|
+
"commit": {
|
|
31
|
+
"type": "feat",
|
|
32
|
+
"subject": "create .claude/scripts directory"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
}
|