diff --git a/.env.example b/.env.example index 885a0c6..9743d07 100644 --- a/.env.example +++ b/.env.example @@ -1,11 +1,11 @@ -# Sea Haven Industries ÔÇö shoc-backend required configuration +# Sea Haven Industries — shoc-backend required configuration # # This file documents the secrets that used to be hardcoded in appsettings*.json # and source files. Copy the values into one of the supported configuration sources; # do NOT commit real values. # # .NET resolves configuration in this order (later wins): -# 1. appsettings.json / appsettings.{Environment}.json (committed ÔÇö placeholders only) +# 1. appsettings.json / appsettings.{Environment}.json (committed — placeholders only) # 2. User Secrets (local dev): dotnet user-secrets set "Key:Sub" "value" # 3. Environment variables (use "__" as the section separator) # diff --git a/.gitattributes b/.gitattributes index 1ff0c42..52cd8b4 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,63 +1,2 @@ -############################################################################### -# Set default behavior to automatically normalize line endings. -############################################################################### +# Normalize line endings on checkout and checkin. * text=auto - -############################################################################### -# Set default behavior for command prompt diff. -# -# This is need for earlier builds of msysgit that does not have it on by -# default for csharp files. -# Note: This is only used by command line -############################################################################### -#*.cs diff=csharp - -############################################################################### -# Set the merge driver for project and solution files -# -# Merging from the command prompt will add diff markers to the files if there -# are conflicts (Merging from VS is not affected by the settings below, in VS -# the diff markers are never inserted). Diff markers may cause the following -# file extensions to fail to load in VS. An alternative would be to treat -# these files as binary and thus will always conflict and require user -# intervention with every merge. To do so, just uncomment the entries below -############################################################################### -#*.sln merge=binary -#*.csproj merge=binary -#*.vbproj merge=binary -#*.vcxproj merge=binary -#*.vcproj merge=binary -#*.dbproj merge=binary -#*.fsproj merge=binary -#*.lsproj merge=binary -#*.wixproj merge=binary -#*.modelproj merge=binary -#*.sqlproj merge=binary -#*.wwaproj merge=binary - -############################################################################### -# behavior for image files -# -# image files are treated as binary by default. -############################################################################### -#*.jpg binary -#*.png binary -#*.gif binary - -############################################################################### -# diff behavior for common document formats -# -# Convert binary document formats to text before diffing them. This feature -# is only available from the command line. Turn it on by uncommenting the -# entries below. -############################################################################### -#*.doc diff=astextplain -#*.DOC diff=astextplain -#*.docx diff=astextplain -#*.DOCX diff=astextplain -#*.dot diff=astextplain -#*.DOT diff=astextplain -#*.pdf diff=astextplain -#*.PDF diff=astextplain -#*.rtf diff=astextplain -#*.RTF diff=astextplain diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..15f9114 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,22 @@ + + +## Summary + + + +## Changes and value + + + +## Ticket + + diff --git a/AGENTS.md b/AGENTS.md index 03e95fe..f5c54f1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,9 +6,7 @@ may add stricter backend rules but may never weaken the workspace baseline. ## Canonical governance documents (precedence) -1. `ARCHITECTURE_AND_CODE_QUALITY.md` — *what* the rules mean (canonical; - supersedes the older `BACKEND_ARCHITECTURE.md`, which is retained only as - historical reference). +1. `ARCHITECTURE_AND_CODE_QUALITY.md` — *what* the rules mean (canonical). 2. `QUALITY_GATES.md` — *how* rules are enforced (commands + CI mapping). 3. `REVIEW_AND_PR_FRAMEWORK.md` — *who* reviews, in what order, with what evidence. diff --git a/ARCHITECTURE_AND_CODE_QUALITY.md b/ARCHITECTURE_AND_CODE_QUALITY.md index 54b35a1..f032028 100644 --- a/ARCHITECTURE_AND_CODE_QUALITY.md +++ b/ARCHITECTURE_AND_CODE_QUALITY.md @@ -1,9 +1,8 @@ # Architecture and Code Quality (canonical) > **Status: canonical.** This document owns the *meaning* of the backend's -> architecture and code-quality rules. On any conflict with the older -> `BACKEND_ARCHITECTURE.md`, **this document governs**; that file is retained -> only as historical reference pending removal. +> architecture and code-quality rules. It replaced the earlier +> `BACKEND_ARCHITECTURE.md`, which now lives only in git history. > > Companion documents: > - `QUALITY_GATES.md` — *how* each rule is enforced (commands + CI mapping). diff --git a/BACKEND_ARCHITECTURE.md b/BACKEND_ARCHITECTURE.md deleted file mode 100644 index ca27a73..0000000 --- a/BACKEND_ARCHITECTURE.md +++ /dev/null @@ -1,106 +0,0 @@ -# Backend Architecture and Quality Rules - -This repository uses a feature-oriented service boundary over Entity Framework Core: - -```text -HTTP controller -> I{Feature}Service -> I{Feature}DataService -> ApplicationDbContext -``` - -The interfaces are architectural seams, not a requirement to wrap every class or every -EF method. Add an interface when it separates HTTP, business, persistence, or external -I/O responsibilities and enables behavior-focused testing. - -## Layer responsibilities - -### API controllers - -- Parse HTTP input, authorize the caller, invoke a business-service interface, and map - the result to the established HTTP contract. -- Do not inject `ApplicationDbContext`, concrete service implementations, or concrete - data-service implementations. -- Do not contain persistence queries or business workflows. -- Do not expose exception messages to clients. Map known failures explicitly and let the - centralized exception boundary handle unexpected failures. - -### Business services - -- Own validation, business decisions, orchestration, and transaction intent. -- Depend on interfaces for persistence and external I/O. -- Use `IOptions` for typed configuration. Do not inject `IConfiguration`. -- Keep feature responsibilities cohesive. Split a service when it has independently - changing business reasons, not because it crossed an arbitrary line count. -- Preserve existing API and board-backed behavior unless the accepted requirement - explicitly changes it. - -### Data services - -- Own EF Core query shape, persistence, batching, and transaction implementation. -- Accept cancellation tokens on new I/O methods and pass them to EF Core. -- Use `AsNoTracking()` for read-only queries. -- Project only required columns for list/read models; include full graphs only when the - caller needs them. -- Page unbounded collections at the database. -- Avoid query-in-loop and save-in-loop patterns. Prefer set-based reads and batched writes - while preserving the workflow's failure and transaction semantics. -- Do not introduce a generic repository over EF Core. Feature data services should expose - intent-revealing operations. - -## Performance review - -For each changed hot path, document and test: - -- input size variables; -- CPU and memory complexity; -- database round trips; -- whether filtering, ordering, and paging execute in SQL; -- whether tracking is necessary; -- whether repeated work can be hoisted out of loops; -- the partial-failure and transaction behavior. - -Prefer dictionary or hash-set reconstruction when database results must follow caller -order. A query followed by dictionary reconstruction is normally `O(n)` CPU and memory; -repeated `First`/`Single` scans over the result are `O(n²)`. - -Do not optimize by weakening correctness. In particular, batching all writes into one -final save can change partial-success behavior, and adding a transaction can change -locking and retry semantics. Those are business decisions, not mechanical cleanup. - -## Configuration - -Configuration is bound once during composition in -`SeaHaven.Services/DependencyInjection/ServicesModule.cs`. Business services receive -typed options such as `FrontendOptions`, `JwtOptions`, `ApprovalsOptions`, and -`VendorPortalOptions`. - -Defaults must preserve current behavior. Startup validation should be introduced only -when every deployed environment is known to provide the required value. - -## Enforcement - -`ArchitectureTests` enforces mechanical dependency rules: - -- controllers cannot inject EF contexts or concrete service/data-service classes; -- business services cannot inject EF contexts or raw `IConfiguration`. - -The pull-request quality workflow runs those tests and verifies formatting for changed -C# files. The normal CI workflow builds the solution and runs the full test suite. - -Architecture tests are appropriate for dependency direction. Behavior belongs in tests -through public interfaces. Do not add tests merely to prove a linter or analyzer itself -works; test the product behavior the rule protects. - -## Review checklist - -- Controller depends only on service abstractions. -- Business logic is in a cohesive feature service. -- EF operations are behind a feature data-service abstraction. -- No raw `IConfiguration` in a business service. -- No unbounded load followed by in-memory filtering. -- No query/save loop where a set-based operation preserves semantics. -- Read-only EF queries use no tracking. -- New async I/O accepts and propagates cancellation where the public contract permits. -- Errors do not leak internal exception details. -- Tests cover behavior, authorization, data contracts, ordering, duplicates, missing - records, and relevant failure boundaries. -- Changed behavior has been checked against the authoritative ticket board. Missing board - access blocks readiness and merge claims. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2215fb6 --- /dev/null +++ b/README.md @@ -0,0 +1,115 @@ +# SHOC Backend (`shoc-backend`) + +[![CI](https://github.com/Sea-Haven-Industries/shoc-backend/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/Sea-Haven-Industries/shoc-backend/actions/workflows/ci.yml) +[![Deploy](https://github.com/Sea-Haven-Industries/shoc-backend/actions/workflows/deploy.yaml/badge.svg)](https://github.com/Sea-Haven-Industries/shoc-backend/actions/workflows/deploy.yaml) +![.NET 8](https://img.shields.io/badge/.NET-8.0-512BD4?logo=dotnet&logoColor=white) +![SQL Server](https://img.shields.io/badge/SQL%20Server-CC2927?logo=microsoftsqlserver&logoColor=white) +![Terraform](https://img.shields.io/badge/Terraform-844FBA?logo=terraform&logoColor=white) + +ASP.NET Core 8 API for Sea Haven facility management (SHOC): work orders, the +work-order board, dispatches and the vendor portal, uplift approvals, +notifications, and the dashboard. It is the backend for +[`shoc-frontend-new`](https://github.com/Sea-Haven-Industries/shoc-frontend-new), +which calls it directly over HTTPS. + +| Environment | API | Elastic Beanstalk environment | Deployed by | +|---|---|---|---| +| dev | `https://api.dev.seahaven.com` | `shoc-backend-dev` | every push to `main` | +| staging | `https://api.staging.seahaven.com` | `shoc-backend-staging` | a `vX.Y.Z-staging` tag cut with `release.yaml` | + +Both run in `us-east-1` on the .NET 8 Amazon Linux 2023 platform. Terraform in +`terraform/live/` owns the environments; GitHub Actions owns the application +versions. There is no production environment yet. + +## Architecture + +```text +Controller -> I{Feature}Service -> I{Feature}DataService -> ApplicationDbContext +``` + +Controllers depend on feature service interfaces only. Business services depend +on feature data-service interfaces, never on `DbContext`. Data services own +Entity Framework Core and are the atomic commit boundary. Tenant scope is +derived on the server from claims, and authorization is enforced at service +entry. The rules and their reasons are in +[`ARCHITECTURE_AND_CODE_QUALITY.md`](ARCHITECTURE_AND_CODE_QUALITY.md). + +| Project | Role | +|---|---| +| `Api.SeaHavenIndustries` | The deployed API: controllers, hosted services, infrastructure adapters, `Program.cs` | +| `SeaHaven.Services` | Business services, DTOs, validation, helpers | +| `SeaHaven.DataServices` | Feature data services over EF Core | +| `Data.SeaHavenIndustries` | Entities, `ApplicationDbContext`, Identity, migrations | +| `SeaHavenIndustries` | Legacy Blazor Server app sharing the data layer; not part of the API deployment | +| `Api.SeaHavenIndustries.Tests`, `SeaHaven.Services.Tests`, `SeaHavenIndustries.Tests` | xunit test projects | + +## Local development + +Requires the .NET 8 SDK and a reachable SQL Server. Configuration comes from +`appsettings*.json` placeholders, then user secrets, then environment +variables. `.env.example` lists every key, including the connection string, JWT +secret, SendGrid key and Sentry DSN. Do not commit real values. + +```bash +dotnet restore SeaHavenIndustries.sln +dotnet build SeaHavenIndustries.sln --configuration Release +dotnet test SeaHavenIndustries.sln --configuration Release +dotnet run --project Api.SeaHavenIndustries +``` + +The full repository gate that CI runs, including architecture discovery, the +changed-file maintainability check, Terraform checks and app/Terraform +isolation: + +```bash +BASE_REF=origin/main bash scripts/governance-check.sh +``` + +Migrations live in `Data.SeaHavenIndustries/Migrations` and are applied at +deploy time from a bundle the packaging script builds with `dotnet-ef`. Adding +one follows the G6 rules in [`QUALITY_GATES.md`](QUALITY_GATES.md). + +## Contributing + +- Branch from `main` with a `feature/`, `fix/`, `chore/`, `docs/` or + `refactor/` prefix and a kebab-case description. +- Commit subjects follow Conventional Commits. PR titles end with the Jira + key for product work. +- The PR body uses the three-section layout the template pre-fills: Summary, + Changes and value, Ticket. The reasoning is in + [`REVIEW_AND_PR_FRAMEWORK.md`](REVIEW_AND_PR_FRAMEWORK.md). +- `main` requires a code-owner review and the `Build and test`, + `architecture` and `review / dependency-review` checks. PRs merge through the + merge queue, so a branch does not need to be updated with `main` before it + merges. +- Application code and `terraform/` do not change in the same PR (G13). + +## Deployment + +`deploy.yaml` packages the API with `scripts/package-elastic-beanstalk.sh`, +uploads the bundle to the Elastic Beanstalk bucket, updates the environment, +verifies the exact version is active, and smoke-tests it. The bundle carries a +self-contained EF Core migrations bundle that Elastic Beanstalk runs on the +leader instance before the new version starts +(`.ebextensions/01_migrations.config`). A push to `main` targets dev. +`release.yaml` cuts a SemVer tag from `main` and calls the same workflow for +staging. Both are described in the workflow headers and in +[`terraform/live/README.md`](terraform/live/README.md). + +Renovate opens dependency PRs on the schedule in `.github/renovate.json`; +majors wait for approval on the Dependency Dashboard issue. + +## Documentation + +- [`AGENTS.md`](AGENTS.md): repo-specific rules for coding agents and the order + of precedence between the governance documents. +- [`ARCHITECTURE_AND_CODE_QUALITY.md`](ARCHITECTURE_AND_CODE_QUALITY.md): what + the architecture rules mean. +- [`QUALITY_GATES.md`](QUALITY_GATES.md): every gate, the command that runs it + locally, and where CI runs it. +- [`REVIEW_AND_PR_FRAMEWORK.md`](REVIEW_AND_PR_FRAMEWORK.md): review order, + evidence, and the PR description contract. +- [`docs/adr/`](docs/adr/): architecture decision records. +- [`docs/work-orders/`](docs/work-orders/): work-order board phase notes. +- [`postman/`](postman/): generated Postman collection and dev environment. +- [`terraform/README.md`](terraform/README.md): infrastructure runbook. diff --git a/REVIEW_AND_PR_FRAMEWORK.md b/REVIEW_AND_PR_FRAMEWORK.md index d0ea942..0ef1def 100644 --- a/REVIEW_AND_PR_FRAMEWORK.md +++ b/REVIEW_AND_PR_FRAMEWORK.md @@ -130,6 +130,11 @@ Avoid boilerplate: no deployment notes, no validation transcripts, no "residual-risk" theatre, no AI signatures. The validation story lives in the check run results and the close-out, not in the PR body. +`.github/PULL_REQUEST_TEMPLATE.md` pre-fills this layout and overrides the org +template, whose Summary / Validation / Tests / Notes headings this repository +does not use. The org `callable-pr-policy` workflow hard-codes those four +headings; it is not wired into this repository, and this layout is the reason. + ## 9. Merge readiness Merge requires: exact-head review done; board-backed regression check pass (or diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 68fc21b..0000000 --- a/TODO.md +++ /dev/null @@ -1,52 +0,0 @@ -# SHOC — TODO - -## Vendor Portal (Next Priority) -- [ ] Change dispatch email Accept button to "View Work Order" linking to vendor portal -- [ ] Vendor web portal — public pages authenticated by dispatch token -- [ ] Vendor can view their dispatches, accept, update status, complete sign-offs, fill checklists -- [ ] No login required — token-based access from email link -- [ ] Per-WO template selection in multi-WO dispatch - -## Dispatch & Vendor Communication -- [x] Dispatch detail modal — view/edit status, dates, NTE, description -- [x] Dispatch number — auto-generated DSP-00001 -- [x] DispatchId on Comments — tie vendor comments to specific dispatches -- [x] Vendor activity feed per dispatch -- [x] Internal user → vendor email -- [x] Cancel dispatch button -- [x] Checklist items with template support -- [x] Two-party sign-offs (Customer + Vendor) -- [x] Dispatcher verification gate -- [x] Vendor accept via email link -- [x] Time tracking / wait indicators -- [x] Multi-WO dispatch -- [ ] **Front API integration** — replace SendGrid/SES with Front inbox (vendors@seahaven.com) -- [ ] Add ability for dispatcher to assign a template checklist after initial dispatch -- [ ] Resend dispatch email button - -## Work Order List -- [ ] Pinned Actions column — CSS grid doesn't support sticky horizontal scroll, revisit - -## Pages Not Yet Built -- [ ] `/profile` — My Profile page (linked from user dropdown) -- [ ] `/settings` — Account Settings page (linked from user dropdown) -- [ ] `/change-password` — Change Password page (linked from user dropdown) - -## Controllers Not Yet Built -- [ ] `CalendarController` — backend CRUD for calendar/events (frontend pages exist) - -## Dashboard -- [ ] Priority Analysis table — needs backend endpoint to calculate age buckets by severity -- [ ] Invoice Analysis table — placeholder data, no backend yet - -## Data & Integration -- [ ] Customer NTE — wire to PO database (placeholder on WO view page) -- [ ] Vendor PO detailed format — line items, billing address, payment terms, expiration, T&C -- [ ] PDF generation for Vendor PO — QuestPDF or similar -- [ ] Address-based distance calculation — upgrade from zip-to-zip to geocoded addresses -- [ ] Backfill location zip codes from address strings during sync - -## Deployment -- [ ] When SHOC deploys, switch workorder-ingest Lambda from DynamoDB to direct SHOC API calls -- [ ] Retire DynamoDB sync bridge -- [ ] GitHub branch protection — requires paid plan for private repos