diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index da7f998b..d7d0bc44 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,300 +1,52 @@ -# GitHub Copilot Agent Configuration for DKNet Framework - -## Agent Identity -- **Project**: DKNet Framework -- **Type**: .NET 9 Library Collection -- **Focus**: EF Core Extensions, Specifications, Dynamic Predicates -- **Standards**: Enterprise-grade, production-ready code - -## Core Instructions for AI Agent - -### 1. ALWAYS Load Context First -Before generating ANY code, you MUST: -``` -1. Read /memory-bank/README.md (navigation) -2. Read /memory-bank/activeContext.md (current focus) -3. Read /memory-bank/copilot-quick-reference.md (patterns) -4. Read /memory-bank/systemPatterns.md (detailed patterns) -5. Read /memory-bank/copilot-rules.md (complete standards) -``` - -**Priority**: README → activeContext → quick-reference → systemPatterns → copilot-rules - -### 2. Project-Specific Knowledge - -#### Current Development Focus -- **Active Area**: EfCore.Specifications - Dynamic Predicate System -- **Key Features**: - - Dynamic predicate building with `DynamicPredicateBuilder` - - Specification Pattern implementation - - LinqKit integration for expression composition - - TestContainers for integration testing - - Enum validation and type safety - -#### Technology Stack -- **.NET**: 9.0 with C# 13 -- **EF Core**: 9.0 -- **Testing**: xUnit, Shouldly, TestContainers.MsSql, Bogus -- **Dynamic LINQ**: System.Linq.Dynamic.Core, LinqKit - -#### Code Quality Requirements -- `TreatWarningsAsErrors=true` - ZERO warnings allowed -- `enable` - Nullable reference types mandatory -- XML documentation required for all public APIs -- Test coverage: 85%+ target - -### 3. Pattern Recognition Rules - -When you see code involving: - -#### Dynamic Predicates -→ Use: `PredicateBuilder.New()`, `.DynamicAnd()`, `.DynamicOr()` -→ Always: Include `.AsExpandable()` before `.Where()` -→ Pattern: Null-safe dynamic expression building -```csharp -var predicate = PredicateBuilder.New() - .And(p => p.IsActive) - .DynamicAnd(builder => builder - .With("PropertyName", FilterOperations.Operator, value)); -``` - -#### EF Core Queries -→ Use: `.AsNoTracking()` for read-only -→ Use: `async`/`await` for all database operations -→ Filter: Push to database with `.Where()` before `.ToListAsync()` -→ Avoid: N+1 queries (use `.Include()` or projections) - -#### Tests -→ Framework: xUnit with Shouldly assertions -→ Integration: TestContainers.MsSql (real SQL Server) -→ Naming: `MethodName_Scenario_ExpectedBehavior` -→ Structure: Arrange-Act-Assert - -#### Extension Methods -→ Location: Static classes in `/Extensions` folder -→ Documentation: XML docs with ``, ``, `` -→ Naming: Verb-based (e.g., `TryConvertToEnum`, `DynamicAnd`) - -### 4. Code Generation Rules - -#### When Generating Classes -```csharp -// -// Copyright (c) 2025 Steven Hoang. All rights reserved. -// Licensed under the MIT License. See LICENSE in the project root for license information. -// - -/// -/// Brief description of the class purpose. -/// -public class ClassName -{ - private readonly IService _service; - - /// - /// Description of what this constructor does. - /// - public ClassName(IService service) - { - _service = service; - } -} -``` - -#### When Generating Methods -```csharp -/// -/// Description of what the method does. -/// -/// Description of generic parameter -/// Description of parameter -/// Description of return value -/// When paramName is null -public async Task> MethodNameAsync(string paramName) -{ - // Implementation with proper error handling -} -``` - -#### When Generating Tests -```csharp -[Fact] -public void MethodName_WhenScenarioOccurs_ThenExpectedOutcome() -{ - // Arrange: Setup test data and dependencies - var testData = CreateTestData(); - - // Act: Execute the operation under test - var result = _sut.MethodUnderTest(testData); - - // Assert: Verify expected outcomes - result.ShouldNotBeNull(); - result.ShouldBe(expectedValue); -} +# Project Guidelines + +## Context First +Before making code changes, load project context in this order: +1. `src/memory-bank/README.md` +2. `src/memory-bank/activeContext.md` +3. `src/memory-bank/copilot-quick-reference.md` +4. `src/memory-bank/systemPatterns.md` +5. `src/memory-bank/copilot-rules.md` + +## Architecture +- DKNet is a `.NET 10` library suite for enterprise API development using **DDD** and **Onion Architecture**. +- Keep domain behavior in domain types (aggregate roots, entities, value objects); keep infrastructure concerns in EF Core, messaging, and service packages. +- Prefer Specification + Repository patterns for query composition and reuse. +- For dynamic predicates, compose with LinqKit and use `.AsExpandable()` before `.Where()`. +- Keep boundaries clear across `Core`, `EfCore`, `Services`, `SlimBus`, and `AspNet` modules. + +## Build and Test +Run commands from `src/` unless noted. + +```bash +dotnet restore DKNet.FW.sln +dotnet build DKNet.FW.sln --configuration Release +dotnet test DKNet.FW.sln --configuration Release --settings coverage.runsettings --collect "XPlat Code Coverage" +dotnet pack DKNet.FW.sln --configuration Release ``` -### 5. Anti-Patterns to NEVER Generate - -❌ **NEVER** use InMemory database for EF Core tests (use TestContainers) -❌ **NEVER** mix sync and async code (`result = asyncMethod().Result`) -❌ **NEVER** materialize queries early (`.ToList()` then `.Where()`) -❌ **NEVER** forget `.AsExpandable()` with LinqKit predicates -❌ **NEVER** omit XML documentation on public APIs -❌ **NEVER** include secrets or credentials in code -❌ **NEVER** use `async void` (except event handlers) -❌ **NEVER** catch exceptions without logging -❌ **NEVER** ignore nullable warnings -❌ **NEVER** violate the Single Responsibility Principle - -### 6. Decision Making Guidelines - -#### When Asked to Implement a Feature -1. **Check** `activeContext.md` - Is this aligned with current focus? -2. **Review** `systemPatterns.md` - What pattern should be used? -3. **Reference** `copilot-quick-reference.md` - Are there templates? -4. **Generate** code following established patterns -5. **Include** comprehensive tests (arrange-act-assert) -6. **Document** with XML comments -7. **Verify** zero warnings after build - -#### When Asked to Fix a Bug -1. **Understand** the issue (read error messages, stack traces) -2. **Check** existing tests - Do they cover this scenario? -3. **Add** test that reproduces the bug (TDD approach) -4. **Fix** the code to make test pass -5. **Verify** all tests still pass -6. **Document** the fix in comments if non-obvious - -#### When Asked to Refactor -1. **Ensure** tests exist and pass before refactoring -2. **Make** small, incremental changes -3. **Run** tests after each change -4. **Keep** functionality identical (tests prove this) -5. **Improve** code quality, readability, performance -6. **Update** documentation if patterns change - -### 7. Quality Checklist - -Before considering code complete, verify: -- [ ] Compiles without warnings -- [ ] All tests pass -- [ ] XML documentation on public APIs -- [ ] File header present -- [ ] Follows naming conventions -- [ ] Null safety considered -- [ ] Error handling implemented -- [ ] Performance considered (async, filtering) -- [ ] Security considered (no secrets, validation) -- [ ] Patterns followed (Specification, Repository, etc.) - -### 8. Communication Guidelines - -#### When Explaining Code -- Reference the specific pattern from `systemPatterns.md` -- Include code examples from actual codebase -- Explain WHY, not just WHAT -- Link to relevant documentation - -#### When Suggesting Improvements -- Reference quality standards from `copilot-rules.md` -- Show before/after comparisons -- Explain benefits (performance, maintainability, etc.) -- Consider impact on existing code - -#### When Reporting Issues -- Provide error messages and stack traces -- Show relevant code context -- Suggest potential solutions -- Reference similar solved issues if available - -### 9. Special DKNet Framework Features - -#### Dynamic Predicate Builder -- **Purpose**: Build EF Core queries from runtime conditions -- **Usage**: `.DynamicAnd(builder => builder.With(...))` -- **Key**: Type-safe, null-safe, composable -- **Gotcha**: Always use `.AsExpandable()` with LinqKit - -#### Specification Pattern -- **Purpose**: Encapsulate query logic in reusable specifications -- **Base Class**: `Specification` -- **Features**: Criteria, Includes, OrderBy -- **Usage**: Compose with `.And()`, `.Or()` using LinqKit - -#### Type Extensions -- **Purpose**: Type checking and conversion utilities -- **Key Method**: `TryConvertToEnum` with validation -- **Usage**: Safe enum conversion with culture-invariant parsing -- **Pattern**: Return `bool`, `out` parameter for result - -#### TestContainers Integration -- **Purpose**: Real SQL Server for integration tests -- **Setup**: `IAsyncLifetime` fixture pattern -- **Benefits**: Catches SQL-specific issues, accurate testing -- **Usage**: One container per test class, dispose properly - -### 10. Context-Aware Responses - -When the user asks about: - -**"How do I..."** -→ Check `copilot-quick-reference.md` for templates -→ Provide code example following DKNet patterns -→ Include test example -→ Reference full documentation - -**"Why does..."** -→ Explain based on patterns in `systemPatterns.md` -→ Reference technical constraints in `techContext.md` -→ Show alternatives if applicable - -**"Is this correct..."** -→ Compare against `copilot-rules.md` standards -→ Check pattern usage in `systemPatterns.md` -→ Suggest improvements if needed -→ Explain reasoning - -**"What should I do next..."** -→ Check `activeContext.md` for current priorities -→ Reference `progress-detailed.md` for roadmap -→ Suggest aligned with project goals - ---- - -## Quick Reference for Agent - -### File Priority (Load Order) -1. `/memory-bank/README.md` - Navigation -2. `/memory-bank/activeContext.md` - Current work -3. `/memory-bank/copilot-quick-reference.md` - Quick patterns -4. `/memory-bank/systemPatterns.md` - Detailed patterns -5. `/memory-bank/copilot-rules.md` - Complete standards - -### Critical Patterns -- **Specification Pattern**: Reusable query specifications -- **Dynamic Predicates**: Runtime query building -- **Repository Pattern**: Data access abstraction -- **TestContainers**: Real database testing -- **Arrange-Act-Assert**: Test structure - -### Non-Negotiable Standards -- Zero warnings (`TreatWarningsAsErrors=true`) -- Nullable types enabled -- XML docs on public APIs -- Async/await for I/O -- TestContainers for integration tests - -### Common Tasks -- Adding filter operation → Update `DynamicPredicateBuilder`, add tests -- Creating specification → Inherit from `Specification`, implement `Criteria` -- Writing test → xUnit, Shouldly, `MethodName_Scenario_Outcome` naming -- Adding extension → Static class, XML docs, comprehensive tests - ---- - -**Agent Version**: 1.0 -**Last Updated**: November 5, 2025 -**Status**: Production Ready - -**Remember**: This configuration ensures consistent, high-quality code generation aligned with DKNet Framework standards and patterns. - +## Code Style +- Treat warnings as errors (`TreatWarningsAsErrors=true`) and keep nullable annotations correct (`Nullable=enable`). +- Add XML documentation for all public APIs. +- Use async I/O end-to-end; avoid sync-over-async (`.Result`, `.Wait()`). +- Follow existing naming conventions and static extension class placement. +- Keep changes minimal and scoped; do not refactor unrelated areas. + +## Conventions +- Test stack: xUnit + Shouldly. +- Integration tests should use Testcontainers/real provider behavior (avoid EF Core InMemory for integration scenarios). +- Test naming: `MethodName_Scenario_ExpectedBehavior`. +- For read-only EF queries, prefer `.AsNoTracking()`. +- Filter in database (compose `IQueryable`) before materialization. + +## Pitfalls +- Forgetting `.AsExpandable()` with LinqKit dynamic predicates breaks expression expansion. +- Early materialization (`ToList()` before filtering) causes performance and correctness issues. +- Missing XML docs or nullable fixes will fail CI due to strict build settings. + +## Key References +- Architecture and DDD: `docs/Architecture.md` +- Contribution workflow and commands: `docs/Contributing.md` +- Testing strategy: `TESTING_STRATEGY.md`, `src/coverage.runsettings` +- Build/analyzer settings: `src/Directory.Build.props`, `src/Directory.Packages.props`, `src/global.json` +- Detailed project guidance: `src/memory-bank/` diff --git a/.github/workflows/dotnet-publish.yml b/.github/workflows/dotnet-publish.yml index 00ad5efb..f686c99c 100644 --- a/.github/workflows/dotnet-publish.yml +++ b/.github/workflows/dotnet-publish.yml @@ -5,6 +5,7 @@ permissions: packages: write on: + workflow_dispatch: {} push: branches: - 'main' diff --git a/.vscode/extensions.json b/.vscode/extensions.json index dc5f6cda..e3ddb721 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -3,10 +3,8 @@ "streetsidesoftware.code-spell-checker", "ms-dotnettools.vscode-dotnet-runtime", "ms-dotnettools.csharp", - "ms-dotnettools.csdevkit", - "ms-dotnettools.vscodeintellicode-csharp", - "chadalen.vscode-jetbrains-icon-theme", "yzhang.markdown-all-in-one", - "shd101wyy.markdown-preview-enhanced" + "shd101wyy.markdown-preview-enhanced", + "jetbrains.resharper-code" ] -} +} \ No newline at end of file diff --git a/README.md b/README.md index f3a8235e..70b9b9f9 100644 Binary files a/README.md and b/README.md differ diff --git a/specs/002-IdempotanSqlStore/plan.md b/specs/002-IdempotanSqlStore/plan.md deleted file mode 100644 index e69de29b..00000000 diff --git a/specs/003-ai-library-skills/checklists/requirements.md b/specs/003-ai-library-skills/checklists/requirements.md new file mode 100644 index 00000000..982b0e96 --- /dev/null +++ b/specs/003-ai-library-skills/checklists/requirements.md @@ -0,0 +1,47 @@ +# Specification Quality Checklist: AI Library Skills for DKNet RESTful API Development + +**Purpose**: Validate specification completeness and quality before proceeding to planning +**Created**: 2026-03-16 +**Feature**: [spec.md](../spec.md) + +--- + +## Content Quality + +- [x] No implementation details (languages, frameworks, APIs) +- [x] Focused on user value and business needs +- [x] Written for non-technical stakeholders +- [x] All mandatory sections completed + +## Requirement Completeness + +- [x] No [NEEDS CLARIFICATION] markers remain +- [x] Requirements are testable and unambiguous +- [x] Success criteria are measurable +- [x] Success criteria are technology-agnostic (no implementation details) +- [x] All acceptance scenarios are defined +- [x] Edge cases are identified +- [x] Scope is clearly bounded +- [x] Dependencies and assumptions identified + +## Feature Readiness + +- [x] All functional requirements have clear acceptance criteria +- [x] User scenarios cover primary flows +- [x] Feature meets measurable outcomes defined in Success Criteria +- [x] No implementation details leak into specification + +## Notes + +All checklist items pass. Planning and implementation tasks are complete. + +Final implementation validation highlights: +- All 15 numbered library skill files exist under `memory-bank/libraries/`. +- Master index and composition patterns are present and linked. +- Skill files were normalized to include required template sections, including `Quick Decision Guide`. +- Test example sections across skills reference xUnit/Shouldly/TestContainers patterns and avoid `UseInMemoryDatabase` usage. + +Key decisions documented in Assumptions: +- Skill files stored under `memory-bank/libraries/` +- Minimal APIs only (no MVC Controllers) +- `DKNet.AspCore.Extensions` disambiguation between SlimBus and AspNet folders is explicitly noted diff --git a/specs/003-ai-library-skills/contracts/skill-file-template.md b/specs/003-ai-library-skills/contracts/skill-file-template.md new file mode 100644 index 00000000..ed987583 --- /dev/null +++ b/specs/003-ai-library-skills/contracts/skill-file-template.md @@ -0,0 +1,109 @@ +# Skill File Template + +> Copy this template when adding a new library to `memory-bank/libraries/`. +> Fill every section. Do not leave placeholder text. + +--- + +# [Library Name] — AI Skill File + +> **Package**: `[NuGet package name]` +> **Minimum Version**: `[x.y.z]` +> **Minimum .NET**: `net10.0` +> **Source**: `[relative path in repo]` + +--- + +## Purpose + +_One sentence: what problem does this library solve?_ + +--- + +## When To Use + +- ✅ [Scenario 1] +- ✅ [Scenario 2] + +## When NOT To Use + +- ❌ [Anti-scenario 1 — suggest the correct alternative] +- ❌ [Anti-scenario 2] + +--- + +## Installation + +```bash +dotnet add package [PackageName] +``` + +--- + +## Setup / DI Registration + +```csharp +// Program.cs / ServiceCollectionExtensions +[paste the exact service registration snippet] +``` + +--- + +## Key API Surface + +| Type / Method | Role | +|---|---| +| `TypeName` | What it does | + +--- + +## Usage Pattern + +```csharp +// ✅ Correct idiomatic usage +[complete, compilable example with XML doc headers] +``` + +--- + +## Anti-Patterns + +```csharp +// ❌ WRONG — [reason] +[bad code] + +// ✅ CORRECT +[good code] +``` + +--- + +## Composes With + +| Library | How | +|---|---| +| `DKNet.XYZ` | [relationship] | + +--- + +## Test Example + +```csharp +// xUnit + Shouldly + TestContainers — NO UseInMemoryDatabase +[test method following MethodName_Scenario_ExpectedBehavior naming] +``` + +--- + +## Security Notes _(required for libraries handling sensitive data)_ + +- [Note 1] + +--- + +## Version + +| Version | Notes | +|---|---| +| `x.y.z` | Initial documentation | + diff --git a/specs/003-ai-library-skills/data-model.md b/specs/003-ai-library-skills/data-model.md new file mode 100644 index 00000000..279e1f3e --- /dev/null +++ b/specs/003-ai-library-skills/data-model.md @@ -0,0 +1,56 @@ +# Data Model: Skill File Schema + +## Entity: SkillFile + +| Field | Type | Required | Notes | +|---|---|---|---| +| `package` | string | ✅ | NuGet package name | +| `minimumVersion` | semver | ✅ | Earliest version the documented API applies to | +| `minimumDotNet` | string | ✅ | Always `net10.0` | +| `source` | path | ✅ | Relative path in repo | +| `purpose` | string | ✅ | One sentence | +| `whenToUse` | string[] | ✅ | ≥1 bullet | +| `whenNotToUse` | string[] | ✅ | ≥1 bullet with redirect | +| `installation` | code | ✅ | `dotnet add package` snippet | +| `diRegistration` | code | ✅ | `Program.cs` service setup | +| `keyApiSurface` | table | ✅ | Type/Method → Role | +| `usagePattern` | code | ✅ | Complete compilable example | +| `antiPatterns` | code[] | ✅ | ≥2 wrong→correct pairs | +| `composesWith` | table | ✅ | Library → relationship | +| `testExample` | code | ✅ | xUnit + Shouldly + TestContainers | +| `securityNotes` | string[] | conditional | Required for security-relevant libraries | +| `versionTable` | table | ✅ | version → notes | + +## Entity: MasterIndex (README.md) + +| Field | Type | Notes | +|---|---|---| +| `scenarioTable` | table | Scenario → library list → skill file link(s) | +| `libraryList` | table | Package name → file → purpose | +| `loadingOrder` | ordered list | Which files to load for common tasks | + +## Entity: CompositionPattern + +| Field | Type | Notes | +|---|---|---| +| `name` | string | e.g., "CRUD Endpoint", "Idempotent Mutation" | +| `libraries` | string[] | All packages involved | +| `registrationSnippet` | code | Combined `Program.cs` setup | +| `handlerSnippet` | code | Handler + entity + DTO | +| `endpointSnippet` | code | Endpoint mapping | + +## Relationships + +``` +MasterIndex ──(1:N)──> SkillFile +SkillFile ──(M:N)──> SkillFile (via "Composes With") +CompositionPattern ──(1:N)──> SkillFile +``` + +## Validation Rules + +- `package` must match an entry in `Directory.Packages.props` or NuGet registry +- `minimumDotNet` must be `net10.0` (constitution requirement) +- `testExample` must NOT contain `UseInMemoryDatabase` (constitution requirement) +- `diRegistration` must NOT contain connection strings or secrets (constitution requirement) + diff --git a/specs/003-ai-library-skills/plan.md b/specs/003-ai-library-skills/plan.md new file mode 100644 index 00000000..39d41128 --- /dev/null +++ b/specs/003-ai-library-skills/plan.md @@ -0,0 +1,104 @@ +# Implementation Plan: AI Library Skills for DKNet RESTful API Development + +**Branch**: `003-ai-library-skills` | **Date**: 2026-03-16 | **Spec**: [spec.md](./spec.md) +**Input**: Feature specification from `/specs/003-ai-library-skills/spec.md` + +--- + +## Summary + +Create structured AI skill files — one per DKNet library — stored under `memory-bank/libraries/`, plus a master index and composition patterns. Update `AGENTS.md` and `memory-bank/README.md` to reference them. The skill files enable AI agents (GitHub Copilot, Cursor, etc.) to correctly choose and apply the right DKNet library when helping developers build ASP.NET Core Minimal API REST endpoints. + +--- + +## Technical Context + +**Language/Version**: C# 13 / .NET 10+ +**Primary Dependencies**: DKNet library suite (15 libraries) +**Storage**: N/A — documentation feature +**Testing**: N/A — docs only; verified by reviewing against real source API surface +**Target Platform**: AI agent context loading (GitHub Copilot, Cursor, Claude Code) +**Project Type**: Documentation / AI context library +**Performance Goals**: N/A +**Constraints**: Files must be under `memory-bank/` to be picked up by the existing agent loading chain +**Scale/Scope**: 15 skill files + 1 master index + 1 composition patterns document = 17 files total + +--- + +## Constitution Check + +- [x] **Runtime baseline**: All code examples target .NET 10+ / `net10.0`. No .NET 9 examples. +- [x] **Zero warnings**: All code snippets reviewed for `TreatWarningsAsErrors=true` compliance. +- [x] **Nullability contracts**: All examples use nullable reference types with explicit null handling. +- [x] **Documentation contract**: Skill files are self-documenting markdown. No new `.cs` public API introduced. +- [x] **Test-first gate**: Each skill file includes at least one test example using xUnit + Shouldly + TestContainers. +- [x] **Real DB integration**: All test examples use TestContainers, never `UseInMemoryDatabase`. +- [x] **Pattern integrity**: Specification/Repository, dynamic predicates, `.AsExpandable()` shown consistently. +- [x] **Security/secrets**: All examples use `configuration["ConnectionStrings:Default"]` — no hardcoded credentials. + +--- + +## Project Structure + +### Documentation (this feature) + +```text +specs/003-ai-library-skills/ +├── plan.md ← This file +├── research.md ← Phase 0 research output +├── data-model.md ← Skill file schema / structure contract +├── quickstart.md ← How to create and maintain skill files +└── contracts/ + └── skill-file-template.md ← Reusable template for new library skill files +``` + +### Deliverable Files (repository root) + +```text +memory-bank/ +└── libraries/ + ├── README.md ← Master index: scenario → library mapping + ├── 01-slimbus-extensions.md ← DKNet.SlimBus.Extensions + ├── 02-aspcore-extensions.md ← DKNet.AspCore.Extensions (SlimBus) + ├── 03-idempotency.md ← DKNet.AspCore.Idempotency + ├── 04-idempotency-mssql.md ← DKNet.AspCore.Idempotency.MsSqlStore + ├── 05-efcore-repos-abstractions.md ← DKNet.EfCore.Repos.Abstractions + ├── 06-efcore-repos.md ← DKNet.EfCore.Repos + ├── 07-efcore-specifications.md ← DKNet.EfCore.Specifications + ├── 08-efcore-auditlogs.md ← DKNet.EfCore.AuditLogs + ├── 09-efcore-dataauthorization.md ← DKNet.EfCore.DataAuthorization + ├── 10-efcore-encryption.md ← DKNet.EfCore.Encryption + ├── 11-efcore-events.md ← DKNet.EfCore.Events + ├── 12-efcore-extensions.md ← DKNet.EfCore.Extensions + ├── 13-efcore-dtogenerator.md ← DKNet.EfCore.DtoGenerator + ├── 14-aspcore-tasks.md ← DKNet.AspCore.Tasks + ├── 15-fw-extensions.md ← DKNet.Fw.Extensions + └── composition-patterns.md ← Multi-library recipe patterns + +AGENTS.md ← Updated to reference memory-bank/libraries/ +memory-bank/README.md ← Updated navigation entry for libraries/ +``` + +--- + +## Complexity Tracking + +No constitution violations. This feature is purely additive documentation with no code changes. + +--- + +## Post-Design Constitution Re-Check + +- [x] **Runtime baseline**: All new skill file examples remain .NET 10+ aligned. +- [x] **Zero warnings**: No compilable source code added; examples follow warning-safe conventions. +- [x] **Nullability contracts**: All examples use nullable-aware signatures and checks. +- [x] **Documentation contract**: Public API docs unaffected; feature output is documentation only. +- [x] **Test-first + real infra**: Skill files include xUnit/Shouldly/TestContainers patterns and explicitly reject `UseInMemoryDatabase`. +- [x] **Pattern integrity**: Specs/repositories/dynamic predicate guidance remains consistent. +- [x] **Security/secrets**: No secrets were introduced; configuration-based examples only. + +## Agent Context Update Notes + +- Attempted to run `.specify/scripts/bash/update-agent-context.sh copilot` per workflow. +- Script failed in this workspace because it expects a template outside the current workspace boundary (`/Users/steven/_CODE/DRUNK/DKNet/.specify/templates/agent-file-template.md`). +- Fallback applied: created `src/.github/agents/copilot-instructions.md` manually with the new planning context so downstream agent loading still works. diff --git a/specs/003-ai-library-skills/quickstart.md b/specs/003-ai-library-skills/quickstart.md new file mode 100644 index 00000000..1ba34b0d --- /dev/null +++ b/specs/003-ai-library-skills/quickstart.md @@ -0,0 +1,70 @@ +# Quickstart: Creating and Maintaining DKNet AI Skill Files + +## What Is a Skill File? + +A skill file is a structured markdown document in `memory-bank/libraries/` that tells AI agents (GitHub Copilot, Cursor, Claude Code) exactly how to use one DKNet library. AI agents load these files as context when generating code. + +--- + +## Adding a New Skill File + +1. **Copy** `specs/003-ai-library-skills/contracts/skill-file-template.md` +2. **Name it** `NN-package-name.md` where `NN` is the next sequence number +3. **Fill every section** — do not leave placeholder text +4. **Add it** to `memory-bank/libraries/README.md` master index +5. **Verify** all code examples compile with zero warnings + +--- + +## Updating an Existing Skill File + +Skill files MUST be updated in the **same PR** as the library change when: + +- A public API method signature changes +- A DI registration method is renamed or split +- A new anti-pattern is discovered +- The minimum version requirement increases + +Update the `## Version` table at the bottom of the file. + +--- + +## Quality Checklist (per file) + +Before merging a skill file: + +- [ ] All sections of the template are filled +- [ ] Code examples use `.NET 10+` syntax +- [ ] All code examples compile with `TreatWarningsAsErrors=true` +- [ ] Nullable reference types used everywhere +- [ ] Test example uses xUnit + Shouldly + TestContainers (no `UseInMemoryDatabase`) +- [ ] Anti-Patterns section has at least 2 entries +- [ ] "Composes With" table is accurate +- [ ] Security Notes section present for security-relevant libraries +- [ ] Entry added to `memory-bank/libraries/README.md` + +--- + +## File Naming Convention + +``` +NN-short-name.md + +Examples: + 01-slimbus-extensions.md + 07-efcore-specifications.md + composition-patterns.md (multi-library recipes, no number prefix) + README.md (master index, always this name) +``` + +--- + +## Agent Loading + +The `memory-bank/libraries/README.md` master index is referenced from: +- `AGENTS.md` → "Library Skills" section +- `memory-bank/README.md` → "Libraries" navigation entry +- `.github/copilot-instructions.md` → loading priority list + +AI agents are instructed to load `README.md` first (for scenario routing) then the specific skill file(s) for the task at hand. + diff --git a/specs/003-ai-library-skills/research.md b/specs/003-ai-library-skills/research.md new file mode 100644 index 00000000..dbf33b8a --- /dev/null +++ b/specs/003-ai-library-skills/research.md @@ -0,0 +1,97 @@ +# Research: AI Library Skills for DKNet RESTful API Development + +**Phase**: 0 — Resolve unknowns before design +**Date**: 2026-03-16 + +--- + +## Research Questions & Decisions + +### 1. Where should skill files live to be auto-loaded by AI agents? + +**Decision**: `memory-bank/libraries/` +**Rationale**: The existing agent loading chain already references `memory-bank/README.md` from both `AGENTS.md` and `.github/copilot-instructions.md`. Adding `libraries/` as a subdirectory with its own `README.md` keeps the discovery path consistent with current conventions — no new tool configuration required. +**Alternatives considered**: `.github/skills/` (too GitHub-specific, not loaded by Cursor), `.specify/memory/libraries/` (used for spec tooling only, not agent code context). + +--- + +### 2. What is the canonical skill file structure for maximum AI agent parse reliability? + +**Decision**: Fixed markdown headings in a predictable order: Purpose → Minimum Requirements → When To Use → When NOT To Use → Installation → Setup → Key API Surface → Usage Pattern → Anti-Patterns → Composition → Test Example. +**Rationale**: AI agents parse structured markdown well when headings are consistent across all files. A fixed schema allows the agent to skip sections it doesn't need without confusion. +**Alternatives considered**: Free-form narrative (hard to navigate programmatically), JSON/YAML (not human-friendly for inline code examples). + +--- + +### 3. Which libraries are used exclusively for REST API construction vs. general EF Core use? + +**Decision**: All 15 libraries are included. Even "general" EF Core libraries (Encryption, DataAuthorization, Events) are legitimately applied in REST API contexts and must be covered to prevent AI from reaching for third-party alternatives. +**Rationale**: If a skill file is missing, the AI will invent usage patterns or suggest MediatR / other alternatives. Every library must be documented. + +--- + +### 4. How does `DKNet.AspCore.Extensions` in the `SlimBus/` folder differ from the one in `AspNet/`? + +**Decision**: The `SlimBus/DKNet.AspCore.Extensions` package contains the Minimal API endpoint mappers (`FluentsEndpointMapperExtensions` — `MapPost`, `MapGet`, `MapGetPage`, `MapPut`, `MapPatch`, `MapDelete`, `ProducesCommons`). The `AspNet/DKNet.AspCore.Extensions` contains `ResultResponseExtensions`, `ProblemDetailsExtensions`, `PagedResponse` — HTTP result helpers used *inside* the SlimBus mapper. Both are needed for a complete REST API; the `SlimBus/` one is the entry point, the `AspNet/` one is the support library it internally depends on. +**Rationale**: Source code review of `SlimBus/DKNet.AspCore.Extensions/bin` vs `AspNet/DKNet.AspCore.Extensions/*.cs` confirms this distinction. + +--- + +### 5. What is the concrete `Fluents` interface hierarchy developers must implement? + +**Decision** (verified from `Fluents.cs`): + +``` +Commands (mutate state): + Fluents.Requests.INoResponse ← fire-and-forget command marker + Fluents.Requests.IWitResponse ← command returning Result marker + Fluents.Requests.IHandler ← handler for INoResponse commands + Fluents.Requests.IHandler ← handler for IWitResponse commands + +Queries (return data): + Fluents.Queries.IWitResponse ← single-result query marker + Fluents.Queries.IWitPageResponse ← paged query marker + Fluents.Queries.IHandler ← handler for single-result queries + Fluents.Queries.IPageHandler ← handler for paged queries + +Events: + Fluents.EventsConsumers.IHandler ← event consumer handler +``` + +--- + +### 6. What is the correct DI registration for the CQRS + Minimal API stack? + +**Decision** (verified from READMEs and source): +```csharp +// 1. Register SlimBus with EF Core auto-save behavior +services.AddSlimBusForEfCore(builder => builder + .WithProviderMemory() + .AutoDeclareFrom(typeof(CreateProductHandler).Assembly) + .AddJsonSerializer()); + +// 2. Register generic repositories +services.AddGenericRepositories(); + +// 3. Register DbContext +services.AddDbContext(...); +``` + +--- + +### 7. Do EfCore.Hooks and EfCore.AuditLogs overlap? When to use each? + +**Decision**: Use `EfCore.AuditLogs` when you need **structured field-level change records** (who changed what field from what value to what value). Use `EfCore.Hooks` when you need a **general-purpose lifecycle callback** (e.g., set timestamps, dispatch events, invalidate cache) that doesn't need to be a structured audit record. They can coexist. + +--- + +### 8. Best practices for AI agent skill file maintenance + +**Decision**: Each skill file includes a `## Version` section stating the minimum package version the documented API surface applies to. Maintainers update this section when the library API changes. The constitution's Documentation Gate (Principle IV) covers this. + +--- + +## Summary + +All NEEDS CLARIFICATION items resolved. Ready for Phase 1 design. + diff --git a/specs/003-ai-library-skills/spec.md b/specs/003-ai-library-skills/spec.md new file mode 100644 index 00000000..ab20d9c2 --- /dev/null +++ b/specs/003-ai-library-skills/spec.md @@ -0,0 +1,169 @@ +# Feature Specification: AI Library Skills for DKNet RESTful API Development + +**Feature Branch**: `003-ai-library-skills` +**Created**: 2026-03-16 +**Status**: Draft +**Input**: User description: "for each project here is the library that will be used to implement the RESTful API. I would like to build a set of AI skills so that the AI agent can understand each library and use it correctly." + +## Overview + +This feature defines a set of structured AI knowledge documents ("skills") — one per DKNet library — that enable AI coding agents (GitHub Copilot, Cursor, Claude, etc.) to correctly understand, choose, and apply each library when helping developers build RESTful APIs on the DKNet Framework stack. + +--- + +## User Scenarios & Testing *(mandatory)* + + + +### User Story 1 - AI Generates Correct CQRS REST Endpoint (Priority: P1) + +A developer prompts their AI agent to scaffold a new REST endpoint (e.g., "Create a POST endpoint to create a Product"). The AI correctly generates a SlimMessageBus command handler, maps it to a Minimal API endpoint via `DKNet.AspCore.Extensions`, and wires `FluentResults` for uniform HTTP responses — without the developer having to specify which libraries to use. + +**Why this priority**: The CQRS + Minimal API pattern (`DKNet.SlimBus.Extensions` + `DKNet.AspCore.Extensions`) is the primary architectural pattern for every REST endpoint in DKNet. If the AI gets this wrong, nothing else matters. + +**Independent Test**: Verified by asking the AI to scaffold a single POST resource endpoint and checking that the output contains a `ICommandHandler>` handler, a command record, and a `MapPost` one-liner using `DKNet.AspCore.Extensions` — without manual result-to-HTTP translation code. + +**Acceptance Scenarios**: + +1. **Given** a developer asks for a POST endpoint to create a resource, **When** the AI has the DKNet skill files loaded, **Then** it generates a `ICommandHandler>` handler, a matching command record, and a `MapPost` Minimal API endpoint using the `DKNet.AspCore.Extensions` one-liner mapping. +2. **Given** the developer asks for a GET query endpoint, **When** the AI generates the code, **Then** it uses `IQueryHandler>` and maps it as a `MapGet` with a `null → 404` guard. +3. **Given** the developer asks for a paged list endpoint, **When** the AI generates the code, **Then** it uses `IPagedQueryHandler` and returns a `PagedResult` JSON wrapper. + +--- + +### User Story 2 - AI Applies Idempotency to State-Mutating Endpoints (Priority: P2) + +A developer asks the AI to "make this POST endpoint idempotent." The AI correctly adds `DKNet.AspCore.Idempotency` middleware, registers the appropriate backing store (in-memory or SQL Server via `DKNet.AspCore.Idempotency.MsSqlStore`), and attaches the idempotency filter to the endpoint — without introducing duplicate-processing risk. + +**Why this priority**: Idempotency is a correctness requirement for payment, order, and mutation endpoints. Incorrect application causes data corruption or silent duplicate processing. + +**Independent Test**: Verified in isolation by prompting the AI to add idempotency to an existing endpoint and checking that the output includes `.WithIdempotency()` on the endpoint, `AddIdempotency(...)` in service registration, and — when SQL Server is requested — `AddIdempotencyMsSqlStore(...)` with a configuration reference (not a hardcoded connection string). + +**Acceptance Scenarios**: + +1. **Given** an existing POST endpoint, **When** the developer asks the AI to add idempotency, **Then** the AI adds `.WithIdempotency()` to the endpoint and `AddIdempotency(...)` to `Program.cs` service registration. +2. **Given** the developer specifies SQL Server persistence, **When** the AI applies idempotency, **Then** it also registers `AddIdempotencyMsSqlStore(...)` with the connection string read from configuration — not hardcoded. +3. **Given** a duplicate request arrives with the same idempotency key, **When** the endpoint is called, **Then** the generated architecture returns the cached response and does not re-execute the handler. + +--- + +### User Story 3 - AI Uses Repositories and Specifications for Data Access (Priority: P3) + +A developer asks the AI to "add data access for Products filtered by category and price range." The AI correctly uses `DKNet.EfCore.Repos` with a `Specification` from `DKNet.EfCore.Specifications`, avoiding raw `DbContext` calls, N+1 queries, and in-memory filtering. + +**Why this priority**: Data access is involved in nearly every endpoint. Incorrect patterns (raw `DbContext`, in-memory filtering) cause performance and maintainability problems at scale. + +**Independent Test**: Verified independently by asking the AI to generate a data access layer for a filtered list query and checking that the output contains a `Specification` subclass (not a raw LINQ chain) with `WithFilter`, `AddInclude`, and `AddOrderBy`, and that the repository call is `_repository.ToListAsync(spec, cancellationToken)`. + +**Acceptance Scenarios**: + +1. **Given** a request for filtered data, **When** the AI generates the query code, **Then** it creates a `Specification` subclass with `WithFilter`, `AddInclude`, and `AddOrderBy` — with no raw `_dbContext.Set().ToList().Where(...)` pattern. +2. **Given** dynamic runtime filters (e.g., search term, price range), **When** the AI adds dynamic filtering, **Then** it uses `DynamicPredicateBuilder` with `.DynamicAnd(builder => builder.With(...))` and includes `.AsExpandable()` on the query. +3. **Given** a write operation, **When** the AI generates the data access code, **Then** it uses `IWriteRepository` for commands and `IReadRepository` for queries, respecting CQRS boundaries. + +--- + +### User Story 4 - AI Adds Cross-Cutting Concerns Correctly (Priority: P4) + +A developer asks the AI to "add audit logging to this entity," "encrypt this column," or "restrict this query to the current user's data." The AI correctly applies the appropriate DKNet library (`DKNet.EfCore.AuditLogs`, `DKNet.EfCore.Encryption`, or `DKNet.EfCore.DataAuthorization`) without mixing them up or misapplying registration. + +**Why this priority**: Cross-cutting concerns are frequently added after initial scaffolding. Misapplication causes silent failures or security vulnerabilities. + +**Independent Test**: Verified independently by prompting the AI to add each concern in isolation and confirming correct attribute decoration and service registration for each library, with no cross-contamination. + +**Acceptance Scenarios**: + +1. **Given** a request to add audit logging, **When** the AI generates the code, **Then** it applies the DKNet audit marker/attribute to the entity and registers `AddEfCoreAuditLogs()` in `Program.cs` — not a manual `SaveChanges` override. +2. **Given** a request to encrypt a column, **When** the AI generates the code, **Then** it applies the DKNet encryption attribute to the entity property and registers the encryption provider in `DbContext` configuration. +3. **Given** a request for row-level data authorization, **When** the AI generates the code, **Then** it uses `DKNet.EfCore.DataAuthorization` patterns with the correct filter injection, not a manual `.Where(x => x.OwnerId == userId)` in every query. + +--- + +### Edge Cases + +- What happens when a developer asks the AI about a library that has no DKNet equivalent? The skill files should acknowledge the gap and suggest the closest DKNet alternative. +- What happens when two libraries overlap in functionality (e.g., both hooks and events could react to entity changes)? The skill files must include a disambiguation decision guide. +- How does the AI handle requests requiring composition of multiple libraries (e.g., idempotent CQRS endpoint + audit log + encrypted column)? A composition pattern document must exist. +- What if the developer's prompt is ambiguous about query vs. command? The skill files must define the disambiguation rule (mutates state → command; returns data → query). + +--- + +## Requirements *(mandatory)* + +### Functional Requirements + +- **FR-001**: A skill file MUST exist for every DKNet library listed in the Libraries to Cover table, covering: purpose, when to use, when NOT to use, setup/registration pattern, and at least one complete code example. +- **FR-002**: Each skill file MUST include an "Anti-Patterns" section listing the top 3 incorrect usages with corrected DKNet alternatives. +- **FR-003**: Skill files MUST use consistent, predictable section headings so AI agents can parse and navigate them reliably. +- **FR-004**: Each skill file MUST document inter-library dependencies and how it composes with other DKNet libraries. +- **FR-005**: A master index document MUST map common REST API development scenarios to the correct set of DKNet libraries (e.g., "CRUD endpoint → SlimBus.Extensions + AspCore.Extensions + EfCore.Repos"). +- **FR-006**: Skill files MUST be discoverable by AI agents through the existing `memory-bank/README.md` navigation and `AGENTS.md` loading instructions. +- **FR-007**: Each skill file MUST state the minimum .NET version and minimum package version for every API surface it documents. +- **FR-008**: Each skill file MUST include a "Quick Decision Guide" to help the AI choose between library variants (e.g., in-memory vs. SQL Server idempotency store, read vs. write repository). +- **FR-009**: Each skill file MUST include at least one test example following the DKNet test standard: xUnit, Shouldly, and TestContainers (no `UseInMemoryDatabase`). +- **FR-010**: A composition pattern document MUST exist for the most common multi-library scenarios: CRUD endpoint, paginated search, idempotent mutation, audited mutation, and encrypted data access. + +### Libraries to Cover + +| Layer | Library | Primary Role | +|-------|---------|-------------| +| API Endpoint Mapping | `DKNet.AspCore.Extensions` (SlimBus folder) | CQRS handler → Minimal API wiring | +| CQRS Handlers | `DKNet.SlimBus.Extensions` | Commands, queries, pagination, domain events | +| Idempotency | `DKNet.AspCore.Idempotency` | Duplicate request prevention | +| Idempotency Store | `DKNet.AspCore.Idempotency.MsSqlStore` | SQL Server persistence for idempotency | +| Repository (Write) | `DKNet.EfCore.Repos` | Concrete repository implementations | +| Repository (Abstractions) | `DKNet.EfCore.Repos.Abstractions` | IReadRepository, IWriteRepository contracts | +| Specifications | `DKNet.EfCore.Specifications` | Reusable, composable query specifications | +| Audit Logging | `DKNet.EfCore.AuditLogs` | Change tracking and audit trail | +| Data Authorization | `DKNet.EfCore.DataAuthorization` | Row-level access control | +| Encryption | `DKNet.EfCore.Encryption` | Column-level data encryption | +| Domain Events | `DKNet.EfCore.Events` | EF Core-integrated event publishing | +| EF Core Extensions | `DKNet.EfCore.Extensions` | EF Core utility and configuration helpers | +| DTO Generation | `DKNet.EfCore.DtoGenerator` | Source-generated DTOs from entity definitions | +| Background Tasks | `DKNet.AspCore.Tasks` | Hosted service task scheduling for APIs | +| Framework Extensions | `DKNet.Fw.Extensions` | Core utility extensions (validation, type helpers) | + +### Constitution Alignment *(mandatory)* + +- **CA-001 Runtime Baseline**: All skill file code examples MUST use .NET 10+ syntax and `net10.0` targets; no .NET 9 or earlier examples. +- **CA-002 Build Quality**: All code examples in skill files MUST be free of compiler warnings when `TreatWarningsAsErrors=true` is active. +- **CA-003 Nullability**: All code examples MUST use nullable reference types (`?`) and handle nulls explicitly; no `!` suppressors without justification. +- **CA-004 Documentation**: Skill files are the documentation; they MUST be complete, accurate, and reviewed when library APIs change. +- **CA-005 Testing**: Each skill file test example MUST use xUnit, Shouldly, and TestContainers; no `UseInMemoryDatabase` in any example. +- **CA-006 Patterns**: Skill files MUST reinforce Specification/Repository, dynamic predicate, and CQRS patterns throughout all examples. +- **CA-007 Security**: Libraries handling sensitive data (idempotency keys, encryption keys, authorization) MUST include a dedicated security notes section in their skill file. + +### Key Entities + +- **Skill File**: A structured markdown document for a single DKNet library, stored under `memory-bank/libraries/`, containing purpose, setup, usage patterns, anti-patterns, composition rules, and test examples. +- **Master Index**: A top-level scenario-to-library mapping document (`memory-bank/libraries/README.md`) serving as the AI agent's entry point for choosing which skill files to load. +- **Composition Pattern**: A multi-library recipe document showing how two or more DKNet libraries work together for a complete REST API scenario. +- **AI Agent Loading Point**: The existing `memory-bank/README.md` and `AGENTS.md` files, updated to reference the new `memory-bank/libraries/` directory so agents automatically discover skill files. + +--- + +## Success Criteria *(mandatory)* + +### Measurable Outcomes + +- **SC-001**: An AI agent with skill files loaded produces compilable, warning-free DKNet REST API code on the first attempt for at least 90% of the scenario types documented in the master index. +- **SC-002**: A developer using AI assistance can scaffold a complete CRUD REST feature (endpoint + handler + repository + specification) in under 5 minutes without correcting AI-generated library misuse. +- **SC-003**: AI-generated code uses the correct DKNet library (not an equivalent third-party alternative) for 100% of scenarios covered by skill files. +- **SC-004**: Documented anti-patterns do not appear in AI-generated code for any scenario explicitly covered by skill files (zero occurrences of documented anti-patterns). +- **SC-005**: All 15 libraries listed in the Libraries to Cover table have a completed skill file that passes the specification quality checklist before this feature is marked Done. +- **SC-006**: The master index and all composition pattern documents are reviewed and approved by the library maintainer before this feature is marked Done. + +--- + +## Assumptions + +- AI agents are GitHub Copilot, Cursor, or similar tools that load context from files referenced in `AGENTS.md`, `.github/copilot-instructions.md`, or `memory-bank/README.md`. +- Skill files will be stored under `memory-bank/libraries/` and referenced from the existing `memory-bank/README.md` navigation so the loading chain is consistent with current project conventions. +- The primary REST API style for DKNet projects is ASP.NET Core Minimal APIs; MVC Controller patterns are out of scope for this feature. +- `DKNet.AspCore.Extensions` in the `SlimBus/` folder is the Minimal API endpoint mapping library; the identically-named package in `AspNet/` folder covers unrelated concerns and is documented separately. +- Skill files are living documents; keeping them accurate is the responsibility of the library maintainer and is part of the definition of done for any future library change. +- Skill file quality is validated through the checklist template in `.specify/templates/checklist-template.md` before marking each skill file complete. + diff --git a/specs/003-ai-library-skills/tasks.md b/specs/003-ai-library-skills/tasks.md new file mode 100644 index 00000000..29cde616 --- /dev/null +++ b/specs/003-ai-library-skills/tasks.md @@ -0,0 +1,214 @@ +# Tasks: AI Library Skills for DKNet RESTful API Development + +**Input**: Design documents from `/specs/003-ai-library-skills/` +**Prerequisites**: `plan.md` (required), `spec.md` (required), `research.md`, `data-model.md`, `quickstart.md`, `contracts/` + +## Phase 1: Setup (Shared Infrastructure) + +**Purpose**: Prepare file structure and baseline documentation scaffolding. + +- [X] T001 Create the library skills folder and base artifact placeholders in `memory-bank/libraries/` +- [X] T002 Create/align feature documentation artifacts in `specs/003-ai-library-skills/research.md`, `specs/003-ai-library-skills/data-model.md`, `specs/003-ai-library-skills/quickstart.md`, and `specs/003-ai-library-skills/contracts/skill-file-template.md` +- [X] T003 [P] Record canonical DKNet library inventory and source-path mapping in `specs/003-ai-library-skills/research.md` + +--- + +## Phase 2: Foundational (Blocking Prerequisites) + +**Purpose**: Build shared guidance that all user stories depend on. + +**⚠️ CRITICAL**: No user story work starts before this phase is complete. + +- [X] T004 Build the master index skeleton (scenario routing + full library list) in `memory-bank/libraries/README.md` +- [X] T005 Define mandatory skill-file schema and validation rules in `specs/003-ai-library-skills/data-model.md` +- [X] T006 [P] Document contributor workflow for creating/updating skill files in `specs/003-ai-library-skills/quickstart.md` +- [X] T007 [P] Add memory-bank navigation and load order entry for library skills in `memory-bank/README.md` +- [X] T008 Add agent loading requirement for library skills index in `AGENTS.md` +- [X] T009 Add spec-agent context fallback guidance in `.github/agents/copilot-instructions.md` + +**Checkpoint**: Foundation complete - user stories can proceed. + +--- + +## Phase 3: User Story 1 - AI Generates Correct CQRS REST Endpoint (Priority: P1) 🎯 MVP + +**Goal**: Ensure AI uses `DKNet.SlimBus.Extensions` + `DKNet.AspCore.Extensions` correctly for POST/GET/paged endpoint generation. + +**Independent Test**: Ask AI to scaffold one POST endpoint, one GET endpoint, and one paged GET endpoint; output must use the correct Fluents interfaces and one-liner endpoint mapping. + +### Tests/Validation for User Story 1 + +- [X] T010 [P] [US1] Add xUnit/Shouldly/TestContainers validation example for command/query handler generation in `memory-bank/libraries/01-slimbus-extensions.md` +- [X] T011 [P] [US1] Add xUnit/Shouldly/TestContainers validation example for Minimal API mapping behavior in `memory-bank/libraries/02-aspcore-extensions.md` + +### Implementation for User Story 1 + +- [X] T012 [US1] Author the complete `DKNet.SlimBus.Extensions` skill file (purpose, setup, key APIs, anti-patterns, quick decisions) in `memory-bank/libraries/01-slimbus-extensions.md` +- [X] T013 [US1] Author the complete `DKNet.AspCore.Extensions` skill file (MapPost/MapGet/MapGetPage guidance + anti-patterns) in `memory-bank/libraries/02-aspcore-extensions.md` +- [X] T014 [US1] Update CQRS endpoint scenario routing for US1 in `memory-bank/libraries/README.md` + +**Checkpoint**: User Story 1 independently testable via AI prompt-to-code checks. + +--- + +## Phase 4: User Story 2 - AI Applies Idempotency to State-Mutating Endpoints (Priority: P2) + +**Goal**: Ensure AI applies idempotency middleware/store correctly for POST/PUT/PATCH/DELETE endpoints. + +**Independent Test**: Ask AI to add idempotency to an existing POST endpoint and require SQL-store variant; output must include `.WithIdempotency()`, `AddIdempotency(...)`, and `AddIdempotencyMsSqlStore(...)` with config-based connection string. + +### Tests/Validation for User Story 2 + +- [X] T015 [P] [US2] Add duplicate-request replay validation test example in `memory-bank/libraries/03-idempotency.md` +- [X] T016 [P] [US2] Add SQL-backed idempotency persistence validation test example in `memory-bank/libraries/04-idempotency-mssql.md` + +### Implementation for User Story 2 + +- [X] T017 [US2] Author the complete `DKNet.AspCore.Idempotency` skill file (options, endpoint filter usage, anti-patterns) in `memory-bank/libraries/03-idempotency.md` +- [X] T018 [US2] Author the complete `DKNet.AspCore.Idempotency.MsSqlStore` skill file (registration, security, durability guidance) in `memory-bank/libraries/04-idempotency-mssql.md` +- [X] T019 [US2] Add in-memory vs SQL-store quick decision guidance to scenario routing in `memory-bank/libraries/README.md` + +**Checkpoint**: User Story 2 independently testable with duplicate-request prompts. + +--- + +## Phase 5: User Story 3 - AI Uses Repositories and Specifications for Data Access (Priority: P3) + +**Goal**: Ensure AI generates repository/specification-based query and command data access, including dynamic predicates. + +**Independent Test**: Ask AI for filtered Product query + write operation; output must use `IReadRepository/IWriteRepository`, `Specification`, and dynamic predicates with `.AsExpandable()` when required. + +### Tests/Validation for User Story 3 + +- [X] T020 [P] [US3] Add repository abstraction validation examples (read vs write interface usage) in `memory-bank/libraries/05-efcore-repos-abstractions.md` +- [X] T021 [P] [US3] Add concrete repository DI/projection validation examples in `memory-bank/libraries/06-efcore-repos.md` +- [X] T022 [P] [US3] Add specification/dynamic predicate validation examples in `memory-bank/libraries/07-efcore-specifications.md` + +### Implementation for User Story 3 + +- [X] T023 [US3] Author the complete `DKNet.EfCore.Repos.Abstractions` skill file with `IReadRepository`, `IWriteRepository`, and decision guide in `memory-bank/libraries/05-efcore-repos-abstractions.md` +- [X] T024 [US3] Author the complete `DKNet.EfCore.Repos` skill file with registration and usage patterns in `memory-bank/libraries/06-efcore-repos.md` +- [X] T025 [US3] Author the complete `DKNet.EfCore.Specifications` skill file with `Specification`, `DynamicAnd/DynamicOr`, and `.AsExpandable()` rules in `memory-bank/libraries/07-efcore-specifications.md` +- [X] T026 [US3] Update query/data-access scenario routing in `memory-bank/libraries/README.md` + +**Checkpoint**: User Story 3 independently testable with data-access generation prompts. + +--- + +## Phase 6: User Story 4 - AI Adds Cross-Cutting Concerns Correctly (Priority: P4) + +**Goal**: Ensure AI correctly applies audit logging, data authorization, encryption, events, and supporting platform libraries. + +**Independent Test**: Ask AI to add audit logging, then encryption, then row-level authorization to a sample entity/API; output must select the right library and wiring each time. + +### Tests/Validation for User Story 4 + +- [X] T027 [P] [US4] Add structured audit-log validation examples in `memory-bank/libraries/08-efcore-auditlogs.md` +- [X] T028 [P] [US4] Add ownership-filter validation examples in `memory-bank/libraries/09-efcore-dataauthorization.md` +- [X] T029 [P] [US4] Add encrypted-field validation examples and security notes in `memory-bank/libraries/10-efcore-encryption.md` +- [X] T030 [P] [US4] Add domain-event publishing validation examples in `memory-bank/libraries/11-efcore-events.md` + +### Implementation for User Story 4 + +- [X] T031 [P] [US4] Author the complete `DKNet.EfCore.AuditLogs` skill file in `memory-bank/libraries/08-efcore-auditlogs.md` +- [X] T032 [P] [US4] Author the complete `DKNet.EfCore.DataAuthorization` skill file in `memory-bank/libraries/09-efcore-dataauthorization.md` +- [X] T033 [P] [US4] Author the complete `DKNet.EfCore.Encryption` skill file in `memory-bank/libraries/10-efcore-encryption.md` +- [X] T034 [P] [US4] Author the complete `DKNet.EfCore.Events` skill file in `memory-bank/libraries/11-efcore-events.md` +- [X] T035 [P] [US4] Author the complete `DKNet.EfCore.Extensions` skill file in `memory-bank/libraries/12-efcore-extensions.md` +- [X] T036 [P] [US4] Author supporting library skills in `memory-bank/libraries/13-efcore-dtogenerator.md`, `memory-bank/libraries/14-aspcore-tasks.md`, and `memory-bank/libraries/15-fw-extensions.md` +- [X] T037 [P] [US4] Update cross-cutting scenario routing and disambiguation guidance in `memory-bank/libraries/README.md` + +**Checkpoint**: User Story 4 independently testable via cross-cutting concern prompts. + +--- + +## Phase 7: Polish & Cross-Cutting Concerns + +**Purpose**: Final consistency pass across all stories and artifacts. + +- [X] T038 Create full multi-library recipe documentation in `memory-bank/libraries/composition-patterns.md` +- [X] T039 [P] Validate all 15 skill files include required template sections from `specs/003-ai-library-skills/contracts/skill-file-template.md` across `memory-bank/libraries/` +- [X] T040 [P] Verify all skill-file test examples use xUnit + Shouldly + TestContainers and avoid `UseInMemoryDatabase` across `memory-bank/libraries/` +- [X] T041 [P] Normalize .NET/version/security wording and quick-decision sections across `memory-bank/libraries/*.md` +- [X] T042 Finalize feature quality checklist notes in `specs/003-ai-library-skills/checklists/requirements.md` + +--- + +## Dependencies & Execution Order + +### Phase Dependencies + +- **Phase 1 (Setup)**: Starts immediately. +- **Phase 2 (Foundational)**: Depends on Phase 1 completion; blocks all user stories. +- **Phase 3-6 (User Stories)**: Depend on Phase 2 completion. +- **Phase 7 (Polish)**: Depends on completion of selected user stories. + +### User Story Dependencies + +- **US1 (P1)**: No dependency on other user stories. +- **US2 (P2)**: Depends on US1 only for shared index consistency; remains independently testable. +- **US3 (P3)**: Independent after foundational phase. +- **US4 (P4)**: Independent after foundational phase. + +### Suggested Delivery Order + +- MVP: **US1 only** +- Next increments: **US2**, **US3**, **US4** +- Finish with **Phase 7 polish** + +--- + +## Parallel Execution Examples + +### User Story 1 + +- Run T010 and T011 in parallel (different files). +- Run T012 and T013 in parallel after validation tasks. + +### User Story 2 + +- Run T015 and T016 in parallel. +- T017 and T018 can proceed in parallel, then merge via T019. + +### User Story 3 + +- Run T020, T021, T022 in parallel. +- Run T023, T024, T025 in parallel, then merge via T026. + +### User Story 4 + +- Run T027-T030 in parallel. +- Run T031-T036 in parallel (different files), then consolidate via T037. + +--- + +## Implementation Strategy + +### MVP First (US1) + +1. Complete Phase 1 and Phase 2. +2. Complete US1 tasks (T010-T014). +3. Validate AI-generated POST/GET/paged endpoint output against US1 independent test. + +### Incremental Delivery + +1. Deliver US1 (endpoint generation reliability). +2. Deliver US2 (idempotency correctness). +3. Deliver US3 (repository/specification correctness). +4. Deliver US4 (cross-cutting concern correctness). +5. Run Phase 7 quality normalization. + +### Team Parallelization + +1. One developer owns shared routing/index (`memory-bank/libraries/README.md`). +2. Other developers own separate skill files by story in parallel. +3. Final reviewer performs Phase 7 consistency sweep. + +--- + +## Notes + +- Tasks marked **[P]** are safe to execute concurrently. +- User story tasks include **[US1]-[US4]** labels for traceability. +- Every task includes an explicit file path as required. +- The resulting skills set should be immediately usable by AI agents through `memory-bank/libraries/README.md`. diff --git a/src/.github/agents/copilot-instructions.md b/src/.github/agents/copilot-instructions.md new file mode 100644 index 00000000..a5e5ddda --- /dev/null +++ b/src/.github/agents/copilot-instructions.md @@ -0,0 +1,21 @@ +# Copilot Agent Context (Spec-Kit) + +This file is generated/maintained for spec-driven planning context. + +## Feature Context +- Feature: `003-ai-library-skills` +- Plan: `specs/003-ai-library-skills/plan.md` +- Language: C# 13 / .NET 10+ +- Project Type: Documentation / AI context library + +## New Technology Focus Added By This Plan +- DKNet per-library skills under `memory-bank/libraries/` +- Scenario-based routing for API implementation through `memory-bank/libraries/README.md` +- Composition patterns for multi-library usage in `memory-bank/libraries/composition-patterns.md` + +## Usage +Before API code generation tasks: +1. Read `memory-bank/libraries/README.md` +2. Load only the relevant library skill files for the scenario +3. Apply anti-pattern guidance and test conventions from each selected file + diff --git a/src/.github/agents/speckit.checklist.agent.md b/src/.github/agents/speckit.checklist.agent.md index 970e6c9e..b7624e22 100644 --- a/src/.github/agents/speckit.checklist.agent.md +++ b/src/.github/agents/speckit.checklist.agent.md @@ -91,9 +91,10 @@ You **MUST** consider the user input before proceeding (if not empty). - Generate unique checklist filename: - Use short, descriptive name based on domain (e.g., `ux.md`, `api.md`, `security.md`) - Format: `[domain].md` - - If file exists, append to existing file - - Number items sequentially starting from CHK001 - - Each `/speckit.checklist` run creates a NEW file (never overwrites existing checklists) + - File handling behavior: + - If file does NOT exist: Create new file and number items starting from CHK001 + - If file exists: Append new items to existing file, continuing from the last CHK ID (e.g., if last item is CHK015, start new items at CHK016) + - Never delete or replace existing checklist content - always preserve and append **CORE PRINCIPLE - Test the Requirements, Not the Implementation**: Every checklist item MUST evaluate the REQUIREMENTS THEMSELVES for: @@ -205,13 +206,13 @@ You **MUST** consider the user input before proceeding (if not empty). 6. **Structure Reference**: Generate the checklist following the canonical template in `.specify/templates/checklist-template.md` for title, meta section, category headings, and ID formatting. If template is unavailable, use: H1 title, purpose/created meta lines, `##` category sections containing `- [ ] CHK### ` lines with globally incrementing IDs starting at CHK001. -7. **Report**: Output full path to created checklist, item count, and remind user that each run creates a new file. Summarize: +7. **Report**: Output full path to checklist file, item count, and summarize whether the run created a new file or appended to an existing one. Summarize: - Focus areas selected - Depth level - Actor/timing - Any explicit user-specified must-have items incorporated -**Important**: Each `/speckit.checklist` command invocation creates a checklist file using short, descriptive names unless file already exists. This allows: +**Important**: Each `/speckit.checklist` command invocation uses a short, descriptive checklist filename and either creates a new file or appends to an existing one. This allows: - Multiple checklists of different types (e.g., `ux.md`, `test.md`, `security.md`) - Simple, memorable filenames that indicate checklist purpose diff --git a/src/.github/agents/speckit.clarify.agent.md b/src/.github/agents/speckit.clarify.agent.md index 6b28dae1..657439f0 100644 --- a/src/.github/agents/speckit.clarify.agent.md +++ b/src/.github/agents/speckit.clarify.agent.md @@ -86,7 +86,7 @@ Execution steps: - Information is better deferred to planning phase (note internally) 3. Generate (internally) a prioritized queue of candidate clarification questions (maximum 5). Do NOT output them all at once. Apply these constraints: - - Maximum of 10 total questions across the whole session. + - Maximum of 5 total questions across the whole session. - Each question must be answerable with EITHER: - A short multiple‑choice selection (2–5 distinct, mutually exclusive options), OR - A one-word / short‑phrase answer (explicitly constrain: "Answer in <=5 words"). diff --git a/src/.github/agents/speckit.constitution.agent.md b/src/.github/agents/speckit.constitution.agent.md index 18302642..63d4f662 100644 --- a/src/.github/agents/speckit.constitution.agent.md +++ b/src/.github/agents/speckit.constitution.agent.md @@ -18,9 +18,11 @@ You **MUST** consider the user input before proceeding (if not empty). You are updating the project constitution at `.specify/memory/constitution.md`. This file is a TEMPLATE containing placeholder tokens in square brackets (e.g. `[PROJECT_NAME]`, `[PRINCIPLE_1_NAME]`). Your job is to (a) collect/derive concrete values, (b) fill the template precisely, and (c) propagate any amendments across dependent artifacts. +**Note**: If `.specify/memory/constitution.md` does not exist yet, it should have been initialized from `.specify/templates/constitution-template.md` during project setup. If it's missing, copy the template first. + Follow this execution flow: -1. Load the existing constitution template at `.specify/memory/constitution.md`. +1. Load the existing constitution at `.specify/memory/constitution.md`. - Identify every placeholder token of the form `[ALL_CAPS_IDENTIFIER]`. **IMPORTANT**: The user might require less or more principles than the ones used in the template. If a number is specified, respect that - follow the general template. You will update the doc accordingly. diff --git a/src/.github/agents/speckit.implement.agent.md b/src/.github/agents/speckit.implement.agent.md index 41da7b93..6158d20f 100644 --- a/src/.github/agents/speckit.implement.agent.md +++ b/src/.github/agents/speckit.implement.agent.md @@ -10,6 +10,40 @@ $ARGUMENTS You **MUST** consider the user input before proceeding (if not empty). +## Pre-Execution Checks + +**Check for extension hooks (before implementation)**: +- Check if `.specify/extensions.yml` exists in the project root. +- If it exists, read it and look for entries under the `hooks.before_implement` key +- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally +- Filter to only hooks where `enabled: true` +- For each remaining hook, do **not** attempt to interpret or evaluate hook `condition` expressions: + - If the hook has no `condition` field, or it is null/empty, treat the hook as executable + - If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation +- For each executable hook, output the following based on its `optional` flag: + - **Optional hook** (`optional: true`): + ``` + ## Extension Hooks + + **Optional Pre-Hook**: {extension} + Command: `/{command}` + Description: {description} + + Prompt: {prompt} + To execute: `/{command}` + ``` + - **Mandatory hook** (`optional: false`): + ``` + ## Extension Hooks + + **Automatic Pre-Hook**: {extension} + Executing: `/{command}` + EXECUTE_COMMAND: {command} + + Wait for the result of the hook command before proceeding to the Outline. + ``` +- If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently + ## Outline 1. Run `.specify/scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot"). @@ -85,7 +119,7 @@ You **MUST** consider the user input before proceeding (if not empty). - **Rust**: `target/`, `debug/`, `release/`, `*.rs.bk`, `*.rlib`, `*.prof*`, `.idea/`, `*.log`, `.env*` - **Kotlin**: `build/`, `out/`, `.gradle/`, `.idea/`, `*.class`, `*.jar`, `*.iml`, `*.log`, `.env*` - **C++**: `build/`, `bin/`, `obj/`, `out/`, `*.o`, `*.so`, `*.a`, `*.exe`, `*.dll`, `.idea/`, `*.log`, `.env*` - - **C**: `build/`, `bin/`, `obj/`, `out/`, `*.o`, `*.a`, `*.so`, `*.exe`, `Makefile`, `config.log`, `.idea/`, `*.log`, `.env*` + - **C**: `build/`, `bin/`, `obj/`, `out/`, `*.o`, `*.a`, `*.so`, `*.exe`, `*.dll`, `autom4te.cache/`, `config.status`, `config.log`, `.idea/`, `*.log`, `.env*` - **Swift**: `.build/`, `DerivedData/`, `*.swiftpm/`, `Packages/` - **R**: `.Rproj.user/`, `.Rhistory`, `.RData`, `.Ruserdata`, `*.Rproj`, `packrat/`, `renv/` - **Universal**: `.DS_Store`, `Thumbs.db`, `*.tmp`, `*.swp`, `.vscode/`, `.idea/` @@ -133,3 +167,32 @@ You **MUST** consider the user input before proceeding (if not empty). - Report final status with summary of completed work Note: This command assumes a complete task breakdown exists in tasks.md. If tasks are incomplete or missing, suggest running `/speckit.tasks` first to regenerate the task list. + +10. **Check for extension hooks**: After completion validation, check if `.specify/extensions.yml` exists in the project root. + - If it exists, read it and look for entries under the `hooks.after_implement` key + - If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally + - Filter to only hooks where `enabled: true` + - For each remaining hook, do **not** attempt to interpret or evaluate hook `condition` expressions: + - If the hook has no `condition` field, or it is null/empty, treat the hook as executable + - If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation + - For each executable hook, output the following based on its `optional` flag: + - **Optional hook** (`optional: true`): + ``` + ## Extension Hooks + + **Optional Hook**: {extension} + Command: `/{command}` + Description: {description} + + Prompt: {prompt} + To execute: `/{command}` + ``` + - **Mandatory hook** (`optional: false`): + ``` + ## Extension Hooks + + **Automatic Hook**: {extension} + Executing: `/{command}` + EXECUTE_COMMAND: {command} + ``` + - If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently diff --git a/src/.github/agents/speckit.plan.agent.md b/src/.github/agents/speckit.plan.agent.md index eb45be20..0ffb929d 100644 --- a/src/.github/agents/speckit.plan.agent.md +++ b/src/.github/agents/speckit.plan.agent.md @@ -69,10 +69,11 @@ You **MUST** consider the user input before proceeding (if not empty). - Validation rules from requirements - State transitions if applicable -2. **Generate API contracts** from functional requirements: - - For each user action → endpoint - - Use standard REST/GraphQL patterns - - Output OpenAPI/GraphQL schema to `/contracts/` +2. **Define interface contracts** (if project has external interfaces) → `/contracts/`: + - Identify what interfaces the project exposes to users or other systems + - Document the contract format appropriate for the project type + - Examples: public APIs for libraries, command schemas for CLI tools, endpoints for web services, grammars for parsers, UI contracts for applications + - Skip if project is purely internal (build scripts, one-off tools, etc.) 3. **Agent context update**: - Run `.specify/scripts/bash/update-agent-context.sh copilot` diff --git a/src/.github/agents/speckit.specify.agent.md b/src/.github/agents/speckit.specify.agent.md index 49abdcb7..23bab103 100644 --- a/src/.github/agents/speckit.specify.agent.md +++ b/src/.github/agents/speckit.specify.agent.md @@ -36,33 +36,14 @@ Given that feature description, do this: - "Create a dashboard for analytics" → "analytics-dashboard" - "Fix payment processing timeout bug" → "fix-payment-timeout" -2. **Check for existing branches before creating new one**: +2. **Create the feature branch** by running the script with `--short-name` (and `--json`), and do NOT pass `--number` (the script auto-detects the next globally available number across all branches and spec directories): - a. First, fetch all remote branches to ensure we have the latest information: - - ```bash - git fetch --all --prune - ``` - - b. Find the highest feature number across all sources for the short-name: - - Remote branches: `git ls-remote --heads origin | grep -E 'refs/heads/[0-9]+-$'` - - Local branches: `git branch | grep -E '^[* ]*[0-9]+-$'` - - Specs directories: Check for directories matching `specs/[0-9]+-` - - c. Determine the next available number: - - Extract all numbers from all three sources - - Find the highest number N - - Use N+1 for the new branch number - - d. Run the script `.specify/scripts/bash/create-new-feature.sh --json "$ARGUMENTS"` with the calculated number and short-name: - - Pass `--number N+1` and `--short-name "your-short-name"` along with the feature description - - Bash example: `.specify/scripts/bash/create-new-feature.sh --json "$ARGUMENTS" --json --number 5 --short-name "user-auth" "Add user authentication"` - - PowerShell example: `.specify/scripts/bash/create-new-feature.sh --json "$ARGUMENTS" -Json -Number 5 -ShortName "user-auth" "Add user authentication"` + - Bash example: `.specify/scripts/bash/create-new-feature.sh "$ARGUMENTS" --json --short-name "user-auth" "Add user authentication"` + - PowerShell example: `.specify/scripts/bash/create-new-feature.sh "$ARGUMENTS" -Json -ShortName "user-auth" "Add user authentication"` **IMPORTANT**: - - Check all three sources (remote branches, local branches, specs directories) to find the highest number - - Only match branches/directories with the exact short-name pattern - - If no existing branches/directories found with this short-name, start with number 1 + - Do NOT pass `--number` — the script determines the correct next number automatically + - Always include the JSON flag (`--json` for Bash, `-Json` for PowerShell) so the output can be parsed reliably - You must only ever run this script once per feature - The JSON is provided in the terminal as output - always refer to it to get the actual content you're looking for - The JSON output will contain BRANCH_NAME and SPEC_FILE paths @@ -145,7 +126,7 @@ Given that feature description, do this: c. **Handle Validation Results**: - - **If all items pass**: Mark checklist complete and proceed to step 6 + - **If all items pass**: Mark checklist complete and proceed to step 7 - **If items fail (excluding [NEEDS CLARIFICATION])**: 1. List the failing items and specific issues @@ -194,8 +175,6 @@ Given that feature description, do this: **NOTE:** The script creates and checks out the new branch and initializes the spec file before writing. -## General Guidelines - ## Quick Guidelines - Focus on **WHAT** users need and **WHY**. @@ -232,7 +211,7 @@ When creating this spec from a user prompt: - Performance targets: Standard web/mobile app expectations unless specified - Error handling: User-friendly messages with appropriate fallbacks - Authentication method: Standard session-based or OAuth2 for web apps -- Integration patterns: RESTful APIs unless specified otherwise +- Integration patterns: Use project-appropriate patterns (REST/GraphQL for web services, function calls for libraries, CLI args for tools, etc.) ### Success Criteria Guidelines diff --git a/src/.github/agents/speckit.tasks.agent.md b/src/.github/agents/speckit.tasks.agent.md index f64e86e7..1ae4d625 100644 --- a/src/.github/agents/speckit.tasks.agent.md +++ b/src/.github/agents/speckit.tasks.agent.md @@ -19,20 +19,54 @@ $ARGUMENTS You **MUST** consider the user input before proceeding (if not empty). +## Pre-Execution Checks + +**Check for extension hooks (before tasks generation)**: +- Check if `.specify/extensions.yml` exists in the project root. +- If it exists, read it and look for entries under the `hooks.before_tasks` key +- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally +- Filter to only hooks where `enabled: true` +- For each remaining hook, do **not** attempt to interpret or evaluate hook `condition` expressions: + - If the hook has no `condition` field, or it is null/empty, treat the hook as executable + - If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation +- For each executable hook, output the following based on its `optional` flag: + - **Optional hook** (`optional: true`): + ``` + ## Extension Hooks + + **Optional Pre-Hook**: {extension} + Command: `/{command}` + Description: {description} + + Prompt: {prompt} + To execute: `/{command}` + ``` + - **Mandatory hook** (`optional: false`): + ``` + ## Extension Hooks + + **Automatic Pre-Hook**: {extension} + Executing: `/{command}` + EXECUTE_COMMAND: {command} + + Wait for the result of the hook command before proceeding to the Outline. + ``` +- If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently + ## Outline 1. **Setup**: Run `.specify/scripts/bash/check-prerequisites.sh --json` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot"). 2. **Load design documents**: Read from FEATURE_DIR: - **Required**: plan.md (tech stack, libraries, structure), spec.md (user stories with priorities) - - **Optional**: data-model.md (entities), contracts/ (API endpoints), research.md (decisions), quickstart.md (test scenarios) + - **Optional**: data-model.md (entities), contracts/ (interface contracts), research.md (decisions), quickstart.md (test scenarios) - Note: Not all projects have all documents. Generate tasks based on what's available. 3. **Execute task generation workflow**: - Load plan.md and extract tech stack, libraries, project structure - Load spec.md and extract user stories with their priorities (P1, P2, P3, etc.) - If data-model.md exists: Extract entities and map to user stories - - If contracts/ exists: Map endpoints to user stories + - If contracts/ exists: Map interface contracts to user stories - If research.md exists: Extract decisions for setup tasks - Generate tasks organized by user story (see Task Generation Rules below) - Generate dependency graph showing user story completion order @@ -60,6 +94,35 @@ You **MUST** consider the user input before proceeding (if not empty). - Suggested MVP scope (typically just User Story 1) - Format validation: Confirm ALL tasks follow the checklist format (checkbox, ID, labels, file paths) +6. **Check for extension hooks**: After tasks.md is generated, check if `.specify/extensions.yml` exists in the project root. + - If it exists, read it and look for entries under the `hooks.after_tasks` key + - If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally + - Filter to only hooks where `enabled: true` + - For each remaining hook, do **not** attempt to interpret or evaluate hook `condition` expressions: + - If the hook has no `condition` field, or it is null/empty, treat the hook as executable + - If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation + - For each executable hook, output the following based on its `optional` flag: + - **Optional hook** (`optional: true`): + ``` + ## Extension Hooks + + **Optional Hook**: {extension} + Command: `/{command}` + Description: {description} + + Prompt: {prompt} + To execute: `/{command}` + ``` + - **Mandatory hook** (`optional: false`): + ``` + ## Extension Hooks + + **Automatic Hook**: {extension} + Executing: `/{command}` + EXECUTE_COMMAND: {command} + ``` + - If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently + Context for task generation: $ARGUMENTS The tasks.md should be immediately executable - each task must be specific enough that an LLM can complete it without additional context. @@ -109,13 +172,13 @@ Every task MUST strictly follow this format: - Map all related components to their story: - Models needed for that story - Services needed for that story - - Endpoints/UI needed for that story + - Interfaces/UI needed for that story - If tests requested: Tests specific to that story - Mark story dependencies (most stories should be independent) 2. **From Contracts**: - - Map each contract/endpoint → to the user story it serves - - If tests requested: Each contract → contract test task [P] before implementation in that story's phase + - Map each interface contract → to the user story it serves + - If tests requested: Each interface contract → contract test task [P] before implementation in that story's phase 3. **From Data Model**: - Map each entity to the user story(ies) that need it diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 00000000..f5b1a049 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,34 @@ +# DKNet source workspace ignores + +# .NET build artifacts +bin/ +obj/ +[Bb]uild/ +[Ll]og/ + +# User/IDE files +*.user +*.suo +*.userosscache +*.sln.docstates +.vscode/ +.idea/ + +# NuGet/artifacts +packages/ +*.nupkg +*.snupkg +nupkgs/ + +# Test and coverage artifacts +TestResults/ +coverage/ +coverage-report*/ +*.trx + +# OS/temp +.DS_Store +Thumbs.db +*.tmp +*.swp + diff --git a/src/.specify/init-options.json b/src/.specify/init-options.json new file mode 100644 index 00000000..34923af0 --- /dev/null +++ b/src/.specify/init-options.json @@ -0,0 +1,9 @@ +{ + "ai": "copilot", + "ai_commands_dir": null, + "ai_skills": false, + "here": true, + "preset": null, + "script": "sh", + "speckit_version": "0.3.0" +} \ No newline at end of file diff --git a/src/.specify/memory/constitution.md b/src/.specify/memory/constitution.md index 61a290a5..6ab0decd 100644 --- a/src/.specify/memory/constitution.md +++ b/src/.specify/memory/constitution.md @@ -1,322 +1,199 @@ # DKNet Framework Constitution ## Core Principles -### I. Zero Warnings Tolerance (NON-NEGOTIABLE) +### I. Runtime and SDK Baseline (.NET 10+) -All code MUST compile with zero warnings. This is enforced via `TreatWarningsAsErrors=true` in `Directory.Build.props`. +All maintained projects MUST target the .NET 10 platform baseline and align with the +solution SDK policy. **Rules**: -- Every build MUST pass with `-warnaserror` or equivalent (`TreatWarningsAsErrors=true`) -- Nullable reference types MUST be enabled (`enable`) -- All nullable warnings MUST be resolved, not suppressed without explicit justification -- Code formatting MUST pass `dotnet format` validation before merge +- `global.json` MUST pin a .NET 10 SDK and use controlled roll-forward behavior +- Shared project settings MUST keep `TargetFramework` aligned with `net10.0` +- Feature work MUST NOT introduce new .NET 9 or earlier targets unless approved as a + documented exception +- Version-sensitive documentation MUST be updated in the same change when runtime targets + move -**Rationale**: Warnings become bugs. Zero tolerance ensures code quality at compile time and prevents technical debt accumulation. +**Rationale**: A single runtime baseline prevents incompatibility drift across libraries, +analyzers, CI behavior, and NuGet consumers. -### II. Test-First with Real Databases (NON-NEGOTIABLE) +### II. Zero-Warning and Analyzer Discipline (NON-NEGOTIABLE) -Test-driven development is mandatory. Integration tests MUST use real SQL Server via TestContainers—InMemory database is prohibited for EF Core tests. +Build quality is enforced at compile time. Warnings are treated as defects. **Rules**: -- TDD cycle: Write test → Verify it fails → Implement → Verify it passes → Refactor -- Integration tests MUST use `TestContainers.MsSql` for realistic SQL Server behavior -- `InMemoryDatabase` is PROHIBITED for EF Core integration tests (catches SQL-specific issues) -- Test naming: `MethodName_Scenario_ExpectedBehavior` -- Test structure: Arrange-Act-Assert pattern mandatory -- Coverage targets: 90%+ critical paths, 85%+ business logic, 80%+ utilities +- `TreatWarningsAsErrors=true` MUST remain enabled for all buildable projects +- `dotnet build` and CI builds MUST pass with zero warnings +- Analyzer suppressions MUST be minimal, justified, and committed with rationale +- `dotnet format` compliance MUST be enforced before merge -**Rationale**: InMemory providers miss SQL-specific behaviors (transactions, collations, query translation). Real databases catch production issues during development. +**Rationale**: Strict analyzer enforcement prevents silent regressions and keeps libraries +safe to consume at scale. -### III. Async-Everywhere +### III. Nullable Safety and Explicit Contracts (NON-NEGOTIABLE) -All I/O operations MUST be asynchronous. Synchronous database access or blocking on async code is prohibited. +Null handling and contracts MUST be explicit in all public and internal behavior. **Rules**: -- All EF Core queries MUST use async variants (`ToListAsync`, `FirstOrDefaultAsync`, etc.) -- NEVER block on async: `.Result`, `.Wait()`, or `GetAwaiter().GetResult()` are prohibited -- `async void` is prohibited except for event handlers -- Use `ConfigureAwait(false)` in library code for non-UI context -- Methods performing I/O MUST have `Async` suffix and return `Task` or `Task` +- `enable` MUST remain enabled solution-wide +- Public APIs MUST validate nullable inputs and throw precise exceptions when required +- New code MUST NOT introduce nullable warnings or latent null-reference hazards +- Contract assumptions MUST be expressed in types and guard clauses, not comments alone -**Rationale**: Blocking on async causes deadlocks in ASP.NET Core. Async-everywhere ensures scalability and thread pool efficiency. +**Rationale**: DKNet is a shared library platform. Explicit null contracts reduce runtime +failures and improve API predictability. -### IV. Documentation & API Contracts +### IV. Public API Documentation and Packaging Contracts -All public APIs MUST have XML documentation. External consumers depend on clear contracts. +DKNet ships NuGet libraries; documentation is part of the product surface. **Rules**: -- All public classes, methods, and properties MUST have `` XML documentation -- ``, ``, and `` tags MUST be present where applicable -- File headers with copyright MUST be present in all `.cs` files (see `FILE_HEADER_TEMPLATE.md`) -- Breaking changes MUST be clearly marked in commit messages and PR descriptions -- Memory bank documentation MUST be updated when patterns change +- All public APIs MUST include XML documentation (`summary`, and tags as applicable) +- New `.cs` files MUST include approved file header content +- Package metadata and repository links MUST remain consistent with central package settings +- Breaking changes MUST be called out in PR descriptions and release notes -**Rationale**: DKNet is a NuGet library collection. Clear documentation enables adoption and reduces support burden. +**Rationale**: Consumers rely on generated docs and package metadata for safe adoption and +upgrade planning. -### V. Security & Null Safety +### V. Test-First and Real Infrastructure Validation (NON-NEGOTIABLE) -No secrets in code. Null safety enforced via language features and explicit handling. +Behavior changes MUST be driven by tests, and data-layer integration MUST be verified on +real providers. **Rules**: -- Secrets, API keys, and connection strings MUST NOT be committed to source control -- Use configuration providers (`IConfiguration`) for sensitive values -- Nullable reference types MUST be enabled and respected -- Null checks MUST be explicit or use null-conditional operators (`?.`, `??`) -- `ArgumentNullException` MUST be thrown for invalid null arguments with `nameof()` -- NEVER catch exceptions without logging or re-throwing +- Development MUST follow red-green-refactor for behavior changes +- Unit tests MUST use xUnit with clear Arrange-Act-Assert structure +- EF Core integration tests MUST use Testcontainers (for example, SQL Server via + `Testcontainers.MsSql`) +- EF Core integration tests MUST NOT rely on InMemory provider for SQL-behavior validation +- Test names MUST follow `MethodName_Scenario_ExpectedBehavior` -**Rationale**: Security vulnerabilities and null reference exceptions are the most common production issues. Prevention at code level is cheaper than runtime fixes. +**Rationale**: Real infrastructure tests expose provider-specific translation and transaction +issues that fake providers cannot. -### VI. Pattern Compliance +### VI. Architecture and Data Access Pattern Integrity -Code MUST follow established DKNet patterns. Consistency enables maintainability. +Core architectural patterns are mandatory for consistency across modules. **Rules**: -- Dynamic predicates MUST use `PredicateBuilder.New()` with `.DynamicAnd()` / `.DynamicOr()` -- LinqKit queries MUST include `.AsExpandable()` before `.Where()` with dynamic predicates -- Specifications MUST inherit from `Specification` base class -- Extension methods MUST be in static classes within `/Extensions` folder -- Repository pattern MUST be used for data access abstraction -- EF Core queries MUST use `.AsNoTracking()` for read-only operations -- Filtering MUST happen on database (`.Where()` before `.ToListAsync()`) +- Domain-driven and onion layering boundaries MUST be preserved +- Query logic MUST use Specification and Repository patterns where those abstractions exist +- Dynamic predicates MUST use the project predicate builder conventions + (`PredicateBuilder.New()`, `.DynamicAnd()`, `.DynamicOr()`) +- LinqKit-backed dynamic predicate queries MUST call `.AsExpandable()` before `.Where(...)` +- Read-only EF Core queries MUST use `.AsNoTracking()` and keep filtering in database -**Rationale**: Consistent patterns reduce cognitive load, enable code reuse, and simplify code reviews. +**Rationale**: Pattern consistency keeps modules composable, testable, and maintainable. -## Quality Gates +### VII. Security, Secrets, and Operational Hardening -Pre-merge requirements that MUST pass for any code change. +Security hygiene is mandatory in source, configuration, and runtime behavior. -**Build Gate**: -- `dotnet build -c Release` with zero warnings -- `dotnet format --verify-no-changes` passes +**Rules**: +- Secrets (keys, credentials, raw connection strings) MUST NOT be committed +- Sensitive configuration MUST come from approved configuration providers and secret stores +- Exception handling MUST log or propagate actionable context; silent catch blocks are + prohibited +- Input validation MUST be explicit at boundaries (API endpoints, handlers, data filters) -**Test Gate**: -- `dotnet test` with all tests passing -- Coverage thresholds met (see Principle II) -- No new test failures introduced +**Rationale**: Secret leakage and opaque failures create avoidable operational and compliance +risk. -**Documentation Gate**: -- XML docs present for all new public APIs -- Memory bank updated if patterns/context changed -- File headers present on new `.cs` files +## Additional Constraints -**Review Gate**: -- At least one approval from module owner -- All review comments addressed -- Commit messages follow conventional format (`type(scope): description`) +- Primary languages and tooling: C# 13, .NET 10 SDK, EF Core 10+, xUnit, Shouldly, + Testcontainers, LinqKit, System.Linq.Dynamic.Core. +- Central package and build governance in `Directory.Packages.props` and + `Directory.Build.props` is authoritative for shared defaults. +- Module placement MUST follow solution domains (`Core`, `EfCore`, `AspNet`, `Services`, + `SlimBus`, `Aspire`) with minimal cross-domain coupling. ## Development Workflow -Standard process for feature development in DKNet Framework. +All work MUST pass explicit gates before merge. -**Branch Naming**: `###-feature-name` (e.g., `001-dynamic-predicate-enums`) - -**Commit Format**: -``` -(): - - +**Build Gate**: +- `dotnet restore DKNet.FW.sln` +- `dotnet build DKNet.FW.sln -c Debug` +- Zero warnings in all changed projects -