fix: dashboard & backend improvements#94
Merged
Conversation
- Add data retention with configurable cleanup (default 30 days) and dashboard settings UI with manual prune button - Restrict CORS to configured origins (OPENTOWER_CORS_ORIGIN env var) instead of wildcard; same-origin works without config - Fix token comparison timing leak by using HMAC-based constant-time compare instead of length-gated timingSafeEqual - Migrate cron job form to react-hook-form + zod validation - Replace hand-rolled dialog with Radix-based shadcn dialog (focus trap, proper a11y, escape handling) - Fix per-card mutation state in cron page (toggle/delete/trigger now only show loading on the affected card) - Add ErrorBoundary component wrapping the app - Extract shared isValidUrl utility, replace inline IIFE in dispatches with SessionLink component - Auto-seed email worker allowlist on first email when table is empty - Add structured JSON logger to opentower (replaces ad-hoc console calls with timestamped, leveled JSON lines) - Fix stale README config schema (retention field, add CORS env var, batch_window_ms)
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
opencode-email-worker | 4c001b9 | Commit Preview URL Branch Preview URL |
May 20 2026, 02:15 PM |
- Exclude in-flight dispatches (status='started') from retention prune - Prune orphaned links rows when both sides are deleted - Fix cron form state by unmounting dialog content when closed - Skip retention validation when API client is unavailable - Extract DEFAULT_RETENTION_DAYS to shared constant in storage.ts - Add HMAC key purpose comment in safeTokenCompare - Add OPENTOWER_CORS_ORIGIN to .env.example - Migrate all remaining console.log/warn/error calls to structured logger (index.ts, server.ts, pipeline.ts, cron.ts, config.ts, bot-identity.ts)
The /seed endpoint was redundant — POST /senders can do the same thing. Added clear setup documentation in the file header comment explaining which patterns to create for GitHub notification emails.
- Extract formatError() helper to logger.ts, replace 15+ inline occurrences across all opentower source files - Wire OPENTOWER_LOG_LEVEL env var to configure log level at startup - Exclude pending/running cron executions from retention prune - Include links count in prune total for bootstrap log threshold - Save retention before pruning in settings dialog so the server uses the value the user sees in the input - Fix cron dialog: use reset() on reopen instead of conditional mount (preserves Radix exit animation) - Settings dialog trigger uses DialogTrigger for proper ARIA attrs - Normalize prune response to snake_case (cron_executions)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
retention_daysto config schema,metadatatable to SQLite, and REST endpoints (GET/PUT /api/retention,POST /api/retention/prune). Runs on startup + every 24h.origin: "*"withOPENTOWER_CORS_ORIGINenv var. Same-origin (production) works without config; set the dev server URL during development.timingSafeEqualwith HMAC-based constant-time comparison that doesn't leak token length.react-hook-form+zodschema validation (the deps were already in package.json but unused).aria-modalvia@radix-ui/react-dialog.ErrorBoundarycomponent wrapping the app to prevent full-page crashes on render errors.isValidUrltolib/validation.ts, replace inline IIFE in dispatches page with existingSessionLinkcomponent.console.log/warn/errorin bootstrap and handler.retentionfield, addretention_days,batch_window_ms,OPENTOWER_CORS_ORIGIN).