From b3c436d6a7688a88ae7559739f331444b33f8e1b Mon Sep 17 00:00:00 2001 From: "anthropic-code-agent[bot]" <242468646+Claude@users.noreply.github.com> Date: Mon, 20 Apr 2026 08:07:12 +0000 Subject: [PATCH 1/7] Initial plan From 6227e66e8327920e5bd6f7ce17c28fff0ed7ba38 Mon Sep 17 00:00:00 2001 From: "anthropic-code-agent[bot]" <242468646+Claude@users.noreply.github.com> Date: Mon, 20 Apr 2026 08:09:38 +0000 Subject: [PATCH 2/7] Add conservative path filters to workflow Agent-Logs-Url: https://github.com/dgee2/Menu/sessions/769265b1-51d4-415a-b182-d0e8380d976b Co-authored-by: dgee2 <5671841+dgee2@users.noreply.github.com> --- .github/workflows/main.yml | 48 +++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0f35f0ca..f4f0d9e3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -17,6 +17,35 @@ permissions: # Based from https://docs.github.com/en/actions/use-cases-and-examples/building-and-testing/building-and-testing-net jobs: + changes: + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: read + outputs: + backend: ${{ steps.filter.outputs.backend || 'true' }} + frontend: ${{ steps.filter.outputs.frontend || 'true' }} + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Check for file changes + if: github.event_name == 'pull_request' + uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + backend: + - '**.cs' + - '**.csproj' + - '**.sln' + - 'global.json' + - '.github/workflows/main.yml' + frontend: + - 'ui/**' + - 'open-api/**' + - '.github/workflows/main.yml' + dependency-review: if: github.event_name == 'pull_request' runs-on: ubuntu-latest @@ -32,6 +61,10 @@ jobs: backend-build: name: Create OpenAPI spec + needs: changes + if: | + github.event_name != 'pull_request' || + needs.changes.outputs.backend == 'true' runs-on: ubuntu-latest permissions: contents: read @@ -64,6 +97,10 @@ jobs: backend-tests: name: Backend tests + needs: changes + if: | + github.event_name != 'pull_request' || + needs.changes.outputs.backend == 'true' runs-on: ubuntu-latest permissions: contents: read @@ -93,6 +130,10 @@ jobs: backend-integration-tests: name: Backend integration tests + needs: changes + if: | + github.event_name != 'pull_request' || + needs.changes.outputs.backend == 'true' runs-on: ubuntu-latest permissions: contents: read @@ -135,7 +176,11 @@ jobs: frontend: name: Frontend validation runs-on: ubuntu-latest - needs: backend-build + needs: [changes, backend-build] + if: | + !cancelled() && + (github.event_name != 'pull_request' || needs.changes.outputs.frontend == 'true') && + (needs.backend-build.result == 'success' || needs.backend-build.result == 'skipped') permissions: contents: read actions: read @@ -145,6 +190,7 @@ jobs: uses: actions/checkout@v6 - name: Download OpenAPI document + if: needs.backend-build.result == 'success' uses: actions/download-artifact@v4 with: name: openapi-spec From 7bc75e7e85218e59a2fbe45ae7e0b0c666154871 Mon Sep 17 00:00:00 2001 From: "anthropic-code-agent[bot]" <242468646+Claude@users.noreply.github.com> Date: Mon, 20 Apr 2026 08:11:08 +0000 Subject: [PATCH 3/7] Add aspire.config.json to backend filters and documentation Agent-Logs-Url: https://github.com/dgee2/Menu/sessions/769265b1-51d4-415a-b182-d0e8380d976b Co-authored-by: dgee2 <5671841+dgee2@users.noreply.github.com> --- .github/workflows/main.yml | 1 + docs/ci-path-filters.md | 167 +++++++++++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 docs/ci-path-filters.md diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f4f0d9e3..c825bbe0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -40,6 +40,7 @@ jobs: - '**.csproj' - '**.sln' - 'global.json' + - 'aspire.config.json' - '.github/workflows/main.yml' frontend: - 'ui/**' diff --git a/docs/ci-path-filters.md b/docs/ci-path-filters.md new file mode 100644 index 00000000..19ddbab0 --- /dev/null +++ b/docs/ci-path-filters.md @@ -0,0 +1,167 @@ +# CI Path Filters + +## Overview + +The CI workflow uses conservative path filters to skip unaffected work while ensuring no required validation is missed for cross-stack changes. + +## Implementation + +The workflow uses the [dorny/paths-filter](https://github.com/dorny/paths-filter) action to detect which files have changed in pull requests and conditionally runs jobs based on those changes. + +### Path Filter Configuration + +#### Backend Jobs + +Backend jobs (`backend-build`, `backend-tests`, `backend-integration-tests`) run when any of these files change: + +- `**.cs` - All C# source files +- `**.csproj` - All project files +- `**.sln` - Solution files +- `global.json` - .NET SDK version configuration +- `aspire.config.json` - Aspire orchestration configuration +- `.github/workflows/main.yml` - The workflow file itself + +#### Frontend Job + +The frontend job (`frontend`) runs when any of these files change: + +- `ui/**` - Any file in the frontend directory +- `open-api/**` - OpenAPI specification files (triggers type regeneration) +- `.github/workflows/main.yml` - The workflow file itself + +## Behavior by Event Type + +### Pull Requests + +- **Changes detected**: Only jobs matching the changed files run +- **No changes detected**: Jobs are skipped +- **Workflow file changes**: Both frontend and backend jobs run (conservative approach) + +### Push Events (main/master branches) + +- **All jobs always run**: Path filters are only applied to pull requests +- This ensures complete validation on the main branches + +### Workflow Dispatch + +- **All jobs always run**: Manual triggers run complete validation + +## Cross-Stack Scenarios + +### Scenario: Backend-only changes (e.g., only `.cs` files) + +- ✅ Backend jobs run +- ❌ Frontend job is skipped +- The frontend uses the existing OpenAPI spec from the repository + +### Scenario: Frontend-only changes (e.g., only `ui/` files) + +- ❌ Backend jobs are skipped +- ✅ Frontend job runs +- The frontend uses the existing OpenAPI spec from the repository + +### Scenario: OpenAPI contract changes + +- ❌ Backend jobs are skipped (OpenAPI is generated by backend build) +- ✅ Frontend job runs to regenerate types +- **Note**: If the OpenAPI spec is out of sync with the backend, both backend and frontend files should be changed together + +### Scenario: Both backend and frontend changes + +- ✅ Backend jobs run +- ✅ Frontend job runs +- Normal full validation + +### Scenario: Workflow file changes + +- ✅ Backend jobs run +- ✅ Frontend job runs +- Conservative approach to ensure workflow changes don't break validation + +## Frontend Job Dependencies + +The frontend job has special dependency handling: + +```yaml +needs: [changes, backend-build] +if: | + !cancelled() && + (github.event_name != 'pull_request' || needs.changes.outputs.frontend == 'true') && + (needs.backend-build.result == 'success' || needs.backend-build.result == 'skipped') +``` + +This allows the frontend to run even when backend-build is skipped (frontend-only changes), while ensuring it waits for backend-build when it does run. + +### OpenAPI Artifact Handling + +The "Download OpenAPI document" step in the frontend job is conditional: + +```yaml +- name: Download OpenAPI document + if: needs.backend-build.result == 'success' + uses: actions/download-artifact@v4 +``` + +- If backend-build runs and succeeds, the new OpenAPI spec is downloaded +- If backend-build is skipped, the existing OpenAPI spec from the repository is used + +## Performance Benefits + +Path filters improve CI throughput by: + +1. **Reducing build time**: Backend builds (~2-3 minutes) are skipped for frontend-only PRs +2. **Reducing test time**: Backend tests (~1-2 minutes) are skipped for frontend-only PRs +3. **Reducing runner usage**: Skipped jobs don't consume GitHub Actions runner minutes + +### Example Savings + +- **Frontend-only PR**: Saves ~5-7 minutes (skips 3 backend jobs) +- **Backend-only PR**: Saves ~2-3 minutes (skips 1 frontend job) +- **Documentation-only PR**: Saves ~7-10 minutes (skips all build/test jobs, only runs dependency-review) + +## Guardrails + +The implementation includes several guardrails to prevent missing validation: + +1. **Conservative patterns**: Includes critical config files (global.json, aspire.config.json) +2. **Workflow file triggers both**: Changes to the workflow file trigger all jobs +3. **Always run on push**: All jobs run on pushes to main/master branches +4. **Dependency review still runs**: The dependency-review job always runs on PRs regardless of changed files + +## Testing Path Filters + +To test the path filters work correctly: + +1. Create a PR with only backend changes (e.g., modify a `.cs` file) + - Verify backend jobs run and frontend job is skipped + +2. Create a PR with only frontend changes (e.g., modify a `.vue` file) + - Verify frontend job runs and backend jobs are skipped + +3. Create a PR with both backend and frontend changes + - Verify all jobs run + +4. Create a PR with only documentation changes (e.g., modify a `.md` file) + - Verify only dependency-review runs + +## Troubleshooting + +### Jobs unexpectedly skipped + +- Check if the changed files match the path patterns +- Verify the PR is against the correct base branch +- Check if this is a push event (push events always run all jobs) + +### Jobs not being skipped + +- Ensure the event is a pull_request (not push) +- Check if the workflow file was changed (triggers all jobs) +- Verify the paths-filter action is running correctly in the changes job + +### Frontend fails because OpenAPI spec is missing + +This can happen if: +- The backend changed but wasn't included in the PR +- The OpenAPI spec in the repo is out of sync + +**Solution**: Include both backend and frontend changes in the same PR when the OpenAPI contract changes. From 78f078d351e365d4d5d2b6e0d56d9769296090b3 Mon Sep 17 00:00:00 2001 From: "anthropic-code-agent[bot]" <242468646+Claude@users.noreply.github.com> Date: Mon, 20 Apr 2026 08:26:17 +0000 Subject: [PATCH 4/7] Pin paths-filter to commit hash and simplify backend path filters Agent-Logs-Url: https://github.com/dgee2/Menu/sessions/9d95c0f5-e8ab-484c-8eba-8f5ab3a04f14 Co-authored-by: dgee2 <5671841+dgee2@users.noreply.github.com> --- .github/workflows/main.yml | 11 +++++++---- docs/ci-path-filters.md | 13 ++++++++----- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c825bbe0..6e8fc682 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -31,14 +31,17 @@ jobs: - name: Check for file changes if: github.event_name == 'pull_request' - uses: dorny/paths-filter@v3 + uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v3.0.2 id: filter with: filters: | backend: - - '**.cs' - - '**.csproj' - - '**.sln' + - 'Menu.*/**' + - 'MenuApi/**' + - 'MenuApi.Tests/**' + - 'MenuApi.Integration.Tests/**' + - 'MenuDB/**' + - '*.sln' - 'global.json' - 'aspire.config.json' - '.github/workflows/main.yml' diff --git a/docs/ci-path-filters.md b/docs/ci-path-filters.md index 19ddbab0..616b9f72 100644 --- a/docs/ci-path-filters.md +++ b/docs/ci-path-filters.md @@ -12,11 +12,14 @@ The workflow uses the [dorny/paths-filter](https://github.com/dorny/paths-filter #### Backend Jobs -Backend jobs (`backend-build`, `backend-tests`, `backend-integration-tests`) run when any of these files change: - -- `**.cs` - All C# source files -- `**.csproj` - All project files -- `**.sln` - Solution files +Backend jobs (`backend-build`, `backend-tests`, `backend-integration-tests`) run when any of these paths change: + +- `Menu.*/**` - All Menu service projects (Menu.AppHost, Menu.ServiceDefaults, Menu.ApiServiceDefaults, Menu.MigrationService) +- `MenuApi/**` - API project files +- `MenuApi.Tests/**` - Unit test project files +- `MenuApi.Integration.Tests/**` - Integration test project files +- `MenuDB/**` - Database project files +- `*.sln` - Solution files - `global.json` - .NET SDK version configuration - `aspire.config.json` - Aspire orchestration configuration - `.github/workflows/main.yml` - The workflow file itself From 1dcb98a7cb4cb822dd9fd4f972f65d4e8bc406e5 Mon Sep 17 00:00:00 2001 From: "anthropic-code-agent[bot]" <242468646+Claude@users.noreply.github.com> Date: Mon, 20 Apr 2026 08:28:24 +0000 Subject: [PATCH 5/7] Fix copilot review comments on path filters Agent-Logs-Url: https://github.com/dgee2/Menu/sessions/7c7b022c-438b-456a-9086-a6f3e35ebbc4 Co-authored-by: dgee2 <5671841+dgee2@users.noreply.github.com> --- .github/workflows/main.yml | 1 + docs/ci-path-filters.md | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6e8fc682..faaa5d91 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -27,6 +27,7 @@ jobs: frontend: ${{ steps.filter.outputs.frontend || 'true' }} steps: - name: Checkout + if: github.event_name == 'pull_request' uses: actions/checkout@v6 - name: Check for file changes diff --git a/docs/ci-path-filters.md b/docs/ci-path-filters.md index 616b9f72..504ace9a 100644 --- a/docs/ci-path-filters.md +++ b/docs/ci-path-filters.md @@ -37,7 +37,7 @@ The frontend job (`frontend`) runs when any of these files change: ### Pull Requests - **Changes detected**: Only jobs matching the changed files run -- **No changes detected**: Jobs are skipped +- **No changes detected**: Backend/frontend build and test jobs are skipped when no relevant files change - **Workflow file changes**: Both frontend and backend jobs run (conservative approach) ### Push Events (main/master branches) @@ -55,7 +55,7 @@ The frontend job (`frontend`) runs when any of these files change: - ✅ Backend jobs run - ❌ Frontend job is skipped -- The frontend uses the existing OpenAPI spec from the repository +- The checked-in OpenAPI spec in the repository remains unchanged ### Scenario: Frontend-only changes (e.g., only `ui/` files) @@ -120,7 +120,7 @@ Path filters improve CI throughput by: - **Frontend-only PR**: Saves ~5-7 minutes (skips 3 backend jobs) - **Backend-only PR**: Saves ~2-3 minutes (skips 1 frontend job) -- **Documentation-only PR**: Saves ~7-10 minutes (skips all build/test jobs, only runs dependency-review) +- **Documentation-only PR**: Saves ~7-10 minutes (skips all build/test jobs, runs only `changes` and `dependency-review`) ## Guardrails @@ -145,7 +145,7 @@ To test the path filters work correctly: - Verify all jobs run 4. Create a PR with only documentation changes (e.g., modify a `.md` file) - - Verify only dependency-review runs + - Verify the `changes` job runs, `dependency-review` runs, and backend/frontend jobs are skipped ## Troubleshooting From f846b37568c6a3e97e1d467291472cc7ee8adb57 Mon Sep 17 00:00:00 2001 From: Daniel Gee Date: Mon, 20 Apr 2026 22:15:06 +0100 Subject: [PATCH 6/7] Move backend under backend directory Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/main.yml | 17 ++++----- .vscode/settings.json | 4 +-- AGENTS.md | 35 ++++++++++--------- .editorconfig => backend/.editorconfig | 0 .../Menu.ApiServiceDefaults}/Extensions.cs | 0 .../Menu.ApiServiceDefaults.csproj | 0 .../Menu.AppHost}/Menu.AppHost.csproj | 0 .../Menu.AppHost}/Program.cs | 0 .../Properties/launchSettings.json | 0 .../appsettings.Development.json | 0 .../Menu.AppHost}/appsettings.json | 0 .../Menu.MigrationService.csproj | 0 .../Menu.MigrationService}/Program.cs | 0 .../Menu.MigrationService}/Worker.cs | 0 .../Menu.ServiceDefaults}/Extensions.cs | 0 .../Menu.ServiceDefaults.csproj | 0 .../Factory/ApiAuthentication.cs | 0 .../Factory/ApiTestFixture.cs | 0 .../Factory/ShortStringAutoDataAttribute.cs | 0 .../Factory/TestParameters.cs | 0 .../IngredientIntegrationTests.cs | 0 .../MenuApi.Integration.Tests.csproj | 0 ...enuApi.Integration.Tests.v3.ncrunchproject | 0 .../RecipeIntegrationTests.cs | 0 .../RecipeWithIngredientsIntegrationTests.cs | 0 .../ValidationIntegrationTests.cs | 0 .../Controllers/RecipeApiTests.cs | 0 .../MenuApi.Tests}/CustomAutoDataAttribute.cs | 0 .../MenuApi.Tests}/CustomGenerator.cs | 0 .../MenuApi.Tests}/MenuApi.Tests.csproj | 0 .../Services/RecipeServiceTests.cs | 0 .../Validation/NewIngredientValidatorTests.cs | 0 .../Validation/NewRecipeValidatorTests.cs | 0 .../RecipeIngredientValidatorTests.cs | 0 .../Validation/ValidationFilterTests.cs | 0 .../MenuApi.lutconfig | 0 MenuApi.sln => backend/MenuApi.sln | 0 .../MenuApi.v3.ncrunchsolution | 0 .../MenuApi}/DBModel/GetRecipeIngredient.cs | 0 .../MenuApi}/DBModel/Ingredient.cs | 0 .../MenuApi}/DBModel/IngredientUnit.cs | 0 .../MenuApi}/DBModel/Recipe.cs | 0 .../MenuApi}/DBModel/RecipeIngredient.cs | 0 .../Exceptions/BusinessValidationException.cs | 0 .../BusinessValidationExceptionHandler.cs | 0 .../MenuApi}/GlobalSuppressions.cs | 0 .../MappingProfiles/ViewModelMapper.cs | 0 {MenuApi => backend/MenuApi}/MenuApi.csproj | 2 +- {MenuApi => backend/MenuApi}/Program.cs | 0 .../local/appInsights1.arm.json | 0 .../MenuApi}/Properties/launchSettings.json | 0 .../Properties/serviceDependencies.json | 0 .../Properties/serviceDependencies.local.json | 0 .../MenuApi}/Recipes/IngredientApi.cs | 0 .../MenuApi}/Recipes/RecipeApi.cs | 0 .../Repositories/IIngredientRepository.cs | 0 .../Repositories/IRecipeRepository.cs | 0 .../MenuApi}/Repositories/IUnitRepository.cs | 0 .../Repositories/IngredientRepository.cs | 0 .../MenuApi}/Repositories/RecipeRepository.cs | 0 .../MenuApi}/Repositories/UnitRepository.cs | 0 .../MenuApi}/Services/IIngredientService.cs | 0 .../MenuApi}/Services/IRecipeService.cs | 0 .../MenuApi}/Services/IngredientService.cs | 0 .../MenuApi}/Services/RecipeService.cs | 0 .../Validation/NewIngredientValidator.cs | 0 .../MenuApi}/Validation/NewRecipeValidator.cs | 0 .../Validation/RecipeIngredientValidator.cs | 0 .../MenuApi}/Validation/ValidationFilter.cs | 0 .../Validation/VogenValidationRules.cs | 0 .../MenuApi}/ValueObjects/Ingredient.cs | 0 .../MenuApi}/ValueObjects/IngredientUnit.cs | 0 .../MenuApi}/ValueObjects/Recipe.cs | 0 .../MenuApi}/ValueObjects/ValueObject.cs | 0 .../MenuApi}/ViewModel/FullRecipe.cs | 0 .../MenuApi}/ViewModel/Ingredient.cs | 0 .../MenuApi}/ViewModel/IngredientUnit.cs | 0 .../MenuApi}/ViewModel/NewIngredient.cs | 0 .../MenuApi}/ViewModel/NewRecipe.cs | 0 .../MenuApi}/ViewModel/Recipe.cs | 0 .../MenuApi}/ViewModel/RecipeIngredient.cs | 0 {MenuApi => backend/MenuApi}/VogenDefaults.cs | 0 .../MenuApi}/appsettings.Development.json | 0 {MenuApi => backend/MenuApi}/appsettings.json | 0 {MenuApi => backend/MenuApi}/libman.json | 0 {MenuApi => backend/MenuApi}/stylecop.json | 0 .../MenuDB}/Data/IngredientEntity.cs | 0 .../MenuDB}/Data/IngredientUnitEntity.cs | 0 .../MenuDB}/Data/RecipeEntity.cs | 0 .../MenuDB}/Data/RecipeIngredientEntity.cs | 0 {MenuDB => backend/MenuDB}/Data/UnitEntity.cs | 0 .../MenuDB}/Data/UnitTypeEntity.cs | 0 {MenuDB => backend/MenuDB}/MenuDB.csproj | 0 {MenuDB => backend/MenuDB}/MenuDbContext.cs | 0 .../MenuDB}/MenuDbContextFactory.cs | 0 .../20260307231933_InitialCreate.Designer.cs | 0 .../20260307231933_InitialCreate.cs | 0 .../Migrations/MenuDbContextModelSnapshot.cs | 0 .../aspire.config.json | 0 global.json => backend/global.json | 0 docs/ci-path-filters.md | 13 ++----- docs/database-migrations.md | 8 ++--- docs/integration-tests.md | 6 ++-- docs/specs/api-validation.md | 2 +- 104 files changed, 41 insertions(+), 46 deletions(-) rename .editorconfig => backend/.editorconfig (100%) rename {Menu.ApiServiceDefaults => backend/Menu.ApiServiceDefaults}/Extensions.cs (100%) rename {Menu.ApiServiceDefaults => backend/Menu.ApiServiceDefaults}/Menu.ApiServiceDefaults.csproj (100%) rename {Menu.AppHost => backend/Menu.AppHost}/Menu.AppHost.csproj (100%) rename {Menu.AppHost => backend/Menu.AppHost}/Program.cs (100%) rename {Menu.AppHost => backend/Menu.AppHost}/Properties/launchSettings.json (100%) rename {Menu.AppHost => backend/Menu.AppHost}/appsettings.Development.json (100%) rename {Menu.AppHost => backend/Menu.AppHost}/appsettings.json (100%) rename {Menu.MigrationService => backend/Menu.MigrationService}/Menu.MigrationService.csproj (100%) rename {Menu.MigrationService => backend/Menu.MigrationService}/Program.cs (100%) rename {Menu.MigrationService => backend/Menu.MigrationService}/Worker.cs (100%) rename {Menu.ServiceDefaults => backend/Menu.ServiceDefaults}/Extensions.cs (100%) rename {Menu.ServiceDefaults => backend/Menu.ServiceDefaults}/Menu.ServiceDefaults.csproj (100%) rename {MenuApi.Integration.Tests => backend/MenuApi.Integration.Tests}/Factory/ApiAuthentication.cs (100%) rename {MenuApi.Integration.Tests => backend/MenuApi.Integration.Tests}/Factory/ApiTestFixture.cs (100%) rename {MenuApi.Integration.Tests => backend/MenuApi.Integration.Tests}/Factory/ShortStringAutoDataAttribute.cs (100%) rename {MenuApi.Integration.Tests => backend/MenuApi.Integration.Tests}/Factory/TestParameters.cs (100%) rename {MenuApi.Integration.Tests => backend/MenuApi.Integration.Tests}/IngredientIntegrationTests.cs (100%) rename {MenuApi.Integration.Tests => backend/MenuApi.Integration.Tests}/MenuApi.Integration.Tests.csproj (100%) rename {MenuApi.Integration.Tests => backend/MenuApi.Integration.Tests}/MenuApi.Integration.Tests.v3.ncrunchproject (100%) rename {MenuApi.Integration.Tests => backend/MenuApi.Integration.Tests}/RecipeIntegrationTests.cs (100%) rename {MenuApi.Integration.Tests => backend/MenuApi.Integration.Tests}/RecipeWithIngredientsIntegrationTests.cs (100%) rename {MenuApi.Integration.Tests => backend/MenuApi.Integration.Tests}/ValidationIntegrationTests.cs (100%) rename {MenuApi.Tests => backend/MenuApi.Tests}/Controllers/RecipeApiTests.cs (100%) rename {MenuApi.Tests => backend/MenuApi.Tests}/CustomAutoDataAttribute.cs (100%) rename {MenuApi.Tests => backend/MenuApi.Tests}/CustomGenerator.cs (100%) rename {MenuApi.Tests => backend/MenuApi.Tests}/MenuApi.Tests.csproj (100%) rename {MenuApi.Tests => backend/MenuApi.Tests}/Services/RecipeServiceTests.cs (100%) rename {MenuApi.Tests => backend/MenuApi.Tests}/Validation/NewIngredientValidatorTests.cs (100%) rename {MenuApi.Tests => backend/MenuApi.Tests}/Validation/NewRecipeValidatorTests.cs (100%) rename {MenuApi.Tests => backend/MenuApi.Tests}/Validation/RecipeIngredientValidatorTests.cs (100%) rename {MenuApi.Tests => backend/MenuApi.Tests}/Validation/ValidationFilterTests.cs (100%) rename MenuApi.lutconfig => backend/MenuApi.lutconfig (100%) rename MenuApi.sln => backend/MenuApi.sln (100%) rename MenuApi.v3.ncrunchsolution => backend/MenuApi.v3.ncrunchsolution (100%) rename {MenuApi => backend/MenuApi}/DBModel/GetRecipeIngredient.cs (100%) rename {MenuApi => backend/MenuApi}/DBModel/Ingredient.cs (100%) rename {MenuApi => backend/MenuApi}/DBModel/IngredientUnit.cs (100%) rename {MenuApi => backend/MenuApi}/DBModel/Recipe.cs (100%) rename {MenuApi => backend/MenuApi}/DBModel/RecipeIngredient.cs (100%) rename {MenuApi => backend/MenuApi}/Exceptions/BusinessValidationException.cs (100%) rename {MenuApi => backend/MenuApi}/Exceptions/BusinessValidationExceptionHandler.cs (100%) rename {MenuApi => backend/MenuApi}/GlobalSuppressions.cs (100%) rename {MenuApi => backend/MenuApi}/MappingProfiles/ViewModelMapper.cs (100%) rename {MenuApi => backend/MenuApi}/MenuApi.csproj (97%) rename {MenuApi => backend/MenuApi}/Program.cs (100%) rename {MenuApi => backend/MenuApi}/Properties/ServiceDependencies/local/appInsights1.arm.json (100%) rename {MenuApi => backend/MenuApi}/Properties/launchSettings.json (100%) rename {MenuApi => backend/MenuApi}/Properties/serviceDependencies.json (100%) rename {MenuApi => backend/MenuApi}/Properties/serviceDependencies.local.json (100%) rename {MenuApi => backend/MenuApi}/Recipes/IngredientApi.cs (100%) rename {MenuApi => backend/MenuApi}/Recipes/RecipeApi.cs (100%) rename {MenuApi => backend/MenuApi}/Repositories/IIngredientRepository.cs (100%) rename {MenuApi => backend/MenuApi}/Repositories/IRecipeRepository.cs (100%) rename {MenuApi => backend/MenuApi}/Repositories/IUnitRepository.cs (100%) rename {MenuApi => backend/MenuApi}/Repositories/IngredientRepository.cs (100%) rename {MenuApi => backend/MenuApi}/Repositories/RecipeRepository.cs (100%) rename {MenuApi => backend/MenuApi}/Repositories/UnitRepository.cs (100%) rename {MenuApi => backend/MenuApi}/Services/IIngredientService.cs (100%) rename {MenuApi => backend/MenuApi}/Services/IRecipeService.cs (100%) rename {MenuApi => backend/MenuApi}/Services/IngredientService.cs (100%) rename {MenuApi => backend/MenuApi}/Services/RecipeService.cs (100%) rename {MenuApi => backend/MenuApi}/Validation/NewIngredientValidator.cs (100%) rename {MenuApi => backend/MenuApi}/Validation/NewRecipeValidator.cs (100%) rename {MenuApi => backend/MenuApi}/Validation/RecipeIngredientValidator.cs (100%) rename {MenuApi => backend/MenuApi}/Validation/ValidationFilter.cs (100%) rename {MenuApi => backend/MenuApi}/Validation/VogenValidationRules.cs (100%) rename {MenuApi => backend/MenuApi}/ValueObjects/Ingredient.cs (100%) rename {MenuApi => backend/MenuApi}/ValueObjects/IngredientUnit.cs (100%) rename {MenuApi => backend/MenuApi}/ValueObjects/Recipe.cs (100%) rename {MenuApi => backend/MenuApi}/ValueObjects/ValueObject.cs (100%) rename {MenuApi => backend/MenuApi}/ViewModel/FullRecipe.cs (100%) rename {MenuApi => backend/MenuApi}/ViewModel/Ingredient.cs (100%) rename {MenuApi => backend/MenuApi}/ViewModel/IngredientUnit.cs (100%) rename {MenuApi => backend/MenuApi}/ViewModel/NewIngredient.cs (100%) rename {MenuApi => backend/MenuApi}/ViewModel/NewRecipe.cs (100%) rename {MenuApi => backend/MenuApi}/ViewModel/Recipe.cs (100%) rename {MenuApi => backend/MenuApi}/ViewModel/RecipeIngredient.cs (100%) rename {MenuApi => backend/MenuApi}/VogenDefaults.cs (100%) rename {MenuApi => backend/MenuApi}/appsettings.Development.json (100%) rename {MenuApi => backend/MenuApi}/appsettings.json (100%) rename {MenuApi => backend/MenuApi}/libman.json (100%) rename {MenuApi => backend/MenuApi}/stylecop.json (100%) rename {MenuDB => backend/MenuDB}/Data/IngredientEntity.cs (100%) rename {MenuDB => backend/MenuDB}/Data/IngredientUnitEntity.cs (100%) rename {MenuDB => backend/MenuDB}/Data/RecipeEntity.cs (100%) rename {MenuDB => backend/MenuDB}/Data/RecipeIngredientEntity.cs (100%) rename {MenuDB => backend/MenuDB}/Data/UnitEntity.cs (100%) rename {MenuDB => backend/MenuDB}/Data/UnitTypeEntity.cs (100%) rename {MenuDB => backend/MenuDB}/MenuDB.csproj (100%) rename {MenuDB => backend/MenuDB}/MenuDbContext.cs (100%) rename {MenuDB => backend/MenuDB}/MenuDbContextFactory.cs (100%) rename {MenuDB => backend/MenuDB}/Migrations/20260307231933_InitialCreate.Designer.cs (100%) rename {MenuDB => backend/MenuDB}/Migrations/20260307231933_InitialCreate.cs (100%) rename {MenuDB => backend/MenuDB}/Migrations/MenuDbContextModelSnapshot.cs (100%) rename aspire.config.json => backend/aspire.config.json (100%) rename global.json => backend/global.json (100%) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 64ac5566..3b66fd40 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -37,14 +37,7 @@ jobs: with: filters: | backend: - - 'Menu.*/**' - - 'MenuApi/**' - - 'MenuApi.Tests/**' - - 'MenuApi.Integration.Tests/**' - - 'MenuDB/**' - - '*.sln' - - 'global.json' - - 'aspire.config.json' + - 'backend/**' - '.github/workflows/main.yml' frontend: - 'ui/**' @@ -89,9 +82,11 @@ jobs: - name: Restore run: dotnet restore MenuApi.sln + working-directory: ./backend - name: Build solution (generate OpenAPI) run: dotnet build MenuApi.sln --configuration Release --no-restore + working-directory: ./backend - name: Upload OpenAPI document uses: actions/upload-artifact@v4 @@ -125,12 +120,15 @@ jobs: - name: Restore run: dotnet restore MenuApi.sln + working-directory: ./backend - name: Build solution (generate OpenAPI) run: dotnet build MenuApi.sln --configuration Release --no-restore + working-directory: ./backend - name: Test with the dotnet CLI run: dotnet test --project MenuApi.Tests/MenuApi.Tests.csproj --configuration Release --no-build + working-directory: ./backend backend-integration-tests: @@ -158,9 +156,11 @@ jobs: - name: Restore run: dotnet restore MenuApi.sln + working-directory: ./backend - name: Build solution (generate OpenAPI) run: dotnet build MenuApi.sln --configuration Release --no-restore + working-directory: ./backend - name: clean ssl cert run: dotnet dev-certs https --clean @@ -172,6 +172,7 @@ jobs: - name: Test with the dotnet CLI run: dotnet test --project MenuApi.Integration.Tests/MenuApi.Integration.Tests.csproj --configuration Release --no-build + working-directory: ./backend env: parameters__Auth0TestClientId: ${{ vars.AUTH0_CLIENT_ID }} parameters__Auth0TestClientSecret: ${{ secrets.AUTH0_CLIENT_SECRET }} diff --git a/.vscode/settings.json b/.vscode/settings.json index a4c4bee6..bad6e73f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,7 @@ { - "dotnet.defaultSolution": "MenuApi.sln", + "dotnet.defaultSolution": "backend/MenuApi.sln", "sonarlint.connectedMode.project": { "connectionId": "dgee2-github", "projectKey": "dgee2_Menu" } -} \ No newline at end of file +} diff --git a/AGENTS.md b/AGENTS.md index d6f3fcb6..78a9812b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,10 +2,10 @@ ## Architecture -.NET Aspire distributed app (net10.0) for recipe/menu management. `Menu.AppHost` orchestrates all services: +.NET Aspire distributed app (net10.0) for recipe/menu management. Backend projects live under `backend/`, and `backend/Menu.AppHost` orchestrates all services: -- **MenuApi** – Minimal API (Auth0 JWT-secured). Endpoints defined via `MapGroup` extensions in `MenuApi/Recipes/`. -- **MenuDB** – EF Core `MenuDbContext` + entity definitions (`MenuDB/Data/`) + migrations (`MenuDB/Migrations/`). +- **MenuApi** – Minimal API (Auth0 JWT-secured). Endpoints defined via `MapGroup` extensions in `backend/MenuApi/Recipes/`. +- **MenuDB** – EF Core `MenuDbContext` + entity definitions (`backend/MenuDB/Data/`) + migrations (`backend/MenuDB/Migrations/`). - **Menu.MigrationService** – BackgroundService that applies EF migrations on startup, then exits. The API (`MenuApi`) waits for this to complete before starting (`WaitForCompletion`). - **Redis** – `AddRedis("cache")` resource for caching. - **Menu.ServiceDefaults / Menu.ApiServiceDefaults** – Shared Aspire service defaults (OpenTelemetry, health checks, Swagger). @@ -17,15 +17,15 @@ Three distinct model layers — never mix them: | Layer | Namespace / Location | Purpose | |---|---|---| -| **EF Entities** | `MenuDB/Data/` (e.g. `RecipeEntity`) | Database rows; configured in `MenuDbContext.OnModelCreating` | -| **DB Models** | `MenuApi/DBModel/` (e.g. `DBModel.Recipe`) | Intermediate records using Vogen value objects; returned by repositories | -| **ViewModels** | `MenuApi/ViewModel/` (e.g. `ViewModel.Recipe`, `NewRecipe`, `FullRecipe`) | API request/response DTOs | +| **EF Entities** | `backend/MenuDB/Data/` (e.g. `RecipeEntity`) | Database rows; configured in `MenuDbContext.OnModelCreating` | +| **DB Models** | `backend/MenuApi/DBModel/` (e.g. `DBModel.Recipe`) | Intermediate records using Vogen value objects; returned by repositories | +| **ViewModels** | `backend/MenuApi/ViewModel/` (e.g. `ViewModel.Recipe`, `NewRecipe`, `FullRecipe`) | API request/response DTOs | -Mapping between layers uses **Riok.Mapperly** (source-generated, zero-reflection) in `MenuApi/MappingProfiles/ViewModelMapper.cs`. When adding properties, update the `[MapProperty]` attributes there. +Mapping between layers uses **Riok.Mapperly** (source-generated, zero-reflection) in `backend/MenuApi/MappingProfiles/ViewModelMapper.cs`. When adding properties, update the `[MapProperty]` attributes there. ## Vogen Value Objects -Primitive types are wrapped with [Vogen](https://github.com/SteveDunn/Vogen) (`MenuApi/ValueObjects/`). Example: `RecipeId`, `RecipeName`, `IngredientAmount`. Assembly-wide defaults in `VogenDefaults.cs` enable EF Core value converters and Swagger mapping. When creating a new value object: +Primitive types are wrapped with [Vogen](https://github.com/SteveDunn/Vogen) (`backend/MenuApi/ValueObjects/`). Example: `RecipeId`, `RecipeName`, `IngredientAmount`. Assembly-wide defaults in `VogenDefaults.cs` enable EF Core value converters and Swagger mapping. When creating a new value object: ```csharp [ValueObject] @@ -38,9 +38,10 @@ Repositories must use `.Value` to unwrap and `TypeName.From(x)` to wrap. ```bash # Run the full stack (API + SQL container + migrations + UI) +cd backend dotnet run --project Menu.AppHost -# EF migrations (always from solution root) +# EF migrations (always from the backend solution root) dotnet ef migrations add --project MenuDB --startup-project MenuApi dotnet ef migrations remove --project MenuDB --startup-project MenuApi @@ -60,7 +61,7 @@ dotnet test MenuApi.Integration.Tests ## Code Style - `TreatWarningsAsErrors` is enabled in Debug and Release for all projects. -- StyleCop is configured via `MenuApi/stylecop.json`. +- StyleCop is configured via `backend/MenuApi/stylecop.json`. - `ConfigureAwait(false)` is used on all async calls in service/repository layers. - `Program.cs` exposes a `public partial class Program` for integration test `WebApplicationFactory` compatibility. @@ -138,10 +139,10 @@ pnpm storybook # Storybook dev server (port 6006) ## Adding a New API Endpoint -1. Add ViewModel DTOs in `MenuApi/ViewModel/`. -2. Add DB model records in `MenuApi/DBModel/` (if new data shapes are needed). -3. Add/update Mapperly mappings in `MenuApi/MappingProfiles/ViewModelMapper.cs`. -4. Add repository method (interface in `MenuApi/Repositories/I*Repository.cs`, impl in `*Repository.cs`). -5. Add service method (interface + impl in `MenuApi/Services/`). -6. Add the endpoint in the relevant `MenuApi/Recipes/*Api.cs` file using the `MapGroup` pattern. -7. Register new DI services in `MenuApi/Program.cs`. +1. Add ViewModel DTOs in `backend/MenuApi/ViewModel/`. +2. Add DB model records in `backend/MenuApi/DBModel/` (if new data shapes are needed). +3. Add/update Mapperly mappings in `backend/MenuApi/MappingProfiles/ViewModelMapper.cs`. +4. Add repository method (interface in `backend/MenuApi/Repositories/I*Repository.cs`, impl in `*Repository.cs`). +5. Add service method (interface + impl in `backend/MenuApi/Services/`). +6. Add the endpoint in the relevant `backend/MenuApi/Recipes/*Api.cs` file using the `MapGroup` pattern. +7. Register new DI services in `backend/MenuApi/Program.cs`. diff --git a/.editorconfig b/backend/.editorconfig similarity index 100% rename from .editorconfig rename to backend/.editorconfig diff --git a/Menu.ApiServiceDefaults/Extensions.cs b/backend/Menu.ApiServiceDefaults/Extensions.cs similarity index 100% rename from Menu.ApiServiceDefaults/Extensions.cs rename to backend/Menu.ApiServiceDefaults/Extensions.cs diff --git a/Menu.ApiServiceDefaults/Menu.ApiServiceDefaults.csproj b/backend/Menu.ApiServiceDefaults/Menu.ApiServiceDefaults.csproj similarity index 100% rename from Menu.ApiServiceDefaults/Menu.ApiServiceDefaults.csproj rename to backend/Menu.ApiServiceDefaults/Menu.ApiServiceDefaults.csproj diff --git a/Menu.AppHost/Menu.AppHost.csproj b/backend/Menu.AppHost/Menu.AppHost.csproj similarity index 100% rename from Menu.AppHost/Menu.AppHost.csproj rename to backend/Menu.AppHost/Menu.AppHost.csproj diff --git a/Menu.AppHost/Program.cs b/backend/Menu.AppHost/Program.cs similarity index 100% rename from Menu.AppHost/Program.cs rename to backend/Menu.AppHost/Program.cs diff --git a/Menu.AppHost/Properties/launchSettings.json b/backend/Menu.AppHost/Properties/launchSettings.json similarity index 100% rename from Menu.AppHost/Properties/launchSettings.json rename to backend/Menu.AppHost/Properties/launchSettings.json diff --git a/Menu.AppHost/appsettings.Development.json b/backend/Menu.AppHost/appsettings.Development.json similarity index 100% rename from Menu.AppHost/appsettings.Development.json rename to backend/Menu.AppHost/appsettings.Development.json diff --git a/Menu.AppHost/appsettings.json b/backend/Menu.AppHost/appsettings.json similarity index 100% rename from Menu.AppHost/appsettings.json rename to backend/Menu.AppHost/appsettings.json diff --git a/Menu.MigrationService/Menu.MigrationService.csproj b/backend/Menu.MigrationService/Menu.MigrationService.csproj similarity index 100% rename from Menu.MigrationService/Menu.MigrationService.csproj rename to backend/Menu.MigrationService/Menu.MigrationService.csproj diff --git a/Menu.MigrationService/Program.cs b/backend/Menu.MigrationService/Program.cs similarity index 100% rename from Menu.MigrationService/Program.cs rename to backend/Menu.MigrationService/Program.cs diff --git a/Menu.MigrationService/Worker.cs b/backend/Menu.MigrationService/Worker.cs similarity index 100% rename from Menu.MigrationService/Worker.cs rename to backend/Menu.MigrationService/Worker.cs diff --git a/Menu.ServiceDefaults/Extensions.cs b/backend/Menu.ServiceDefaults/Extensions.cs similarity index 100% rename from Menu.ServiceDefaults/Extensions.cs rename to backend/Menu.ServiceDefaults/Extensions.cs diff --git a/Menu.ServiceDefaults/Menu.ServiceDefaults.csproj b/backend/Menu.ServiceDefaults/Menu.ServiceDefaults.csproj similarity index 100% rename from Menu.ServiceDefaults/Menu.ServiceDefaults.csproj rename to backend/Menu.ServiceDefaults/Menu.ServiceDefaults.csproj diff --git a/MenuApi.Integration.Tests/Factory/ApiAuthentication.cs b/backend/MenuApi.Integration.Tests/Factory/ApiAuthentication.cs similarity index 100% rename from MenuApi.Integration.Tests/Factory/ApiAuthentication.cs rename to backend/MenuApi.Integration.Tests/Factory/ApiAuthentication.cs diff --git a/MenuApi.Integration.Tests/Factory/ApiTestFixture.cs b/backend/MenuApi.Integration.Tests/Factory/ApiTestFixture.cs similarity index 100% rename from MenuApi.Integration.Tests/Factory/ApiTestFixture.cs rename to backend/MenuApi.Integration.Tests/Factory/ApiTestFixture.cs diff --git a/MenuApi.Integration.Tests/Factory/ShortStringAutoDataAttribute.cs b/backend/MenuApi.Integration.Tests/Factory/ShortStringAutoDataAttribute.cs similarity index 100% rename from MenuApi.Integration.Tests/Factory/ShortStringAutoDataAttribute.cs rename to backend/MenuApi.Integration.Tests/Factory/ShortStringAutoDataAttribute.cs diff --git a/MenuApi.Integration.Tests/Factory/TestParameters.cs b/backend/MenuApi.Integration.Tests/Factory/TestParameters.cs similarity index 100% rename from MenuApi.Integration.Tests/Factory/TestParameters.cs rename to backend/MenuApi.Integration.Tests/Factory/TestParameters.cs diff --git a/MenuApi.Integration.Tests/IngredientIntegrationTests.cs b/backend/MenuApi.Integration.Tests/IngredientIntegrationTests.cs similarity index 100% rename from MenuApi.Integration.Tests/IngredientIntegrationTests.cs rename to backend/MenuApi.Integration.Tests/IngredientIntegrationTests.cs diff --git a/MenuApi.Integration.Tests/MenuApi.Integration.Tests.csproj b/backend/MenuApi.Integration.Tests/MenuApi.Integration.Tests.csproj similarity index 100% rename from MenuApi.Integration.Tests/MenuApi.Integration.Tests.csproj rename to backend/MenuApi.Integration.Tests/MenuApi.Integration.Tests.csproj diff --git a/MenuApi.Integration.Tests/MenuApi.Integration.Tests.v3.ncrunchproject b/backend/MenuApi.Integration.Tests/MenuApi.Integration.Tests.v3.ncrunchproject similarity index 100% rename from MenuApi.Integration.Tests/MenuApi.Integration.Tests.v3.ncrunchproject rename to backend/MenuApi.Integration.Tests/MenuApi.Integration.Tests.v3.ncrunchproject diff --git a/MenuApi.Integration.Tests/RecipeIntegrationTests.cs b/backend/MenuApi.Integration.Tests/RecipeIntegrationTests.cs similarity index 100% rename from MenuApi.Integration.Tests/RecipeIntegrationTests.cs rename to backend/MenuApi.Integration.Tests/RecipeIntegrationTests.cs diff --git a/MenuApi.Integration.Tests/RecipeWithIngredientsIntegrationTests.cs b/backend/MenuApi.Integration.Tests/RecipeWithIngredientsIntegrationTests.cs similarity index 100% rename from MenuApi.Integration.Tests/RecipeWithIngredientsIntegrationTests.cs rename to backend/MenuApi.Integration.Tests/RecipeWithIngredientsIntegrationTests.cs diff --git a/MenuApi.Integration.Tests/ValidationIntegrationTests.cs b/backend/MenuApi.Integration.Tests/ValidationIntegrationTests.cs similarity index 100% rename from MenuApi.Integration.Tests/ValidationIntegrationTests.cs rename to backend/MenuApi.Integration.Tests/ValidationIntegrationTests.cs diff --git a/MenuApi.Tests/Controllers/RecipeApiTests.cs b/backend/MenuApi.Tests/Controllers/RecipeApiTests.cs similarity index 100% rename from MenuApi.Tests/Controllers/RecipeApiTests.cs rename to backend/MenuApi.Tests/Controllers/RecipeApiTests.cs diff --git a/MenuApi.Tests/CustomAutoDataAttribute.cs b/backend/MenuApi.Tests/CustomAutoDataAttribute.cs similarity index 100% rename from MenuApi.Tests/CustomAutoDataAttribute.cs rename to backend/MenuApi.Tests/CustomAutoDataAttribute.cs diff --git a/MenuApi.Tests/CustomGenerator.cs b/backend/MenuApi.Tests/CustomGenerator.cs similarity index 100% rename from MenuApi.Tests/CustomGenerator.cs rename to backend/MenuApi.Tests/CustomGenerator.cs diff --git a/MenuApi.Tests/MenuApi.Tests.csproj b/backend/MenuApi.Tests/MenuApi.Tests.csproj similarity index 100% rename from MenuApi.Tests/MenuApi.Tests.csproj rename to backend/MenuApi.Tests/MenuApi.Tests.csproj diff --git a/MenuApi.Tests/Services/RecipeServiceTests.cs b/backend/MenuApi.Tests/Services/RecipeServiceTests.cs similarity index 100% rename from MenuApi.Tests/Services/RecipeServiceTests.cs rename to backend/MenuApi.Tests/Services/RecipeServiceTests.cs diff --git a/MenuApi.Tests/Validation/NewIngredientValidatorTests.cs b/backend/MenuApi.Tests/Validation/NewIngredientValidatorTests.cs similarity index 100% rename from MenuApi.Tests/Validation/NewIngredientValidatorTests.cs rename to backend/MenuApi.Tests/Validation/NewIngredientValidatorTests.cs diff --git a/MenuApi.Tests/Validation/NewRecipeValidatorTests.cs b/backend/MenuApi.Tests/Validation/NewRecipeValidatorTests.cs similarity index 100% rename from MenuApi.Tests/Validation/NewRecipeValidatorTests.cs rename to backend/MenuApi.Tests/Validation/NewRecipeValidatorTests.cs diff --git a/MenuApi.Tests/Validation/RecipeIngredientValidatorTests.cs b/backend/MenuApi.Tests/Validation/RecipeIngredientValidatorTests.cs similarity index 100% rename from MenuApi.Tests/Validation/RecipeIngredientValidatorTests.cs rename to backend/MenuApi.Tests/Validation/RecipeIngredientValidatorTests.cs diff --git a/MenuApi.Tests/Validation/ValidationFilterTests.cs b/backend/MenuApi.Tests/Validation/ValidationFilterTests.cs similarity index 100% rename from MenuApi.Tests/Validation/ValidationFilterTests.cs rename to backend/MenuApi.Tests/Validation/ValidationFilterTests.cs diff --git a/MenuApi.lutconfig b/backend/MenuApi.lutconfig similarity index 100% rename from MenuApi.lutconfig rename to backend/MenuApi.lutconfig diff --git a/MenuApi.sln b/backend/MenuApi.sln similarity index 100% rename from MenuApi.sln rename to backend/MenuApi.sln diff --git a/MenuApi.v3.ncrunchsolution b/backend/MenuApi.v3.ncrunchsolution similarity index 100% rename from MenuApi.v3.ncrunchsolution rename to backend/MenuApi.v3.ncrunchsolution diff --git a/MenuApi/DBModel/GetRecipeIngredient.cs b/backend/MenuApi/DBModel/GetRecipeIngredient.cs similarity index 100% rename from MenuApi/DBModel/GetRecipeIngredient.cs rename to backend/MenuApi/DBModel/GetRecipeIngredient.cs diff --git a/MenuApi/DBModel/Ingredient.cs b/backend/MenuApi/DBModel/Ingredient.cs similarity index 100% rename from MenuApi/DBModel/Ingredient.cs rename to backend/MenuApi/DBModel/Ingredient.cs diff --git a/MenuApi/DBModel/IngredientUnit.cs b/backend/MenuApi/DBModel/IngredientUnit.cs similarity index 100% rename from MenuApi/DBModel/IngredientUnit.cs rename to backend/MenuApi/DBModel/IngredientUnit.cs diff --git a/MenuApi/DBModel/Recipe.cs b/backend/MenuApi/DBModel/Recipe.cs similarity index 100% rename from MenuApi/DBModel/Recipe.cs rename to backend/MenuApi/DBModel/Recipe.cs diff --git a/MenuApi/DBModel/RecipeIngredient.cs b/backend/MenuApi/DBModel/RecipeIngredient.cs similarity index 100% rename from MenuApi/DBModel/RecipeIngredient.cs rename to backend/MenuApi/DBModel/RecipeIngredient.cs diff --git a/MenuApi/Exceptions/BusinessValidationException.cs b/backend/MenuApi/Exceptions/BusinessValidationException.cs similarity index 100% rename from MenuApi/Exceptions/BusinessValidationException.cs rename to backend/MenuApi/Exceptions/BusinessValidationException.cs diff --git a/MenuApi/Exceptions/BusinessValidationExceptionHandler.cs b/backend/MenuApi/Exceptions/BusinessValidationExceptionHandler.cs similarity index 100% rename from MenuApi/Exceptions/BusinessValidationExceptionHandler.cs rename to backend/MenuApi/Exceptions/BusinessValidationExceptionHandler.cs diff --git a/MenuApi/GlobalSuppressions.cs b/backend/MenuApi/GlobalSuppressions.cs similarity index 100% rename from MenuApi/GlobalSuppressions.cs rename to backend/MenuApi/GlobalSuppressions.cs diff --git a/MenuApi/MappingProfiles/ViewModelMapper.cs b/backend/MenuApi/MappingProfiles/ViewModelMapper.cs similarity index 100% rename from MenuApi/MappingProfiles/ViewModelMapper.cs rename to backend/MenuApi/MappingProfiles/ViewModelMapper.cs diff --git a/MenuApi/MenuApi.csproj b/backend/MenuApi/MenuApi.csproj similarity index 97% rename from MenuApi/MenuApi.csproj rename to backend/MenuApi/MenuApi.csproj index d34781c6..b3a43f89 100644 --- a/MenuApi/MenuApi.csproj +++ b/backend/MenuApi/MenuApi.csproj @@ -58,7 +58,7 @@ - ../open-api + ../../open-api --file-name menu-api diff --git a/MenuApi/Program.cs b/backend/MenuApi/Program.cs similarity index 100% rename from MenuApi/Program.cs rename to backend/MenuApi/Program.cs diff --git a/MenuApi/Properties/ServiceDependencies/local/appInsights1.arm.json b/backend/MenuApi/Properties/ServiceDependencies/local/appInsights1.arm.json similarity index 100% rename from MenuApi/Properties/ServiceDependencies/local/appInsights1.arm.json rename to backend/MenuApi/Properties/ServiceDependencies/local/appInsights1.arm.json diff --git a/MenuApi/Properties/launchSettings.json b/backend/MenuApi/Properties/launchSettings.json similarity index 100% rename from MenuApi/Properties/launchSettings.json rename to backend/MenuApi/Properties/launchSettings.json diff --git a/MenuApi/Properties/serviceDependencies.json b/backend/MenuApi/Properties/serviceDependencies.json similarity index 100% rename from MenuApi/Properties/serviceDependencies.json rename to backend/MenuApi/Properties/serviceDependencies.json diff --git a/MenuApi/Properties/serviceDependencies.local.json b/backend/MenuApi/Properties/serviceDependencies.local.json similarity index 100% rename from MenuApi/Properties/serviceDependencies.local.json rename to backend/MenuApi/Properties/serviceDependencies.local.json diff --git a/MenuApi/Recipes/IngredientApi.cs b/backend/MenuApi/Recipes/IngredientApi.cs similarity index 100% rename from MenuApi/Recipes/IngredientApi.cs rename to backend/MenuApi/Recipes/IngredientApi.cs diff --git a/MenuApi/Recipes/RecipeApi.cs b/backend/MenuApi/Recipes/RecipeApi.cs similarity index 100% rename from MenuApi/Recipes/RecipeApi.cs rename to backend/MenuApi/Recipes/RecipeApi.cs diff --git a/MenuApi/Repositories/IIngredientRepository.cs b/backend/MenuApi/Repositories/IIngredientRepository.cs similarity index 100% rename from MenuApi/Repositories/IIngredientRepository.cs rename to backend/MenuApi/Repositories/IIngredientRepository.cs diff --git a/MenuApi/Repositories/IRecipeRepository.cs b/backend/MenuApi/Repositories/IRecipeRepository.cs similarity index 100% rename from MenuApi/Repositories/IRecipeRepository.cs rename to backend/MenuApi/Repositories/IRecipeRepository.cs diff --git a/MenuApi/Repositories/IUnitRepository.cs b/backend/MenuApi/Repositories/IUnitRepository.cs similarity index 100% rename from MenuApi/Repositories/IUnitRepository.cs rename to backend/MenuApi/Repositories/IUnitRepository.cs diff --git a/MenuApi/Repositories/IngredientRepository.cs b/backend/MenuApi/Repositories/IngredientRepository.cs similarity index 100% rename from MenuApi/Repositories/IngredientRepository.cs rename to backend/MenuApi/Repositories/IngredientRepository.cs diff --git a/MenuApi/Repositories/RecipeRepository.cs b/backend/MenuApi/Repositories/RecipeRepository.cs similarity index 100% rename from MenuApi/Repositories/RecipeRepository.cs rename to backend/MenuApi/Repositories/RecipeRepository.cs diff --git a/MenuApi/Repositories/UnitRepository.cs b/backend/MenuApi/Repositories/UnitRepository.cs similarity index 100% rename from MenuApi/Repositories/UnitRepository.cs rename to backend/MenuApi/Repositories/UnitRepository.cs diff --git a/MenuApi/Services/IIngredientService.cs b/backend/MenuApi/Services/IIngredientService.cs similarity index 100% rename from MenuApi/Services/IIngredientService.cs rename to backend/MenuApi/Services/IIngredientService.cs diff --git a/MenuApi/Services/IRecipeService.cs b/backend/MenuApi/Services/IRecipeService.cs similarity index 100% rename from MenuApi/Services/IRecipeService.cs rename to backend/MenuApi/Services/IRecipeService.cs diff --git a/MenuApi/Services/IngredientService.cs b/backend/MenuApi/Services/IngredientService.cs similarity index 100% rename from MenuApi/Services/IngredientService.cs rename to backend/MenuApi/Services/IngredientService.cs diff --git a/MenuApi/Services/RecipeService.cs b/backend/MenuApi/Services/RecipeService.cs similarity index 100% rename from MenuApi/Services/RecipeService.cs rename to backend/MenuApi/Services/RecipeService.cs diff --git a/MenuApi/Validation/NewIngredientValidator.cs b/backend/MenuApi/Validation/NewIngredientValidator.cs similarity index 100% rename from MenuApi/Validation/NewIngredientValidator.cs rename to backend/MenuApi/Validation/NewIngredientValidator.cs diff --git a/MenuApi/Validation/NewRecipeValidator.cs b/backend/MenuApi/Validation/NewRecipeValidator.cs similarity index 100% rename from MenuApi/Validation/NewRecipeValidator.cs rename to backend/MenuApi/Validation/NewRecipeValidator.cs diff --git a/MenuApi/Validation/RecipeIngredientValidator.cs b/backend/MenuApi/Validation/RecipeIngredientValidator.cs similarity index 100% rename from MenuApi/Validation/RecipeIngredientValidator.cs rename to backend/MenuApi/Validation/RecipeIngredientValidator.cs diff --git a/MenuApi/Validation/ValidationFilter.cs b/backend/MenuApi/Validation/ValidationFilter.cs similarity index 100% rename from MenuApi/Validation/ValidationFilter.cs rename to backend/MenuApi/Validation/ValidationFilter.cs diff --git a/MenuApi/Validation/VogenValidationRules.cs b/backend/MenuApi/Validation/VogenValidationRules.cs similarity index 100% rename from MenuApi/Validation/VogenValidationRules.cs rename to backend/MenuApi/Validation/VogenValidationRules.cs diff --git a/MenuApi/ValueObjects/Ingredient.cs b/backend/MenuApi/ValueObjects/Ingredient.cs similarity index 100% rename from MenuApi/ValueObjects/Ingredient.cs rename to backend/MenuApi/ValueObjects/Ingredient.cs diff --git a/MenuApi/ValueObjects/IngredientUnit.cs b/backend/MenuApi/ValueObjects/IngredientUnit.cs similarity index 100% rename from MenuApi/ValueObjects/IngredientUnit.cs rename to backend/MenuApi/ValueObjects/IngredientUnit.cs diff --git a/MenuApi/ValueObjects/Recipe.cs b/backend/MenuApi/ValueObjects/Recipe.cs similarity index 100% rename from MenuApi/ValueObjects/Recipe.cs rename to backend/MenuApi/ValueObjects/Recipe.cs diff --git a/MenuApi/ValueObjects/ValueObject.cs b/backend/MenuApi/ValueObjects/ValueObject.cs similarity index 100% rename from MenuApi/ValueObjects/ValueObject.cs rename to backend/MenuApi/ValueObjects/ValueObject.cs diff --git a/MenuApi/ViewModel/FullRecipe.cs b/backend/MenuApi/ViewModel/FullRecipe.cs similarity index 100% rename from MenuApi/ViewModel/FullRecipe.cs rename to backend/MenuApi/ViewModel/FullRecipe.cs diff --git a/MenuApi/ViewModel/Ingredient.cs b/backend/MenuApi/ViewModel/Ingredient.cs similarity index 100% rename from MenuApi/ViewModel/Ingredient.cs rename to backend/MenuApi/ViewModel/Ingredient.cs diff --git a/MenuApi/ViewModel/IngredientUnit.cs b/backend/MenuApi/ViewModel/IngredientUnit.cs similarity index 100% rename from MenuApi/ViewModel/IngredientUnit.cs rename to backend/MenuApi/ViewModel/IngredientUnit.cs diff --git a/MenuApi/ViewModel/NewIngredient.cs b/backend/MenuApi/ViewModel/NewIngredient.cs similarity index 100% rename from MenuApi/ViewModel/NewIngredient.cs rename to backend/MenuApi/ViewModel/NewIngredient.cs diff --git a/MenuApi/ViewModel/NewRecipe.cs b/backend/MenuApi/ViewModel/NewRecipe.cs similarity index 100% rename from MenuApi/ViewModel/NewRecipe.cs rename to backend/MenuApi/ViewModel/NewRecipe.cs diff --git a/MenuApi/ViewModel/Recipe.cs b/backend/MenuApi/ViewModel/Recipe.cs similarity index 100% rename from MenuApi/ViewModel/Recipe.cs rename to backend/MenuApi/ViewModel/Recipe.cs diff --git a/MenuApi/ViewModel/RecipeIngredient.cs b/backend/MenuApi/ViewModel/RecipeIngredient.cs similarity index 100% rename from MenuApi/ViewModel/RecipeIngredient.cs rename to backend/MenuApi/ViewModel/RecipeIngredient.cs diff --git a/MenuApi/VogenDefaults.cs b/backend/MenuApi/VogenDefaults.cs similarity index 100% rename from MenuApi/VogenDefaults.cs rename to backend/MenuApi/VogenDefaults.cs diff --git a/MenuApi/appsettings.Development.json b/backend/MenuApi/appsettings.Development.json similarity index 100% rename from MenuApi/appsettings.Development.json rename to backend/MenuApi/appsettings.Development.json diff --git a/MenuApi/appsettings.json b/backend/MenuApi/appsettings.json similarity index 100% rename from MenuApi/appsettings.json rename to backend/MenuApi/appsettings.json diff --git a/MenuApi/libman.json b/backend/MenuApi/libman.json similarity index 100% rename from MenuApi/libman.json rename to backend/MenuApi/libman.json diff --git a/MenuApi/stylecop.json b/backend/MenuApi/stylecop.json similarity index 100% rename from MenuApi/stylecop.json rename to backend/MenuApi/stylecop.json diff --git a/MenuDB/Data/IngredientEntity.cs b/backend/MenuDB/Data/IngredientEntity.cs similarity index 100% rename from MenuDB/Data/IngredientEntity.cs rename to backend/MenuDB/Data/IngredientEntity.cs diff --git a/MenuDB/Data/IngredientUnitEntity.cs b/backend/MenuDB/Data/IngredientUnitEntity.cs similarity index 100% rename from MenuDB/Data/IngredientUnitEntity.cs rename to backend/MenuDB/Data/IngredientUnitEntity.cs diff --git a/MenuDB/Data/RecipeEntity.cs b/backend/MenuDB/Data/RecipeEntity.cs similarity index 100% rename from MenuDB/Data/RecipeEntity.cs rename to backend/MenuDB/Data/RecipeEntity.cs diff --git a/MenuDB/Data/RecipeIngredientEntity.cs b/backend/MenuDB/Data/RecipeIngredientEntity.cs similarity index 100% rename from MenuDB/Data/RecipeIngredientEntity.cs rename to backend/MenuDB/Data/RecipeIngredientEntity.cs diff --git a/MenuDB/Data/UnitEntity.cs b/backend/MenuDB/Data/UnitEntity.cs similarity index 100% rename from MenuDB/Data/UnitEntity.cs rename to backend/MenuDB/Data/UnitEntity.cs diff --git a/MenuDB/Data/UnitTypeEntity.cs b/backend/MenuDB/Data/UnitTypeEntity.cs similarity index 100% rename from MenuDB/Data/UnitTypeEntity.cs rename to backend/MenuDB/Data/UnitTypeEntity.cs diff --git a/MenuDB/MenuDB.csproj b/backend/MenuDB/MenuDB.csproj similarity index 100% rename from MenuDB/MenuDB.csproj rename to backend/MenuDB/MenuDB.csproj diff --git a/MenuDB/MenuDbContext.cs b/backend/MenuDB/MenuDbContext.cs similarity index 100% rename from MenuDB/MenuDbContext.cs rename to backend/MenuDB/MenuDbContext.cs diff --git a/MenuDB/MenuDbContextFactory.cs b/backend/MenuDB/MenuDbContextFactory.cs similarity index 100% rename from MenuDB/MenuDbContextFactory.cs rename to backend/MenuDB/MenuDbContextFactory.cs diff --git a/MenuDB/Migrations/20260307231933_InitialCreate.Designer.cs b/backend/MenuDB/Migrations/20260307231933_InitialCreate.Designer.cs similarity index 100% rename from MenuDB/Migrations/20260307231933_InitialCreate.Designer.cs rename to backend/MenuDB/Migrations/20260307231933_InitialCreate.Designer.cs diff --git a/MenuDB/Migrations/20260307231933_InitialCreate.cs b/backend/MenuDB/Migrations/20260307231933_InitialCreate.cs similarity index 100% rename from MenuDB/Migrations/20260307231933_InitialCreate.cs rename to backend/MenuDB/Migrations/20260307231933_InitialCreate.cs diff --git a/MenuDB/Migrations/MenuDbContextModelSnapshot.cs b/backend/MenuDB/Migrations/MenuDbContextModelSnapshot.cs similarity index 100% rename from MenuDB/Migrations/MenuDbContextModelSnapshot.cs rename to backend/MenuDB/Migrations/MenuDbContextModelSnapshot.cs diff --git a/aspire.config.json b/backend/aspire.config.json similarity index 100% rename from aspire.config.json rename to backend/aspire.config.json diff --git a/global.json b/backend/global.json similarity index 100% rename from global.json rename to backend/global.json diff --git a/docs/ci-path-filters.md b/docs/ci-path-filters.md index 504ace9a..51d48550 100644 --- a/docs/ci-path-filters.md +++ b/docs/ci-path-filters.md @@ -14,14 +14,7 @@ The workflow uses the [dorny/paths-filter](https://github.com/dorny/paths-filter Backend jobs (`backend-build`, `backend-tests`, `backend-integration-tests`) run when any of these paths change: -- `Menu.*/**` - All Menu service projects (Menu.AppHost, Menu.ServiceDefaults, Menu.ApiServiceDefaults, Menu.MigrationService) -- `MenuApi/**` - API project files -- `MenuApi.Tests/**` - Unit test project files -- `MenuApi.Integration.Tests/**` - Integration test project files -- `MenuDB/**` - Database project files -- `*.sln` - Solution files -- `global.json` - .NET SDK version configuration -- `aspire.config.json` - Aspire orchestration configuration +- `backend/**` - All backend projects, solution files, and backend-specific configuration grouped under the `backend/` directory - `.github/workflows/main.yml` - The workflow file itself #### Frontend Job @@ -51,7 +44,7 @@ The frontend job (`frontend`) runs when any of these files change: ## Cross-Stack Scenarios -### Scenario: Backend-only changes (e.g., only `.cs` files) +### Scenario: Backend-only changes (e.g., only files under `backend/`) - ✅ Backend jobs run - ❌ Frontend job is skipped @@ -126,7 +119,7 @@ Path filters improve CI throughput by: The implementation includes several guardrails to prevent missing validation: -1. **Conservative patterns**: Includes critical config files (global.json, aspire.config.json) +1. **Conservative structure**: Backend projects and backend-only config files live under `backend/`, so one path captures solution, project, and analyzer changes together 2. **Workflow file triggers both**: Changes to the workflow file trigger all jobs 3. **Always run on push**: All jobs run on pushes to main/master branches 4. **Dependency review still runs**: The dependency-review job always runs on PRs regardless of changed files diff --git a/docs/database-migrations.md b/docs/database-migrations.md index 41b91b33..5ce5e6e4 100644 --- a/docs/database-migrations.md +++ b/docs/database-migrations.md @@ -1,6 +1,6 @@ # Database Migrations -This project uses **Entity Framework Core** with SQL Server to manage the database schema for `MenuDbContext`. Migrations are stored under `MenuDB/Migrations/` and are applied automatically at startup when running inside .NET Aspire. +This project uses **Entity Framework Core** with SQL Server to manage the database schema for `MenuDbContext`. Migrations are stored under `backend/MenuDB/Migrations/` and are applied automatically at startup when running inside .NET Aspire. --- @@ -30,9 +30,9 @@ dotnet ef --version ## Creating a New Migration -All `dotnet ef` commands must be run from the **solution root** (`C:\git\Menu\`) and target the `MenuDB` project, which contains `MenuDbContext` and `MenuDbContextFactory`. `MenuApi` is used as the startup project to provide the runtime host. +All `dotnet ef` commands must be run from the **backend solution root** (`C:\git\Menu\backend\`) and target the `MenuDB` project, which contains `MenuDbContext` and `MenuDbContextFactory`. `MenuApi` is used as the startup project to provide the runtime host. -After modifying any entity in `MenuDB/Data/` or the model configuration in `MenuDB/MenuDbContext.cs`, create a new migration: +After modifying any entity in `backend/MenuDB/Data/` or the model configuration in `backend/MenuDB/MenuDbContext.cs`, create a new migration: ```bash dotnet ef migrations add --project MenuDB --startup-project MenuApi @@ -83,7 +83,7 @@ Migrations are applied by the dedicated **`Menu.MigrationService`** worker, not 2. `Menu.MigrationService` runs — applies all pending migrations, then exits 3. `MenuApi` starts — guaranteed to find the schema already up to date -This is enforced in `Menu.AppHost/Program.cs`: +This is enforced in `backend/Menu.AppHost/Program.cs`: ```csharp var menuDb = sql.AddDatabase("menu"); diff --git a/docs/integration-tests.md b/docs/integration-tests.md index 6b1c111e..6694fa87 100644 --- a/docs/integration-tests.md +++ b/docs/integration-tests.md @@ -100,7 +100,7 @@ The Aspire host starts a SQL Server container. Docker Desktop (or a compatible c The test project requires Auth0 credentials to obtain access tokens. Set them via user secrets: ```bash -cd MenuApi.Integration.Tests +cd backend/MenuApi.Integration.Tests dotnet user-secrets set "Parameters:Auth0TestClientId" "" dotnet user-secrets set "Parameters:Auth0TestClientSecret" "" dotnet user-secrets set "Parameters:Auth0Audience" "" @@ -117,7 +117,7 @@ The solution targets `net9.0`. Ensure the .NET 9 SDK is installed. ## How to Run the Tests -From the solution root: +From the backend solution root (`C:\git\Menu\backend\`): ```bash dotnet test MenuApi.Integration.Tests @@ -139,7 +139,7 @@ Follow these steps when adding integration tests for a new or existing endpoint. ### 1. Create the Test Class -Add a new `.cs` file in the `MenuApi.Integration.Tests` project root. Apply the collection attribute and inject the fixture: +Add a new `.cs` file in `backend/MenuApi.Integration.Tests`. Apply the collection attribute and inject the fixture: ```csharp using AwesomeAssertions; diff --git a/docs/specs/api-validation.md b/docs/specs/api-validation.md index 0b534b5d..c28bec88 100644 --- a/docs/specs/api-validation.md +++ b/docs/specs/api-validation.md @@ -301,7 +301,7 @@ group.MapPost("/", CreateRecipeAsync) New/modified files: ``` -MenuApi/ +backend/MenuApi/ ├── Validation/ │ ├── ValidationFilter.cs # Generic endpoint filter │ ├── NewRecipeValidator.cs # FluentValidation rules for NewRecipe From a8d4882e3f9382589521d112f7a109ba314a0165 Mon Sep 17 00:00:00 2001 From: "anthropic-code-agent[bot]" <242468646+Claude@users.noreply.github.com> Date: Tue, 21 Apr 2026 07:59:58 +0000 Subject: [PATCH 7/7] Update integration tests doc to reference .NET 10 SDK Agent-Logs-Url: https://github.com/dgee2/Menu/sessions/2847a46e-f607-4418-93b5-267433c3aff8 Co-authored-by: dgee2 <5671841+dgee2@users.noreply.github.com> --- docs/integration-tests.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/integration-tests.md b/docs/integration-tests.md index 6694fa87..5d4ddeca 100644 --- a/docs/integration-tests.md +++ b/docs/integration-tests.md @@ -109,9 +109,9 @@ dotnet user-secrets set "Parameters:Auth0Domain" "" The user secrets ID for the integration test project is `ea3aa4c7-9b32-4485-a5b2-fb1cb0def863`. -### 3. .NET 9 SDK +### 3. .NET 10 SDK -The solution targets `net9.0`. Ensure the .NET 9 SDK is installed. +The solution targets `net10.0`. Ensure the .NET 10 SDK is installed. ---