From 5e704c20eb9c39dfbd52e30cfe9ebcb691eeb9d8 Mon Sep 17 00:00:00 2001 From: Copxer Date: Fri, 1 May 2026 00:52:34 -0700 Subject: [PATCH] =?UTF-8?q?chore(docs):=20refresh=20README=20+=20env.examp?= =?UTF-8?q?le=20for=20phases=204=E2=80=935=20shipped?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Phase status table flips 4 + 5 from ⬜ to 🟒 with one-line per-spec summaries. - "What works today" gains Phase 4 (deployments β€” workflow runs storage + timeline UI + Overview success-rate widget) and Phase 5 (website monitoring β€” monitor MVP + scheduled checks + Overview uptime KPI + Reverb live updates) sections. - composer dev callout notes the scheduler tick is what drives spec 024's monitor probes β€” without it (or a real cron), monitors stay on whatever state the last manual probe left them in. - Repository layout adds the new bounded contexts + directories that shipped (Domain/Monitoring with its Probes/, Events/ for the three broadcast classes, Policies/, Pages/Deployments + Pages/Monitoring, lib/{workflowRunStyles,websiteStyles}.ts). - env.example BROADCAST_CONNECTION comment lists all three live broadcast events (ActivityEventCreated, WorkflowRunUpserted, WebsiteCheckRecorded) instead of just spec 019. No new env keys shipped in phases 4 or 5; AGENT_SHARED_SECRET stays as the placeholder for phase 6. --- .env.example | 10 +++++++--- README.md | 40 ++++++++++++++++++++++++++++++++++------ 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/.env.example b/.env.example index 7659cab..a1b9cc8 100644 --- a/.env.example +++ b/.env.example @@ -34,9 +34,13 @@ SESSION_PATH=/ SESSION_DOMAIN=null BROADCAST_CONNECTION=reverb -# Spec 019 wires `ActivityEventCreated` onto Reverb. Set to `null` -# in environments without a running Reverb daemon (the front-end -# composable degrades gracefully β€” page-load reads still work). +# Reverb carries three live broadcast events as of phase 5: +# β€’ ActivityEventCreated (spec 019, monitoring-aware via spec 024) +# β€’ WorkflowRunUpserted (spec 021, /deployments timeline) +# β€’ WebsiteCheckRecorded (spec 025, per-website show page) +# Set to `null` in environments without a running Reverb daemon β€” +# the front-end composables degrade gracefully (offline pill + +# page-load reads still work). FILESYSTEM_DISK=local QUEUE_CONNECTION=redis diff --git a/README.md b/README.md index ef344a8..53706c8 100644 --- a/README.md +++ b/README.md @@ -22,8 +22,8 @@ Status legend: ⬜ not started Β· 🟑 in progress Β· 🟒 done Β· πŸ”΄ blocked | 1 | Projects & Repositories | 🟒 | 3/3 specs done. | | 2 | GitHub Integration MVP | 🟒 | 4/4 specs done β€” connection, repository import + sync, issues sync, PRs + unified Work Items page. | | 3 | GitHub Webhooks & Activity Feed | 🟒 | 3/3 specs done (017–019). Phase complete. | -| 4 | Deployments & CI/CD | ⬜ | β€” | -| 5 | Website Monitoring | ⬜ | β€” | +| 4 | Deployments & CI/CD | 🟒 | 3/3 specs done (020–022) β€” workflow runs storage + sync, cross-repo timeline UI with realtime, Overview success-rate widget. | +| 5 | Website Monitoring | 🟒 | 3/3 specs done (023–025) β€” monitor MVP + manual probe, scheduled checks + uptime calc + activity events, Overview uptime KPI + Reverb live updates + perf chart. | | 6 | Docker Host Agent MVP | ⬜ | β€” | | 7 | Alerts Engine | ⬜ | β€” | | 8 | Analytics & Health Scores | ⬜ | β€” | @@ -49,6 +49,16 @@ After Phase 3 (complete): - Spec 018 (done) β€” Activity Feed UI. `RecentActivityForUserQuery` powers a shared `activity.recent` Inertia prop registered in `HandleInertiaRequests::share()`, so every authenticated page lights up the right rail with the latest events without per-controller plumbing. New `/activity` page (linked from the sidebar between Alerts and Settings) shows up to 100 events. - Spec 019 (done) β€” Real-time broadcasting via Reverb. `CreateActivityEventAction` dispatches `ActivityEventCreated` (a `ShouldBroadcastNow` event on a private `users.{id}.activity` channel) every time a row lands. Echo + Pusher are wired in `bootstrap.ts`; the `useActivityFeed` composable (`resources/js/lib/`) seeds from the shared prop and prepends broadcast events into the rail and the `/activity` page in real time. Three new webhook handlers (`workflow_run`, `push`, `release`) extend the spec-017 ingestion: workflow runs surface as `workflow.{succeeded,failed}`, releases as `release.published`, and pushes silently update `repositories.last_pushed_at` (no activity row β€” too noisy). When the websocket isn't connected the rail and the activity page show a small "Live updates offline" pill; page-load reads still surface the latest data. +After Phase 4 (complete): +- Spec 020 (done) β€” Workflow runs storage + sync. `workflow_runs` table with FK to `repositories` and the same six-column sync pattern as issues / PRs. `SyncRepositoryWorkflowRunsAction` upserts on `(repository_id, github_id)`; the matching `Job` chains off `SyncGitHubRepositoryJob` so importing a repo backfills its run history. Per-repo Workflow Runs tab on the show page lists status, conclusion, branch, run number, actor, started-at; rows link out to the GitHub Actions run. Spec 019's `WorkflowRunWebhookHandler` now upserts into the new table for every `workflow_run` delivery (queued / in_progress / completed) so the timeline reflects in-flight states. +- Spec 021 (done) β€” Deployment timeline UI. New `/deployments` page renders the cross-repo workflow runs as a chronological timeline. URL-bound filters (project / repository / status / conclusion / branch) survive reload; the repository dropdown narrows client-side based on the selected project. Per-run detail drawer (`Teleport` overlay, slide-from-right, Esc / backdrop / close-button dismiss with focus restoration) shows head SHA, duration, actor, conclusion, and a CTA out to GitHub. Real-time updates via a new `WorkflowRunUpserted` event broadcast on a private `users.{id}.deployments` channel β€” fires from the webhook handler upsert path (not from bulk REST sync, which would flood the channel). Sidebar `Deployments` entry replaces the Phase 4 placeholder; `Pipelines` stays disabled as a future filter view. +- Spec 022 (done) β€” Overview success-rate widget. `GetOverviewDashboardQuery::deploymentsKpi()` aggregates `workflow_runs` over the last 24h (vs the prior 24h) for the headline numbers plus a 12-day daily completed-run sparkline. Returns `successful_24h` (primary value), `success_rate_24h` (integer percent or null when no completed runs landed), `change_percent` (capped `[-100, +999]`), `sparkline`, and a status enum. Window keys on `run_completed_at` (not `run_started_at`) so long-running jobs land in the bucket where they actually completed. The Overview's Deployments KPI card secondary line now reads `92% success` (or `β€”% success` for empty windows) instead of the static "Successful" placeholder. + +After Phase 5 (complete): +- Spec 023 (done) β€” Website monitor MVP. `websites` + `website_checks` tables with `WebsiteStatus` (`pending|up|down|slow|error`) and `WebsiteCheckStatus` enums. `RunWebsiteProbeAction` is a pure HTTP probe (no DB writes) classifying the response into up / slow (>3000ms hard threshold) / down / error; `RecordWebsiteCheckAction` persists the check + updates `Website.{status,last_checked_at,last_success_at,last_failure_at}`. CRUD pages live under `/monitoring/websites/*`; per-site show page hosts a manual "Probe now" button (sync request β†’ instant feedback ≀ `timeout_ms`). Sidebar `Monitoring` entry replaces the Phase 5 placeholder. +- Spec 024 (done) β€” Scheduled checks + uptime calc + activity events. `DispatchDueWebsiteChecksJob` runs every minute (`Schedule::job(...)->everyMinute()->withoutOverlapping()` in `routes/console.php`), filters due websites in PHP (cross-DB compat), and dispatches `RunWebsiteCheckJob` per row. The per-website job reuses the spec-023 actions so manual probes and scheduled probes never drift. `RecordWebsiteCheckAction` detects healthy↔failed category transitions and emits `website.down` / `website.up` activity events on swings (steady-state runs stay silent). Spec 019's `ActivityEventCreated::broadcastOn()` was extended to resolve recipient channels for `source: monitoring` rows via `metadata.website_id β†’ website β†’ project β†’ owner_user_id` so monitoring incidents broadcast in realtime. `GetWebsitePerformanceSummaryQuery` returns count-based uptime % over 24h / 7d / 30d windows + last-incident timestamp; the show page renders a 4-tile uptime stats strip. `RecentActivityForUserQuery` extended to surface monitoring events alongside repo events on the right rail. +- Spec 025 (done) β€” Overview uptime KPI + Reverb live updates + perf chart. `GetMonitoringUptimeKpiQuery` aggregates `website_checks` volume-weighted across **all** the user's monitors over 24h (vs prior 24h) plus a 12-day daily sparkline; replaces the long-standing `MOCK_KPIS['uptime']` on Overview. Empty 24h window β†’ null overall + muted status; status thresholds at 99 / 95. New `WebsiteCheckRecorded` event (`ShouldBroadcastNow`, pre-resolved owner id, `users.{id}.monitoring` channel, light-weight `{check_id, website_id}` pulse) fires from `RecordWebsiteCheckAction` on every persisted check (steady-state runs included; transition events stay separate). The website show page subscribes via Echo, filters client-side by `website_id`, and partial-reloads `website + summary + checks` on each pulse. Response-time `Sparkline` of the last 50 `response_time_ms` values renders in the recent-checks card with leading-null skip + carry-forward fill; `<2 data points` renders a "not enough data" placeholder. + ## Local development ```bash @@ -67,7 +77,7 @@ php artisan storage:link composer dev ``` -`composer dev` runs Laravel, Vite, the queue worker, and the scheduler in parallel via concurrently. For real-time/websocket testing, use `composer dev:horizon` (also runs Reverb + Horizon). +`composer dev` runs Laravel, Vite, the queue worker, and the scheduler in parallel via concurrently. For real-time/websocket testing, use `composer dev:horizon` (also runs Reverb + Horizon). The scheduler tick is what drives spec 024's website-monitor probes β€” without `composer dev` (or a real cron in prod), `DispatchDueWebsiteChecksJob` never fires and monitors stay on whatever state the last manual "Probe now" left them in. ### GitHub App setup @@ -189,21 +199,39 @@ Full workflow: [`.claude/skills/nexus-spec-workflow/SKILL.md`](.claude/skills/ne ``` app/ - Domain/ β€” bounded contexts (GitHub, Repositories, Activity, …) + Domain/ β€” bounded contexts (Activity, Dashboard, GitHub, Monitoring, Repositories, …) {Context}/ Actions/ β€” invokable use-cases Jobs/ β€” ShouldQueue background work Services/ β€” external API wrappers WebhookHandlers/β€” per-event handlers (spec 017+) + Probes/ β€” value objects for probe results (Monitoring) Queries/ β€” read-side query classes Exceptions/ Enums/ β€” string-backed PHP enums (status, severity, …) + Events/ β€” broadcast events (ActivityEventCreated, WorkflowRunUpserted, WebsiteCheckRecorded) Http/Controllers/ + Http/Controllers/Monitoring/ Http/Controllers/Webhooks/ Models/ + Policies/ β€” Gate policies (Project, Repository, Website) resources/js/ - Pages/ β€” Inertia page components (Overview, Projects, Repositories, WorkItems, Settings) - Components/ β€” shared UI (Sidebar, StatusBadge, ActivityFeed once spec 018 lands) + Pages/ β€” Inertia page components + Activity/ + Deployments/ β€” cross-repo timeline + drawer (spec 021) + Monitoring/Websites/β€” monitor CRUD + show (specs 023–025) + Projects/ + Repositories/ + WorkItems/ + Overview.vue Β· Settings/Index.vue Β· Welcome.vue + Components/ + Activity/ β€” ActivityFeed, ActivityFeedItem, ActivityHeatmap + Dashboard/ β€” KpiCard, Sparkline, StatusBadge + Sidebar/ + lib/ + useActivityFeed.ts β€” Echo composable for the right rail (spec 019) + workflowRunStyles.ts β€” shared tone/label maps for workflow runs + websiteStyles.ts β€” shared tone maps for website status Layouts/AppLayout.vue β€” primary chrome (sidebar + topbar + right rail) specs/ README.md β€” phase tracker + per-spec links