Skip to content

Spec 023 — Website monitor MVP (CRUD + manual probe + check history)#70

Merged
Copxer merged 3 commits into
mainfrom
spec/023-website-monitor-mvp
May 1, 2026
Merged

Spec 023 — Website monitor MVP (CRUD + manual probe + check history)#70
Copxer merged 3 commits into
mainfrom
spec/023-website-monitor-mvp

Conversation

@Copxer
Copy link
Copy Markdown
Owner

@Copxer Copxer commented May 1, 2026

Closes #69

Spec: specs/phase-5-monitoring/023-website-monitor-mvp.md

First spec of phase 5. Stand up the data layer for website uptime monitoring plus a working CRUD UX with a sync manual "Probe now" that records a real HTTP check. Scheduler is spec 024; Overview KPI integration + Reverb live updates ride spec 025.

Summary

  • 2 migrations: websites + website_checks tables.
  • 2 enums: WebsiteStatus (includes pending), WebsiteCheckStatus (Up/Down/Slow/Error only — checks only exist after a probe ran).
  • WebsiteProbeResult immutable DTO + RunWebsiteProbeAction (pure HTTP, no DB writes; classifies up/slow/down/error against a 3000ms hard threshold) + RecordWebsiteCheckAction (persists a check, updates Website.last_*, treats Slow as success).
  • WebsitePolicy gates create/update/delete/probe to project owners; any verified user can view (matches RepositoryPolicy phase-1 conventions — see "Known limitations" below).
  • WebsiteController resourceful CRUD + WebsiteProbeController single-action sync probe. Routes nested under /monitoring/* so phase-6 hosts can sit beside it. Sidebar Monitoring entry flipped from disabled → linked.
  • 4 Vue pages: Index (cross-project list), Create + Edit (form), Show (header with Probe now / Edit / Delete + recent-checks list).

Test plan

  • vendor/bin/pint --test passes.
  • php artisan test — 19 net new passing tests across 5 files (probe action 6, record action 6, policy 4, controller 9 / 3 new GET pass; 6 POST/PATCH/DELETE hit the env-CSRF baseline; probe controller 3 — all POST, env-CSRF). Full suite 310 passed (was 291). The 10 new local failures are the same env-CSRF (419) baseline affecting every POST test in the repo; CI passes them.
  • npm run build clean.
  • Manual smoke (post-merge): create a monitor for https://example.com, observe it lands on the Show page; click "Probe now", observe a check row + status update; edit + delete flows.

Self-review notes

Self-review pass via superpowers:code-reviewer; addressed all 3 recommendations:

  • Narrowed the probe action's catch list to ConnectionException|RequestException so programmer bugs (typo, future enum drift, OOM) bubble up loudly instead of getting silently classified as "site down."
  • Belt-and-suspenders authorize in WebsiteController::store after validation — mirrors RepositoryController::store, prevents a stale prop from slipping past.
  • Migration column comment on response_time_ms clarifies it's wall-clock (DNS / TCP / TLS / send / receive), not server-reported TTFB. Future timing fields (per spec 023's "Out of scope" + roadmap §8.8 "Later") will sit alongside.

Known limitations

  • Single-tenant view parity: any verified user can view any website by ID — same single-tenant gap as RepositoryPolicy. The index query scopes correctly; the show route doesn't tighten beyond verified-auth. Uniform fix when teams ship.
  • Slow threshold = 3000ms hard-coded. Per-website configuration is a future polish if real users complain.
  • response_time_ms is wall-clock. Per-leg DNS / TCP / TLS / TTFB timings land in a future spec per §8.8's "Later" list.

Phase 5 progress after merge

# Spec Status
023 Website monitor MVP 🟢 (this PR)
024 Scheduled checks + uptime calc + activity events ⬜ next
025 Overview integration + Reverb live updates + perf charts

Copxer added 3 commits April 30, 2026 18:57
Phase 5 starts here. Folder + README + spec markdown for the data
layer (websites + website_checks tables, WebsiteProbeAction +
RecordWebsiteCheckAction) plus CRUD UX and a sync manual "Probe now".
Spec 024 will add the scheduler + uptime calc + activity events;
spec 025 wires the Overview KPI + Reverb live updates.
First spec of phase 5. Stand up website uptime monitoring data layer
plus a working CRUD UX with a sync manual "Probe now" that records a
real HTTP check.

- New `websites` + `website_checks` tables. Two enums:
  WebsiteStatus (includes `pending`) and WebsiteCheckStatus (Up/
  Down/Slow/Error only — checks only exist after a probe ran).
- WebsiteProbeResult DTO carries the probe outcome between the pure
  RunWebsiteProbeAction (HTTP, no DB) and the
  RecordWebsiteCheckAction (persistence). Probe classifies:
    Up      → request succeeded with expected_status_code
    Slow    → success but response_time_ms > 3000ms (hard threshold
              phase-1; per-website config is future polish)
    Down    → request succeeded but status code mismatched
    Error   → DNS / TCP / TLS / timeout / connection refused
  Slow is treated as a successful run for the parent
  Website.last_success_at update.
- Catch list narrowed to ConnectionException|RequestException —
  programmer bugs (typo, future enum drift, OOM) bubble up loudly
  instead of getting silently classified as "site down."
- WebsitePolicy gates create/update/delete/probe to project owners;
  any verified user can view (matches RepositoryPolicy phase-1
  conventions; cross-tenant uniform fix when teams ship).
- WebsiteController resourceful + WebsiteProbeController single-
  action sync probe. Sync because the user clicked the button —
  they want the result. Spec 024's scheduler is where async becomes
  the natural mode; the same RecordWebsiteCheckAction is reused on
  both paths.
- Form requests StoreWebsiteRequest + UpdateWebsiteRequest validate
  field shapes; project_id is intentionally NOT editable post-create
  (moving a website between projects would orphan its check history).
  WebsiteController::store re-authorises via the policy after
  validation (belt-and-suspenders, matches RepositoryController).
- Routes nested under /monitoring/* so phase-6 hosts can sit beside
  it as /monitoring/hosts/*. Sidebar `Monitoring` entry flipped
  from disabled → routeName: monitoring.websites.index.
- 4 Vue pages: Index (cross-project list), Create + Edit (form),
  Show (header with Probe now / Edit / Delete + recent-checks list).

Tests: 28 new tests across 5 files (probe action, record action,
policy, controller, probe controller). 19 net new passing tests;
full suite 310 passed (was 291). The 10 new env-CSRF POST/PATCH/
DELETE failures are the same baseline pattern affecting every POST
test in the repo locally — CI passes them.

Self-review pass via superpowers:code-reviewer; addressed all 3
recommendations (narrowed catch list, belt-and-suspenders authorize,
column comment on response_time_ms clarifying it's wall-clock not
server-reported TTFB).

Spec 024 will add the scheduler (DispatchDueWebsiteChecksJob +
RunWebsiteCheckJob), uptime % calculation, and activity event
creation on status transitions. Spec 025 wires the Overview KPI
widget + Reverb live updates.
Spec 023's create() called authorize('create', [Website::class, null])
when no ?project_id= was provided, returning 403. The form needs to
open so the user can pick one of their own projects from the dropdown
— store() re-authorises at submit time once project_id is in the
request.

Coarsen the page-level gate to viewAny (any verified user) and demote
the preselect lookup to a soft-narrow: a foreign or non-existent
project ID drops to null instead of 403'ing.
@Copxer Copxer merged commit 97f9d35 into main May 1, 2026
1 check passed
@Copxer Copxer deleted the spec/023-website-monitor-mvp branch May 1, 2026 02:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Spec 023 — Website monitor MVP (CRUD + manual probe + check history)

1 participant