Conversation
Backend: - Add ResetToken + ResetTokenExpiry fields to User entity - RequestPasswordReset generates crypto token, stores with 1hr expiry - ResetPassword validates token and updates bcrypt hash - ForgotPassword handler reads SMTP from settings table, sends reset email - ResetPassword handler accepts token + new password - Public routes: POST /api/auth/forgot-password, POST /api/auth/reset-password Frontend: - ForgotPassword.vue — email form with GSAP animations, ambient orbs - ResetPassword.vue — password + confirm form with token from query param - Routes: /forgot-password, /reset-password (both guestOnly) - Forgot password link below password field on login form Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Annotate 18 handler files with @summary, @Param, @success, @router tags. Add SuccessResponseModel/ErrorResponseModel types for swagger references. Add global API info and security definitions in main.go. Add [Admin] prefix to admin-only endpoint summaries. Co-Authored-By: Claude <noreply@anthropic.com>
Install swaggo/swag and echo-swagger packages for OpenAPI spec generation. Co-Authored-By: Claude <noreply@anthropic.com>
Serve Scalar API reference at /api/docs/ instead of Swagger UI. Use wildcard route that serves openapi.json spec or Scalar HTML. Remove echo-swagger dependency import. Co-Authored-By: Claude <noreply@anthropic.com>
Add swag init step before build in build-testing, build-release workflows, and Dockerfile to ensure docs are always up-to-date. Co-Authored-By: Claude <noreply@anthropic.com>
…oint Add API Docs button in API Tokens page (links to Scalar UI). Remove broken status filter dropdown. Proxy /api/docs through Vite dev server. Co-Authored-By: Claude <noreply@anthropic.com>
Cast onSubmit to any to avoid GenericObject type mismatch in template. Co-Authored-By: Claude <noreply@anthropic.com>
Previously swagger.json was read from disk at runtime, causing empty API docs in binary-only deployments (Docker). Now embedded via //go:embed and served from embedded filesystem. Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
* CodeRabbit Generated Unit Tests: Add unit tests for PR changes * 📝 CodeRabbit Chat: Fix response test types and password form handlers (#37) Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Ahmad Rafi'i <70046808+rafia9005@users.noreply.github.com>
- Replace 'Get Started' with 'Live Demo' link to demo-ping.terarush.dev - Add 'API Docs' button linking to /api/docs/ Scalar endpoint - Insert CtaSection component between TeamSection and ContactSection - Ignore landing/ changes in build-release workflow
- Add useUpdateChecker composable fetching latest GitHub release - Compare with current version (v0.1.25) - Show amber 'X available' banner in sidebar footer when update found - Update siteConfig with repo metadata
- Use git describe --tags --always at build time via Vite define - Expose as __APP_VERSION__ global (typed in env.d.ts) - Remove hardcoded currentVersion from siteConfig - useUpdateChecker compares against injected version
…ests Add ping-uptime backend tests
* test: add web unit coverage * test: cover all web composables * chore: enable CodeRabbit reviews on dev --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* test: clean web unit runner output * test: address web unit runner review * test: configure vitest worker warnings * build: suppress DEP0205 in web scripts --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
SQLite strftime with 'localtime' modifier caused inconsistent date grouping across server timezones. Remove modifier, use UTC for all startTime calculations. Also fix unchecked db.Scan error in GetMonitorStats.
Align check_records table with UTC-based timestamps. Remove 'localtime' from DATE() calls in monitor dashboard queries.
Export check_records table alongside existing tables. Import now accepts importUserID to remap user_id ownership — tables with no user_id (check_records, settings, tags, etc.) skip remap.
New /app/overview route with composable-based dashboard showing monitors, SSL certs, incidents, analytics, and resource summaries. Add GalleryVerticalEnd icon to sidebar under Analytics group.
|
Warning Ignoring CodeRabbit configuration file changes. For security, only the configuration from the base branch is applied for open source repositories. 📝 WalkthroughWalkthroughChangesThe PR adds an authenticated overview dashboard, updates backup imports and UTC-based chart handling, and introduces broad Go and frontend test coverage for services, middleware, stores, composables, validations, and utilities. Overview dashboard
Backend consistency and backup restoration
Automated behavior coverage
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
rafia9005
left a comment
There was a problem hiding this comment.
work on testing implementation
Commented in CodeRabbit Change Stack
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
web/vitest.config.ts (1)
12-12: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider using targeted
--disable-warning=DEP0205instead of--no-warningsfor consistency.The
package.jsonscripts use the targeted--disable-warning=DEP0205flag, but the vitest config uses the broader--no-warnings, which suppresses all Node.js process warnings in worker processes. Using--disable-warning=DEP0205here would be consistent and still surface other potentially important warnings (e.g., deprecations, security advisories) during test development.♻️ Suggested alignment
- execArgv: ['--no-warnings'], + execArgv: ['--disable-warning=DEP0205'],🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/vitest.config.ts` at line 12, Replace the broad --no-warnings value in the Vitest configuration’s execArgv with the targeted --disable-warning=DEP0205 flag, matching the package scripts while preserving other Node.js warnings.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@modules/backup/domain/service/backup_service.go`:
- Around line 64-92: The integrations restore currently passes user ID 0,
leaving imported records associated with the backup owner. In the restore flow
of the backup service, update the integrations restoreTable call to pass
importUserID, while leaving tags and ssl_certs unchanged.
In `@web/src/views/App.Overview.vue`:
- Around line 447-523: Make every quick-navigation tile currently implemented as
a clickable div keyboard accessible, including the elements using navigateTo for
monitors, ssl-monitors, status-pages, incidents, maintenances,
settings/notifications, integrations, tags, api-tokens, users, and teams.
Replace each with a semantic button or router link, preserving styling and
conditional isAdmin rendering, and ensure activation invokes the existing
navigateTo destination for both keyboard and pointer users.
---
Nitpick comments:
In `@web/vitest.config.ts`:
- Line 12: Replace the broad --no-warnings value in the Vitest configuration’s
execArgv with the targeted --disable-warning=DEP0205 flag, matching the package
scripts while preserving other Node.js warnings.
🪄 Autofix (Beta)
✅ Autofix completed
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 3d611182-bda7-4a78-9757-000918e52ddd
📒 Files selected for processing (29)
.coderabbit.yamlinternal/pkg/jwt/jwt_test.gointernal/pkg/middleware/auth_test.gomodules/analytics/domain/repository/analytics_repository_impl.gomodules/auth/domain/service/auth_service_test.gomodules/backup/domain/service/backup_service.gomodules/backup/domain/service/backup_service_test.gomodules/backup/handler/backup_handler.gomodules/monitors/domain/entity/check_record.gomodules/monitors/domain/repository/monitor_repository_impl.gomodules/users/domain/service/user_service_test.goweb/package.jsonweb/src/composables/__tests__/storeBindings.test.tsweb/src/composables/__tests__/useApiTokens.test.tsweb/src/composables/__tests__/useAppTitle.test.tsweb/src/composables/__tests__/useIncidents.test.tsweb/src/composables/__tests__/useNotificationLogs.test.tsweb/src/composables/__tests__/useSslMonitors.test.tsweb/src/composables/__tests__/useUpdateChecker.test.tsweb/src/content/sidebar.tsweb/src/lib/__tests__/utils.test.tsweb/src/router/index.tsweb/src/stores/__tests__/authStore.test.tsweb/src/stores/__tests__/backupStore.test.tsweb/src/stores/__tests__/dataStores.test.tsweb/src/stores/__tests__/realtimeStores.test.tsweb/src/validations/__tests__/schemas.test.tsweb/src/views/App.Overview.vueweb/vitest.config.ts
| if err := s.restoreTable(ctx, "monitors", backup.Data.Monitors, importUserID); err != nil { | ||
| return fmt.Errorf("restore monitors: %w", err) | ||
| } | ||
| if err := s.restoreTable(ctx, "incidents", backup.Data.Incidents); err != nil { | ||
| // check_records has no user_id; monitor_id preserved, so no remap. | ||
| if err := s.restoreTable(ctx, "check_records", backup.Data.CheckRecords, 0); err != nil { | ||
| return fmt.Errorf("restore check_records: %w", err) | ||
| } | ||
| if err := s.restoreTable(ctx, "incidents", backup.Data.Incidents, importUserID); err != nil { | ||
| return fmt.Errorf("restore incidents: %w", err) | ||
| } | ||
| if err := s.restoreTable(ctx, "status_pages", backup.Data.StatusPages); err != nil { | ||
| if err := s.restoreTable(ctx, "status_pages", backup.Data.StatusPages, importUserID); err != nil { | ||
| return fmt.Errorf("restore status_pages: %w", err) | ||
| } | ||
| if err := s.restoreTable(ctx, "settings", backup.Data.Settings); err != nil { | ||
| if err := s.restoreTable(ctx, "settings", backup.Data.Settings, 0); err != nil { | ||
| return fmt.Errorf("restore settings: %w", err) | ||
| } | ||
| if err := s.restoreTable(ctx, "notification_channels", backup.Data.NotificationChannels); err != nil { | ||
| if err := s.restoreTable(ctx, "notification_channels", backup.Data.NotificationChannels, importUserID); err != nil { | ||
| return fmt.Errorf("restore notification_channels: %w", err) | ||
| } | ||
| if err := s.restoreTable(ctx, "tags", backup.Data.Tags); err != nil { | ||
| if err := s.restoreTable(ctx, "tags", backup.Data.Tags, 0); err != nil { | ||
| return fmt.Errorf("restore tags: %w", err) | ||
| } | ||
| if err := s.restoreTable(ctx, "integrations", backup.Data.Integrations); err != nil { | ||
| if err := s.restoreTable(ctx, "integrations", backup.Data.Integrations, 0); err != nil { | ||
| return fmt.Errorf("restore integrations: %w", err) | ||
| } | ||
| if err := s.restoreTable(ctx, "ssl_certs", backup.Data.SSLCerts); err != nil { | ||
| if err := s.restoreTable(ctx, "ssl_certs", backup.Data.SSLCerts, 0); err != nil { | ||
| return fmt.Errorf("restore ssl_certs: %w", err) | ||
| } | ||
| if err := s.restoreTable(ctx, "api_tokens", backup.Data.ApiTokens); err != nil { | ||
| if err := s.restoreTable(ctx, "api_tokens", backup.Data.ApiTokens, importUserID); err != nil { |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Inspect ownership columns for the no-remap tables
rg -nP -C2 'user_id|UserID' -g '*ssl*' -g '*integration*' -g '*tag*' --type=goRepository: terarush/ping-uptime
Length of output: 158
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find model/migration/schema definitions for the suspected tables
printf '\n== matching files ==\n'
git ls-files | rg '(^|/)(ssl_certs|integrations|tags)(/|\.|$)|backup_service\.go|migration|schema|model|models|entity|entities'
printf '\n== search for table names and ownership fields ==\n'
rg -n --hidden -S 'ssl_certs|integrations|tags|user_id|UserID|owner_id|OwnerID|account_id|AccountID' .
printf '\n== file outlines (if present) ==\n'
for f in $(git ls-files | rg '(^|/)(ssl_certs|integrations|tags)(/|\.|$)'); do
echo "\n--- $f ---"
wc -l "$f"
sed -n '1,220p' "$f" | cat -n | sed -n '1,220p'
doneRepository: terarush/ping-uptime
Length of output: 50377
🏁 Script executed:
#!/bin/bash
set -euo pipefail
for f in \
modules/integrations/domain/entity/integration.go \
modules/tags/domain/entity/tag.go \
modules/ssl_monitors/domain/entity/ssl_cert.go \
modules/backup/domain/service/backup_service.go
do
echo "===== $f ====="
wc -l "$f"
cat -n "$f" | sed -n '1,220p'
echo
doneRepository: terarush/ping-uptime
Length of output: 10725
Remap integrations here. modules/integrations/domain/entity/integration.go has a UserID, so 0 leaves imported rows tied to the backup owner instead of the importing account. tags and ssl_certs don’t carry ownership fields, so those are fine.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@modules/backup/domain/service/backup_service.go` around lines 64 - 92, The
integrations restore currently passes user ID 0, leaving imported records
associated with the backup owner. In the restore flow of the backup service,
update the integrations restoreTable call to pass importUserID, while leaving
tags and ssl_certs unchanged.
| <div @click="navigateTo('monitors')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors"> | ||
| <div class="p-1.5 rounded-md shrink-0 bg-emerald-500/10"><Activity class="w-3.5 h-3.5 text-emerald-500" /></div> | ||
| <div class="min-w-0"> | ||
| <p class="text-[11px] font-bold truncate">Monitors</p> | ||
| <p class="text-[9px] text-muted-foreground">{{ monitors.length }}</p> | ||
| </div> | ||
| </div> | ||
| <div @click="navigateTo('ssl-monitors')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors"> | ||
| <div class="p-1.5 rounded-md shrink-0 bg-blue-500/10"><ShieldCheck class="w-3.5 h-3.5 text-blue-500" /></div> | ||
| <div class="min-w-0"> | ||
| <p class="text-[11px] font-bold truncate">SSL</p> | ||
| <p class="text-[9px] text-muted-foreground">{{ certs.length }}</p> | ||
| </div> | ||
| </div> | ||
| <div @click="navigateTo('status-pages')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors"> | ||
| <div class="p-1.5 rounded-md shrink-0 bg-indigo-500/10"><Globe class="w-3.5 h-3.5 text-indigo-500" /></div> | ||
| <div class="min-w-0"> | ||
| <p class="text-[11px] font-bold truncate">Status Pages</p> | ||
| <p class="text-[9px] text-muted-foreground">{{ statusPages.length }}</p> | ||
| </div> | ||
| </div> | ||
| <div @click="navigateTo('incidents')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors"> | ||
| <div class="p-1.5 rounded-md shrink-0 bg-rose-500/10"><AlertCircle class="w-3.5 h-3.5 text-rose-500" /></div> | ||
| <div class="min-w-0"> | ||
| <p class="text-[11px] font-bold truncate">Incidents</p> | ||
| <p class="text-[9px] text-muted-foreground">{{ incidents.length }}</p> | ||
| </div> | ||
| </div> | ||
| <div @click="navigateTo('maintenances')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors"> | ||
| <div class="p-1.5 rounded-md shrink-0 bg-amber-500/10"><Wrench class="w-3.5 h-3.5 text-amber-500" /></div> | ||
| <div class="min-w-0"> | ||
| <p class="text-[11px] font-bold truncate">Maintenances</p> | ||
| <p class="text-[9px] text-muted-foreground">{{ maintenances.length }}</p> | ||
| </div> | ||
| </div> | ||
| <div @click="navigateTo('settings/notifications')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors"> | ||
| <div class="p-1.5 rounded-md shrink-0 bg-purple-500/10"><Bell class="w-3.5 h-3.5 text-purple-500" /></div> | ||
| <div class="min-w-0"> | ||
| <p class="text-[11px] font-bold truncate">Channels</p> | ||
| <p class="text-[9px] text-muted-foreground">{{ channels.length }}</p> | ||
| </div> | ||
| </div> | ||
| <div @click="navigateTo('integrations')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors"> | ||
| <div class="p-1.5 rounded-md shrink-0 bg-cyan-500/10"><Link class="w-3.5 h-3.5 text-cyan-500" /></div> | ||
| <div class="min-w-0"> | ||
| <p class="text-[11px] font-bold truncate">Integrations</p> | ||
| <p class="text-[9px] text-muted-foreground">{{ integrations.length }}</p> | ||
| </div> | ||
| </div> | ||
| <div @click="navigateTo('tags')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors"> | ||
| <div class="p-1.5 rounded-md shrink-0 bg-pink-500/10"><Tag class="w-3.5 h-3.5 text-pink-500" /></div> | ||
| <div class="min-w-0"> | ||
| <p class="text-[11px] font-bold truncate">Tags</p> | ||
| <p class="text-[9px] text-muted-foreground">{{ tags.length }}</p> | ||
| </div> | ||
| </div> | ||
| <div @click="navigateTo('api-tokens')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors"> | ||
| <div class="p-1.5 rounded-md shrink-0 bg-orange-500/10"><KeyRound class="w-3.5 h-3.5 text-orange-500" /></div> | ||
| <div class="min-w-0"> | ||
| <p class="text-[11px] font-bold truncate">API Tokens</p> | ||
| <p class="text-[9px] text-muted-foreground">{{ tokens.length }}</p> | ||
| </div> | ||
| </div> | ||
| <div v-if="isAdmin" @click="navigateTo('users')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors"> | ||
| <div class="p-1.5 rounded-md shrink-0 bg-sky-500/10"><Users class="w-3.5 h-3.5 text-sky-500" /></div> | ||
| <div class="min-w-0"> | ||
| <p class="text-[11px] font-bold truncate">Users</p> | ||
| <p class="text-[9px] text-muted-foreground">{{ users.length }}</p> | ||
| </div> | ||
| </div> | ||
| <div v-if="isAdmin" @click="navigateTo('teams')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors"> | ||
| <div class="p-1.5 rounded-md shrink-0 bg-violet-500/10"><UsersRound class="w-3.5 h-3.5 text-violet-500" /></div> | ||
| <div class="min-w-0"> | ||
| <p class="text-[11px] font-bold truncate">Teams</p> | ||
| <p class="text-[9px] text-muted-foreground">{{ teams.length }} ({{ teams.reduce((s, t) => s + (t.member_count || 0), 0) }} members)</p> | ||
| </div> | ||
| </div> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Quick-navigation tiles are not keyboard accessible.
These tiles use <div @click="navigateTo(...)"> with no role, tabindex, or key handler, so keyboard and screen-reader users cannot focus or activate them. Use a semantic interactive element (e.g., <button> or a router link) so navigation works without a pointer.
♿ Example fix for one tile (apply the pattern to all)
- <div `@click`="navigateTo('monitors')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors">
+ <button type="button" `@click`="navigateTo('monitors')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors text-left w-full">
<div class="p-1.5 rounded-md shrink-0 bg-emerald-500/10"><Activity class="w-3.5 h-3.5 text-emerald-500" /></div>
<div class="min-w-0">
<p class="text-[11px] font-bold truncate">Monitors</p>
<p class="text-[9px] text-muted-foreground">{{ monitors.length }}</p>
</div>
- </div>
+ </button>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@web/src/views/App.Overview.vue` around lines 447 - 523, Make every
quick-navigation tile currently implemented as a clickable div keyboard
accessible, including the elements using navigateTo for monitors, ssl-monitors,
status-pages, incidents, maintenances, settings/notifications, integrations,
tags, api-tokens, users, and teams. Replace each with a semantic button or
router link, preserving styling and conditional isAdmin rendering, and ensure
activation invokes the existing navigateTo destination for both keyboard and
pointer users.
|
Note Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it. Fixes Applied SuccessfullyFixed 2 file(s) based on 2 unresolved review comments. A stacked PR containing fixes has been created.
Time taken: |
Summary
4 commits on dev, grouped by subsystem:
fix(analytics): strip 'localtime' from strftime, align timestamps to UTC
localtimemodifier from all date grouping queriesdb.Scanerror inGetMonitorStatsfix(monitors): use UTC for CheckRecord timestamp and queries
NewCheckRecordusestime.Now().UTC()localtimemodifierfeat(backup): include check_records, add user_id remapping on import
check_recordstableImportacceptsimportUserIDparameter to remap ownershipuser_id(settings, tags, ssl_certs, etc.) skip remapfeat(web): add Overview dashboard page with sidebar and route
/app/overviewroute with composable-driven dashboardGalleryVerticalEndiconSummary by CodeRabbit
New Features
Bug Fixes
Tests