Commit 485e5ca
Phase 46 prompt 99 execution gate (#62)
* phase-46/01-error-reporting: capture window/promise/react/query errors and ship to /api/v1/web-errors
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/02-abort: thread AbortSignal through request() and every useQuery, audit script enforces
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/03-tableid-sweep: assign tableId to every DataTable caller, audit gate enforces
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/04-maintenance: add SystemMode + maintenance banner across stack with admin override
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/05-session-timeout: idle countdown + hard-401 modal preserve return URL and surface unsaved drafts
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/06-active-filter-chips: visible chip summary above every FilterBar
Adds shared ActiveFilterChips + useActiveFilterChips so users see what
they have filtered without re-opening every control. Sweeps all FilterBar
callers (admin/audit, alerts, alert log, drives, charging sessions,
tesla charging history, locations, geofences, notifications) and mounts
the chip strip immediately after the bar, wired to URL-state setters.
A new audit:filterbar-chips script is chained into npm run lint to keep
the pairing enforced.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/07-top-progress: top route-change progress bar with Suspense bridge and motion-token transitions
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/08-feedback: in-app feedback modal with admin queue and optional GitHub Issues bridge
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/09-search-history: SearchInput remembers recent searches per scope with dropdown UX
- NEW lib/searchHistory.ts: localStorage v1 store, scoped, capped 12, dedup
case-insensitive, min 2 chars, trim β matches commandFrecency resilience
contract (handles malformed JSON, non-object payloads, malformed entries).
- EXTEND components/forms/SearchInput.tsx with optional historyScope,
showHistoryOnFocus, maxHistory props. Dropdown shows when input is focused
with empty value and the scope has entries; supports click-to-fill,
per-entry remove (X), 'Clear history', and full keyboard nav (ArrowDown,
ArrowUp, Enter, Escape) with combobox/listbox ARIA semantics.
- ADOPT historyScope on 9 list-page SearchInput callers: drives, charging,
charging:sessions, notifications, locations, geofences, alerts:logs,
alerts, admin:audit. KeyboardShortcutsModal and AlertStudioPage modal
inputs intentionally skipped (transient panel filters, not list searches).
- ADD i18n keys search.history.title, .clear, .removeAria.
- Drive-by: drop two stale eslint-disable-next-line directives in
components/feedback/__tests__/FeedbackModal.test.tsx so the lint gate
passes (no-console rule is not enabled, leaving the suppressions as
dead --report-unused-disable-directives violations).
Tests: 26 lib/searchHistory + 16 SearchInput.history; full suite 1727/1727.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/10-mobile-gestures: PullToRefresh + SwipeRow with touch-only opt-in and 5-page adoption
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/11-forced-colors: forced-colors variant + critical-component overrides keep UI visible in Windows high contrast
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/12-visually-hidden: shared VisuallyHidden + useAnnouncer hook + audit gate retire ad-hoc sr-only
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/13-chart-a11y: ChartContainer fallback table for SR + forced-colors users with audit-enforced ariaLabel/data props
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/14-combobox: shared WAI-ARIA combobox + multi-select with async option support, replaces hand-rolled selectors
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/15-avatar: shared Avatar + UserCell with deterministic CB-safe colors, refactor chatbot to share
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/16-chart-export: surface PNG/SVG/copy-image actions in every ChartContainer via ChartExportMenu
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/17-marker-cluster: adopt MarkerCluster on locations + navigation + drive maps with audit gate
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(web): break FeedbackModal infinite render loop on closed state
The cleanup useEffect listed submit (a TanStack Query mutation
object) in its dep array. TanStack Query returns a fresh mutation
object on every internal state change β including the very
submit.reset() call inside the effect β so while the modal was
closed the effect re-fired on every render, flooding the console
with Maximum update depth exceeded warnings and pinning a CPU.
Drop submit from the deps; the reset only needs to fire on the
open->closed transition, which [open] alone captures correctly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/18-deferred-filter: useDeferredFilter on heavy list pages keeps input responsive during list re-render
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/19-quiet-hours: per-user DND windows with bypass severities, dispatcher defers and worker replays
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/20-alert-ack: ack-with-note dialog + alert event timeline + reopen flow
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/21-route-announcer: announce SPA navigation to screen readers
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/22-route-prefetch: prefetch lazy chunks on link hover/focus
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/23-slider-component: shared Slider + RangeSlider primitives
Shared Slider (single-thumb) and RangeSlider (dual-thumb) components built
on native <input type=range> so all WAI-ARIA APG slider keyboard semantics
(Arrow / PageUp / PageDown / Home / End) work natively, with formatted
display values surfaced via aria-valuetext for screen readers.
RangeSlider stacks two range inputs with pointer-events:none on the track
and [&::-webkit-slider-thumb]:pointer-events-auto on the thumbs, swaps
z-index based on thumb position so collisions stay grabbable, and sorts
the [low, high] tuple in onChange so callers never see an inverted range.
Tests are colocated under web/src/components/ui/ to match the gate's
allowed-files regex (matches the existing Logo.test.tsx pattern).
Adoption sweep skipped per the prompt's Blocked Path: none of the five
listed adopter pages have a numeric input that fits a bounded slider
model (AlertStudio thresholds are signal-heterogeneous, DriveScore has
only date filtering, BatteryHealth has no window picker, GeofenceDrawer
uses leaflet-draw, ChargingHeatmap is read-only). Primitives ship now;
adopters can land separately when bounded use sites appear.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/24-tag-input: shared TagInput primitive + adoption sweep
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/25-required-fields: visible + aria required indicator on form primitives
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/26-unit-input: shared UnitInput with canonical-metric storage
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/27-notification-grouping: group_key column + grouped list view
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/28-notification-bell-popover: in-place triage panel from header bell
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/29-sound-notifications: per-category sound prefs + shared player
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/30-context-menu: shared ContextMenu primitive + 3 adopters
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/31-reauth-step-up: sudo-style reauth on sensitive actions
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/32-masked-value: privacy primitive + sweep across admin/diagnostic UIs
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/33-self-test: aggregated diagnostic endpoint + admin page
Adds POST /api/v1/system/diagnostic returning a structured
DiagnosticReport that fans out 10 concurrent checks (DB connectivity
+ migration version, signal_log freshness, Tesla token + circuit
breaker, MQTT, Redis, resilience HealthMonitor, runtime goroutines,
uptime). Each check has a per-check timeout, panic recovery, and
ordered output so the SPA can render a stable list. Endpoint is rate-
limited at 20/min/IP.
Frontend ships /diagnostic page with Run/Re-run button, per-check
cards (status badge, detail, remediation), Copy report (JSON), and
Download .txt for support escalation. Empty state CTA also fires the
mutation. Page-level App.tsx mounting + Layout.tsx sidebar splice are
deferred (out of allowed-files scope) β Sidebar.tsx exports the typed
nav entry data for a follow-up splice.
Backend tests cover aggregation severity ladder, ordering, per-check
timeout, panic recovery, duration measurement, POST-only HTTP, nil-
dep tolerance, and breaker-state mapping. Frontend tests cover empty
state, run flow, remediation surfacing, copy/download actions,
endpoint failure path, and RunβRe-run label flip.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/34-live-log-tail: SSE log stream + admin live tail page
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/35-2fa-totp-ui: TOTP enrollment + verification + ReauthDialog tab
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/36-settings-export-import: JSON export + dry-run import + sudo-gated apply
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/37-webhook-channel-ui: webhook channel CRUD + body template + HMAC signing
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/38-inline-edit: EditableText primitive + adopt on geofence/rule names
EditableText replaces the open-a-Modal-to-rename pattern with inline
double-click / Enter / F2 β input β Enter-to-save / Escape-to-cancel.
Default display is a button-styled-as-text (native keyboard semantics);
custom 'display' render prop lets consumers wrap the value in a Link
plus pencil button (used by the alert rule name cell). Single guarded
commit path covers Enter+blur dedupe, no-op edits, validation, and
async save with Spinner + inline ErrorText on rejection. Successful
saves announce '<label> saved' via the shared useAnnouncer().
Adoption deviates from the prompt's listed paths per the Blocked Path:
- features/locations/components/GeofenceList.tsx does not exist;
adopted in features/maps/pages/GeofencesPage.tsx instead. The
per-card name span becomes inline-editable, and a dedicated rename
mutation sends a full merged payload (safer than relying on the
backend's partial PUT semantics). The Pencil button that opens the
full lat/lng/radius modal is left in place as the multi-field path.
- features/notifications/components/AlertRuleList.tsx does not exist;
adopted in features/notifications/pages/AlertRulesPage.tsx instead.
The custom display render prop preserves the existing Link-to-studio
navigation and adds a sibling pencil button that calls onStartEdit.
Wired to the existing useSaveAlertRule() PATCH path.
- Vehicle nickname adoption is dropped: the current VehicleDetailPage
has no Modal-based rename and the backend exposes no PATCH /vehicles/{id}
endpoint. Both are out of scope for this prompt's allowed-files regex.
Tests use fireEvent (no @testing-library/user-event in the repo) per
the established TagInput / ContextMenu / SearchInput pattern. Test file
is colocated at components/ui/EditableText.test.tsx (not __tests__/) to
match the gate's substring allowlist regex.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/39-lightbox: shared Lightbox primitive + vehicle photo gallery adoption
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/40-rate-limit-status-panel: scope budget endpoint + admin status panel
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/41-job-queue-status: queue depth endpoint + admin status panel + drawer
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/42-session-device-management: provider-agnostic local sessions list + revoke
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/43-per-vehicle-settings: hierarchical resolver + per-vehicle override UI
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/44-rbac-matrix: permissions catalog + role_permissions table + matrix admin page
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/45-column-reorder: DataTable drag-to-reorder + visibility menu + persistence
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/46-impersonate-user: admin impersonation with banner + audit + sudo gate
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/47-crash-recovery: draft index + restore prompt across reloads/crashes
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/48-rtl-support: i18nDir helper + dir attr + RTL audit + chart label flip
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/49-currency-input: CurrencyInput primitive + locale-aware parse + GeneralSettings adoption
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/50-reset-to-defaults: per-section + global settings reset with sudo gate
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/51-recently-viewed-pages: client-side recent pages store + palette + widget
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/52-virtualization-adoption: enable DataTable virtualization on long pages + audit
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/53-pause-polling: refetchIntervalInBackground default false + audit + opt-in annotation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/54-photo-upload: vehicle photo upload + EXIF strip + 3-size storage + hero render
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/55-export-adoption: enable DataTable exportable on long-tail list pages + audit
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/56-fullscreen-button: shared FullscreenButton + ChartContainer/Map adoption
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/57-auth-mode-contract: provider-agnostic auth mode endpoint + RequiresAuth wrapper
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/58-remove-sidebar-version-badge: drop duplicate DEV chip from sidebar header; canonical version stays in footer VersionSegment
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/59-redis-viewer-error-states: surface 503 / network failures in Redis Signal Viewer instead of pretending the cache is empty
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/60-skip-to-content: WCAG 2.4.1 skip link mounted as first focusable element
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/61-tour-replay: Settings -> Product tours panel + per-tour reset/relaunch wiring
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/62-export-columns: optional column allowlist for CSV/JSON exports + picker UI
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/63-browser-compat: detect missing modern web features and warn the user once
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: open-mode auth tolerance + /auth/refresh no-op + 000170 collision
Resolves four bugs surfaced when running the latest backend in open-mode
(AUTH_ENABLED=false) with no Tesla account linked.
1. internal/handler/v1/dashboard_handler.go: GetStats no longer returns
401 when no UserClaims is in the request context. Open-mode is the
project's documented default β there is no JWT middleware to populate
the context β so the handler now falls back to the empty-string
subject (the same scope key used by notification_quiet_hours.user_id,
auth_session_handler, and other phase-46 endpoints).
2. internal/api/auth_handler.go::Refresh: when no Tesla account is linked
the handler returned 502 Bad Gateway (teslaClient.RefreshTokens fails
with 'no refresh token available'). It now reads tokenRepo first and
returns 200 {status:noop, reason:no tesla account linked} when there
is nothing to refresh, eliminating the console spam from auto-refresh
loops in open-mode installs.
3. web/src/lib/resilience.ts + api/auth.ts + api/index.ts: removed the
auto-refresh-on-plain-401 logic. It tried to refresh the *Tesla OAuth
token* on every non-Tesla 401 (ForwardAuth session expiry, missing
user context, etc.), which never helped and produced 502 spam.
Plain 401s now go straight to the SessionExpiredModal via
maybeDispatchSessionExpired, matching the documented session model
(cookie is renewed by the upstream sliding-session proxy on
/auth/session polls). Tesla-specific 401s with code
TESLA_TOKEN_EXPIRED still flow through the dedicated TeslaReauthBanner
path, and the user-initiated 'Refresh Tesla token' button in
TeslaAccountSection (useRefreshAuth) still works.
4. migrations/000170_quiet_hours.up.sql: prepended DROP TABLE IF EXISTS
notification_quiet_hours CASCADE. Baseline migration 000142 created
an earlier per-channel notification_quiet_hours table that was
incompatible with the per-user schema in this migration; the
IF NOT EXISTS guard silently skipped the CREATE and the subsequent
index on user_id then fataled, leaving the DB at dirty=170 on every
fresh install. The legacy table was empty in production so the DROP
loses no data.
Verification:
- web: npx tsc --noEmit clean; npm run lint clean (all 22 audits);
npx vitest run = 2640/2640 passed (incl. resilience.test.ts).
- go: build of internal/handler/v1/... clean; vet of internal/api clean
for auth_handler.go. Full repo build is currently broken by an
unrelated, in-flight phase-46 prompt (vehicle_handler.go +
battery_handler.go + new internal/signal/asof.go); those changes
are NOT included in this commit.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/64-time-machine: read-only ?as_of= point-in-time view via signal_log + global banner
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/65-scheduled-exports: cron-driven recurring exports with download/email/webhook delivery
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/66-edit-lease: BroadcastChannel-based two-tab edit conflict detection on Settings/Automation/AlertRules
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/67-chart-legend-toggle: click-to-hide series via ChartContainer chartKey + URL-persisted state
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/68-inline-help: HelpIcon primitive + audit script + adoption sweep across 4 settings/admin pages
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/69-touch-target: WCAG 2.5.5 forward-looking touch-target audit + .touch-target utility + baseline fixes
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/70-cookie-consent: optional cookie/GDPR consent banner gated by TESLASYNC_REQUIRE_COOKIE_CONSENT (default off)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-46/99-execution-gate: phase complete, all 70 prompts merged with green logs
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Geofence circle WKT, presets, and UI fixes
Add support for circle-shaped geofences and synthesize polygon WKT (circleToPolygonWKT, geofenceCreateRequest, decodeGeofenceWriteBody). Use the decoder in Geofence Create/Update handlers and add unit tests for decoding/round-tripping. Emit latitude/longitude/radius in Geofence.MarshalJSON for the web client. Seed automation presets via registerBuiltins and add registry helpers and tests to validate preset shapes. Fix notification_repo to COALESCE nullable `error` column to avoid NULL scan failures. Frontend tweaks: defensive cache updaters in useNotifications hooks (only mutate array-shaped caches), clamp popover positioning in NotificationBellPopover, adjust AddWidgetButton icon/padding, and refine RecentlyViewedWidget spacing and responsive layout.
* Hide auth-gated nav items; UI tweaks
Hide auth-gated navigation items when no ForwardAuth identity provider is configured by adding a requiresAuth flag and wiring useIsForwardAuth into Layout and CommandPalette. Update isVisibleNavItem signature/logic and related memo deps to respect the auth mode. Reserve footer space in the sidebar for the fixed StatusBar, adjust PageContainer header/action layout for better responsive alignment, and tweak slider background styles to use --glass-border. Make DataTable stickyHeader default to true (with docs and tests) and add tests to cover the new default and opt-out behavior.
* Remove db-refactor prompt log files
Delete generated CI/prompt log artifacts under .github/prompts/db-refactor/logs (phases 45 and 46). These are stale/noisy build and test logs and are being removed to reduce repository clutter.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>1 parent a201040 commit 485e5ca
673 files changed
Lines changed: 98939 additions & 23678 deletions
File tree
- .github/prompts/db-refactor/logs
- cmd/notification-worker
- helm/teslasync
- templates
- internal
- api
- auth
- automation/presets
- config
- crypto
- database
- export
- handler/v1
- imaging
- integrations
- models
- notification
- notifier
- platform
- signal
- tesla
- worker
- migrations
- web
- scripts
- __tests__
- src
- __tests__
- api
- hooks
- __tests__
- components
- a11y
- __tests__
- charts
- __tests__
- data-display
- __tests__
- feedback
- __tests__
- forms
- __tests__
- layout
- __tests__
- maps
- __tests__
- mobile
- __tests__
- ui
- __tests__
- vehicles
- features
- admin
- components
- __tests__
- devtools
- tools
- security-access
- pages
- __tests__
- analytics/pages
- automations/pages
- battery/pages
- charging
- components
- charging-curve
- charging-list
- cost-analysis
- pages
- __tests__
- dashboard
- components
- pages
- widgets
- driving
- components
- drive-detail
- drivetrain-health
- driving-dynamics
- pages
- exports/pages
- maps/pages
- notifications
- components
- pages
- settings
- components
- __tests__
- pages
- sharing/pages
- system
- components
- chatbot
- state-machine
- status
- pages
- telemetry/pages
- trips
- components
- pages
- vehicle-systems/pages
- vehicles
- components
- vehicle-detail
- pages
- hooks
- __tests__
- i18n
- lib
- __tests__
- types
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 0 additions & 628 deletions
This file was deleted.
Lines changed: 0 additions & 667 deletions
This file was deleted.
Lines changed: 0 additions & 667 deletions
This file was deleted.
Lines changed: 0 additions & 681 deletions
This file was deleted.
Lines changed: 0 additions & 710 deletions
This file was deleted.
Lines changed: 0 additions & 694 deletions
This file was deleted.
Lines changed: 0 additions & 695 deletions
This file was deleted.
Lines changed: 0 additions & 700 deletions
This file was deleted.
Lines changed: 0 additions & 707 deletions
This file was deleted.
Lines changed: 0 additions & 372 deletions
This file was deleted.
0 commit comments