Completes Operations phase: Monitoring Setup and Production Readiness Validation
Confirms existing tag-based Sentry alerting and domain-based UptimeRobot/ Umami monitoring already cover the Offerings module and the Api.SlpSoftware cutover with no new configuration. Closes the SECURITY-13 audit-trail open item and records the final production-readiness traceability, completing the slpsoftware-api feature's AI-DLC lifecycle. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FWyStNL2ZsjrS7FLd7xvvN
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
# Monitoring Setup — slpsoftware-api
|
||||
|
||||
This feature does not own separate monitoring infrastructure. Per the same "extend, don't duplicate"
|
||||
relationship as Deployment Setup, all monitoring for `slpsoftware.nl`/`test.slpsoftware.nl` is
|
||||
already built and configured by `gitea-deployment-workflow`:
|
||||
|
||||
- `aidlc-docs/features/gitea-deployment-workflow/operations/monitoring/monitoring-instructions.md`
|
||||
|
||||
## Conclusion: No New Configuration Needed
|
||||
|
||||
Investigated (see `operations/plans/monitoring-setup-plan.md` for the full trace) whether the
|
||||
Offerings module or the D-15 CI/CD cutover require any change to Sentry alert rules, UptimeRobot
|
||||
monitors, or Umami — they do not:
|
||||
|
||||
| Area | Why it's already covered |
|
||||
|---|---|
|
||||
| Sentry alert rules (`rate_limit_triggered` tag) | `AddCmsRateLimiting`'s shared rejection handler fires this tag for **any** policy by name, including the new `offerings-public` policy — no per-policy wiring exists to update |
|
||||
| Sentry alert rules (`authorization_denied` tag) | A single global `IAuthorizationMiddlewareResultHandler` in Core fires this tag for **any** policy failure on **any** endpoint, including `OfferingsController`'s `AdminOnly` actions |
|
||||
| UptimeRobot (`/health`, `/`, `/admin` × test/production) | Checks domains/paths, not a specific `.dll` — the cutover changes which process answers, invisible to an HTTP-status monitor |
|
||||
| Umami (admin SPA website entries) | Same URLs before and after the cutover |
|
||||
| Gitea variables (`VITE_SENTRY_DSN`, `VITE_UMAMI_*`, `SECURITY_ALLOWED_SCRIPT_ORIGINS_*`) | Already set, tied to the Sentry project/Umami instance/CSP config, not to which project publishes the artifact |
|
||||
|
||||
`OfferingsService`'s own audit logging (`LastModifiedByUserId`, structured `LogInformation` on
|
||||
create/update/delete — NFR-OFF-03) was deliberately **not** routed through `SecurityEvents`/Sentry:
|
||||
it logs routine content changes, not alertable anomalies. This was a considered decision at NFR
|
||||
Requirements, not a monitoring gap.
|
||||
@@ -0,0 +1,46 @@
|
||||
# Monitoring Setup Plan — slpsoftware-api
|
||||
|
||||
## Investigation (Before Drafting Anything)
|
||||
|
||||
Read `gitea-deployment-workflow/operations/monitoring/monitoring-instructions.md` in full, then
|
||||
checked whether anything this feature added (the Offerings module, the D-15 cutover) needs new or
|
||||
changed monitoring configuration.
|
||||
|
||||
- **Sentry alert rules (FR-19, tag-based)**: the six existing rules filter on the `security_event`
|
||||
Sentry tag, not on message text or endpoint. Read `SlpModularCms.Core.Hosting.ServiceCollectionExtensions.AddCmsRateLimiting`'s
|
||||
shared `OnRejected` callback — it calls `SecurityEvents.RateLimitTriggered` (tag
|
||||
`rate_limit_triggered`) for **any** rejected policy, by name, not per-policy-hardcoded. The new
|
||||
`offerings-public` policy added in Code Generation is therefore already covered by the existing
|
||||
`rate_limit_triggered` alert rule with zero new configuration.
|
||||
- **Authorization denials**: read `SecurityAuthorizationResultHandler.cs` — it's a global
|
||||
`IAuthorizationMiddlewareResultHandler`, wired once in `Core`, firing `authorization_denied`
|
||||
(tag) for **any** policy failure on **any** endpoint. `OfferingsController`'s `AdminOnly`-protected
|
||||
actions are covered automatically; nothing Offerings-specific needed wiring.
|
||||
- **No new alertable event type**: NFR-OFF-03's audit logging (`OfferingsService`'s
|
||||
`LogInformation` calls) was deliberately kept **out of** `SecurityEvents`/Sentry (see NFR
|
||||
Requirements' investigation) — routine content mutations are not alertable anomalies. Nothing to
|
||||
add here by design.
|
||||
- **UptimeRobot (D-23)**: the six monitors (`/health`, `/`, `/admin` × test/production) check
|
||||
domains and paths, not a specific `.dll`. They already point at `test.slpsoftware.nl`/
|
||||
`slpsoftware.nl` — the D-15 cutover changes which process answers behind those URLs, invisible to
|
||||
a monitor that only checks the HTTP response. No new monitor needed; the public
|
||||
`GET /api/v1/offerings` endpoint was never in scope for dedicated uptime monitoring (D-23 covers
|
||||
liveness/static-hosting/admin-SPA checks only, not every individual API route).
|
||||
- **Umami**: two website entries for the admin SPA, same URLs before and after the cutover. No
|
||||
change.
|
||||
- **Gitea variables**: `VITE_SENTRY_DSN`, `VITE_UMAMI_*`, `SECURITY_ALLOWED_SCRIPT_ORIGINS_*` all
|
||||
already exist and are unaffected — same Sentry project (D-19), same Umami instance, same CSP
|
||||
origins, none of which are tied to which project publishes the artifact.
|
||||
|
||||
## Why No Questions, No New Configuration
|
||||
|
||||
Every piece of monitoring infrastructure this feature could plausibly need is already covered by
|
||||
`gitea-deployment-workflow`'s existing, tag-based/domain-based design — none of it hardcodes a
|
||||
project name or is scoped to a specific endpoint in a way the cutover or the new module would break.
|
||||
This stage's output is a documented confirmation, not new setup.
|
||||
|
||||
## Checklist
|
||||
|
||||
- [x] Create `operations/monitoring/monitoring-instructions.md` as a feature-local pointer document
|
||||
recording this investigation and its "no changes needed" conclusion, so a future reader isn't
|
||||
left wondering whether Offerings' monitoring was simply forgotten
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
# Production Readiness Validation — slpsoftware-api
|
||||
|
||||
Final Operations-phase gate. Validates the feature against its own Requirements Analysis artifacts
|
||||
(traceability, not re-litigation) plus what actually running in production requires beyond passing
|
||||
tests.
|
||||
|
||||
## 1. Functional Requirements Traceability
|
||||
|
||||
| FR | Status | Evidence |
|
||||
|---|---|---|
|
||||
| FR-1 New Client Project `Api.SlpSoftware` | ✅ Done | Unit 1, merged into `feature/slpsoftware-api` |
|
||||
| FR-2 Module Composition (Identity/Availability/Master/Offerings) | ✅ Done | `Api.SlpSoftware.csproj` project references |
|
||||
| FR-3 Shared Hosting Pipeline Extraction (`CmsHost`) | ✅ Done | `SlpModularCms.Core.Hosting.CmsHost`, used by both `Api` and `Api.SlpSoftware` |
|
||||
| FR-4/FR-5 `Offerings` module + admin CRUD | ✅ Done | Unit 2, `SlpModularCms.Modules.Offerings` |
|
||||
| FR-6 Public `GET /api/v1/offerings` | ✅ Done | `OfferingsController.GetOfferings`, `[AllowAnonymous]` |
|
||||
| FR-7 Admin CRUD + reorder, `AdminOnly` | ✅ Done | `OfferingsController`'s remaining actions |
|
||||
| FR-8 Reference content documented | ✅ Done | `requirements.md`'s reference-content table (3 packages); entering it into the running system is an explicit user-owned manual step (Scope Boundaries) |
|
||||
| FR-9 CI/CD retarget (cutover) | ✅ Done (repo side) | `continuous_integration.yaml` retargeted; **host-side systemd edit still pending — see § 4** |
|
||||
|
||||
## 2. Non-Functional Requirements
|
||||
|
||||
| NFR | Status | Evidence |
|
||||
|---|---|---|
|
||||
| NFR-1 No nginx changes | ✅ Confirmed | D-6; verified at Deployment Setup — proxy forwards to a port, not an executable |
|
||||
| NFR-2 Module test coverage | ✅ Met | 38 tests in `Modules.Offerings.Tests` covering entity/context, repository, service (all 4 business rules), controller (routes/auth) |
|
||||
| NFR-3 Long-term reusability (no SlpSoftware-specific baking-in) | ✅ Confirmed | Module named `Offerings` (D-9), no hardcoded tenant/site assumptions in entity/service/controller |
|
||||
| NFR-4 Property-based testing not required | ✅ N/A by design | D-12, example-based tests only throughout |
|
||||
|
||||
## 3. User Story Coverage
|
||||
|
||||
All 12 user stories (US-01–US-12) implemented and covered by tests: US-01/02/03 (public list,
|
||||
featured highlight, empty-state resilience), US-04–US-07 (create/edit/delete, including
|
||||
last-remaining-offering deletion), US-08/US-09 (drag-and-drop and button-based reorder), US-10
|
||||
(featured exclusivity), US-11 (validation feedback), US-12 (`AdminOnly` role gate).
|
||||
|
||||
## 4. Security Compliance — Final Status
|
||||
|
||||
All 15 rules from `requirements.md`'s Security Compliance table are **Addressed**, **Pre-existing/
|
||||
unchanged**, or **N/A**, with one item to formally close:
|
||||
|
||||
**SECURITY-13 (Software and data integrity) — RESOLVED.** Requirements Analysis logged this as an
|
||||
open item pending Functional/NFR Design. Resolution: `Offering.LastModifiedByUserId` +
|
||||
`CreatedAt`/`UpdatedAt` (NFR-OFF-03) provide a minimal "who + when" audit trail on every
|
||||
create/update/delete. Explicitly **not** a full before/after audit-log table — that remains a known,
|
||||
accepted scope boundary (documented in `nfr-requirements.md`), not a gap discovered late.
|
||||
|
||||
No other Security Compliance item changed status during Construction or Operations.
|
||||
|
||||
## 5. Build, Test, and Code Quality
|
||||
|
||||
- Backend: full solution build succeeded; **414/414 tests passing** across 6 test projects, no
|
||||
regressions (verified at the feature-wide Build and Test stage, re-confirmed after two live-testing
|
||||
bug fixes during Unit 2's post-completion review — record-validation targeting and the drag overlay
|
||||
fix — neither of which touched test-covered logic paths differently than already tested).
|
||||
- Frontend: `pnpm build` succeeded, `pnpm lint` clean, **254/254 tests passing** across 41 files.
|
||||
- Migration safety (rollback plan's D-26 requirement — forward-compatible, non-destructive): the
|
||||
`InitialCreate` migration for `OfferingsDbContext` is a single `CREATE TABLE` with no `ALTER` on
|
||||
any existing table — trivially satisfies this by construction. A rollback to a pre-Offerings
|
||||
release simply leaves the `OfferingsOfferings` table unused, never touched destructively.
|
||||
|
||||
## 6. Deployment Readiness
|
||||
|
||||
Repo-side: complete (Deployment Setup stage). **Two items require action outside this repository
|
||||
before the cutover is live**:
|
||||
|
||||
1. **Host action (blocking for production traffic, not for CI)**: edit
|
||||
`~/.config/systemd/user/slpsoftware-test.service` and `slpsoftware-production.service` on
|
||||
pi-main, changing `ExecStart`'s target from `SlpModularCms.Api.dll` to
|
||||
`SlpModularCms.Api.SlpSoftware.dll` (exact steps: `deployment-instructions.md` § 1.6, restated in
|
||||
`operations/deployment/deployment-instructions.md`). Until this is done, a successful CI deploy
|
||||
uploads the new build correctly, but the running service keeps executing the old `Api.dll` from
|
||||
that release directory.
|
||||
2. **Content entry (not blocking, user's own task)**: the three reference offerings (FR-8's table)
|
||||
need to be entered through the new admin UI once live — no auto-seed exists by design (D-5).
|
||||
|
||||
## 7. Monitoring Readiness
|
||||
|
||||
Confirmed at the Monitoring Setup stage: no new Sentry alert rules, UptimeRobot monitors, or Umami
|
||||
entries needed. Existing tag-based/domain-based monitoring already covers the new rate-limit policy,
|
||||
the new `AdminOnly` endpoints, and the cutover itself (see `operations/monitoring/monitoring-instructions.md`).
|
||||
|
||||
## 8. Rollback Readiness
|
||||
|
||||
`gitea-deployment-workflow`'s existing `rollback-plan.md` applies unchanged: fast rollback via the
|
||||
`current` symlink (no rebuild), rebuild-and-redeploy for anything older, database restore from the
|
||||
pre-deploy backup. None of its mechanisms are `.dll`-name-specific, so the D-15 cutover doesn't
|
||||
require a rollback-plan update, and a rollback of this feature's first production deploy would land
|
||||
back on the old `Api.dll` release exactly as any other rollback would.
|
||||
|
||||
## 9. Known, Accepted Limitations (Not Defects)
|
||||
|
||||
- No HTTP caching on the public endpoint (NFR-OFF-02, Q2=B) — deliberate, revisit if traffic ever
|
||||
makes it worth it.
|
||||
- No full audit-log table for Offerings mutations (SECURITY-13's resolution scope, § 4 above).
|
||||
- Sequential (non-transactional) single-row saves remain outside the three multi-row operations'
|
||||
transaction boundary — intentional per NFR Design Pattern 1's scope.
|
||||
- `SlpModularCms.Api`'s own pipeline regression tests (`Api.Tests`, NFR-CS-01) don't separately cover
|
||||
`Api.SlpSoftware` — accepted trade-off from Unit 1, unchanged by this feature.
|
||||
|
||||
## 10. Verdict
|
||||
|
||||
**Ready for production, contingent on completing the one host-side action in § 6.1.** All
|
||||
functional and non-functional requirements are implemented and traced; all tests pass; security
|
||||
compliance is fully addressed with its one open item formally resolved; monitoring and rollback
|
||||
require no changes. This is a documentation/traceability gate — it does not re-run any build or test
|
||||
already verified at the Build and Test stage.
|
||||
Reference in New Issue
Block a user