Add a brownfield dashboard feature with Spec Kit
An existing project has behavior, consumers, tests and conventions. A new feature must integrate with those constraints instead of regenerating the project.
Lab briefing

Original concept illustration (SVG)
| At a glance | Your route |
|---|---|
| Level and time | 300; 85 minutes (facilitation estimate) |
| Starting action | Keep baseline tests green while the new feature starts red. |
| Learner materials | Download 14-brownfield.zip |
| Workspace | Open the extracted kit root; run the baseline from . relative to that root |
| Expected initial check | The supplied baseline tests pass. |
| Setup help | Download, extract, local Git and optional GitHub |
[!NOTE] A trusted test actor is a seam, not production authentication.
Concepts · First task · Evidence checklist · Reset
Learning objectives
- Characterize existing endpoints/module contracts before initializing scaffolding.
- Specify a feature as a bounded delta.
- Keep identity separate from model- or request-supplied fields.
- Verify old and new behavior together.
Before you start
Complete Spec Kit preparation.
Prepare 14-brownfield using the work-drive guide.
This bundled dashboard module replaces the mandatory external repository import.
No LocalDB, cloud account changes, binary upload, or public repository is needed.
Concepts and use cases
| Existing constraint | New requirement |
|---|---|
health() response stays unchanged |
Add document metadata |
projects() preserves IDs and shape |
Register only under an existing project |
| No production authentication in the fixture | Inject a trusted test actor; never accept owner identity from input |
| Module callers must not mutate state | Return copies of metadata records |
Exercise scenario
The dashboard already lists a training project. Add document titles and IDs scoped to the current fixture actor. Actual file uploads, malware scanning, external storage, and real user authentication are explicitly separate work.
Task 1 - Run the old and new contracts separately
node --test --test-concurrency=1 baseline.test.mjs
node --test --test-concurrency=1 feature.test.mjs
- Confirm the baseline is green.
- Confirm the feature tests fail because the feature is not implemented.
- Record the exact messages and exit codes.
- Read
requirements.md; map DOC-1..4 to tests and identify missing knowledge.
Task 2 - Adopt Spec Kit without replacing the application
- Make a baseline commit in the disposable project.
- Inspect
.github,.specifyand editor files beforespecify init --here. - Review every scaffolding change and preserve project-owned instructions.
- Create a constitution that preserves DOC-1 and bans unrelated modernization.
Do not use --force as a substitute for conflict resolution.
Task 3 - Specify the delta and clarify ownership
/speckit-specify Add document metadata to the existing dashboard in requirements.md.
Preserve health/projects exactly. Derive ownerId from a trusted actor supplied by
the application boundary, not from document input. Reject missing project/title,
overlong title, missing actor and owner spoofing. No file upload.
Use /speckit-clarify to answer:
- Who establishes the actor in production?
- What is the maximum title length?
- Does a failed add leave partial state?
- May another actor list these records?
The fixture’s injected actor is a test seam, not proof of production authentication.
Task 4 - Plan with compatibility gates
Use /speckit-plan to require:
- Existing
healthandprojectsunchanged. - New metadata storage and validation confined to the module.
- Owner-scoped listing with defensive copies.
- Combined execution of baseline and feature tests.
- Explicit error propagation, no silent fallback owner.
For .NET, propose an authenticated controller/service adaptation; for TypeScript, add explicit input/output types. Both must preserve DOC-1..4. Do not claim those adapters were run unless you implement and execute their tests.
Task 5 - Implement and evaluate the delta
-
Run
/speckit-tasksand/speckit-analyze. -
Review mappings to both legacy and new tests.
-
Implement one slice, then run:
node --test --test-concurrency=1 baseline.test.mjs feature.test.mjs -
Inspect the entire diff, not just the new method.
-
Temporarily remove owner filtering. Confirm the cross-actor test fails, then restore it.
-
Use
/speckit-convergeas a review aid, not evidence that tests ran.
Verify your work
- Old tests stay green alongside the new feature.
- Ownership comes from the trusted boundary.
- Wrong actor, spoofed owner and invalid input are rejected or isolated.
- The feature introduces no binary upload or new network service.
- The compatibility gate is represented in spec, tasks and executed tests.
Troubleshooting
If the generated code rewrites the whole dashboard, stop and compare the baseline. If tests pass only individually, inspect shared state. If an “owner” string is read from user input, it is not authorization.
Independent practice
Specify a separate binary-upload feature with size limits, content validation, storage ownership, malware handling and deletion policy. Keep it a design exercise until its own fixtures and tests exist.
Reset
Save evidence, then restore only dashboard.mjs in the disposable copy. Keep the
curriculum and upstream material untouched; remove no shared branches or accounts.