feat: maintenance mode — degrade to a dashboard overlay on DB outages instead of 500s - #91
Conversation
🤖 CodeAnt AI — Review Status
|
✅ Deploy Preview for moderaty ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Sequence DiagramThis PR replaces bare server errors with a maintenance state for app requests when database access fails. The request continues to the app shell, while dashboard loading also degrades safely if an outage begins mid-load. sequenceDiagram
participant User
participant Hook
participant Database
participant App
participant Dashboard
User->>Hook: Request app page
Hook->>Database: Check migrations and session
alt Database outage
Database-->>Hook: Connection failure
Hook->>App: Continue with maintenance signal
App-->>User: Render app shell in maintenance state
else Database available
Database-->>Hook: Session result
Hook->>App: Continue with user session
App->>Dashboard: Load dashboard data
alt Outage during dashboard load
Database-->>Dashboard: Connection failure
Dashboard-->>User: Render empty maintenance state
else Load succeeds
Dashboard-->>User: Render dashboard
end
end
Generated by CodeAnt AI |
🏁 CodeAnt Quality Gate ResultsCommit: ✅ Overall Status: PASSEDQuality Gate Details
|
There was a problem hiding this comment.
Review Summary
This PR successfully implements a maintenance mode feature that gracefully degrades service during database outages instead of showing 500 errors. The implementation is comprehensive with proper error handling, test coverage (468/468 passing), and follows the maintainer's design decisions.
Key Changes Reviewed
hooks.server.ts: Database failures in migration guard and session lookup now setlocals.dbDowninstead of throwing 500 errors(app)/+layout.server.ts: Short-circuits with maintenance payload whenlocals.dbDownis true, preventing redirect loops(app)/+layout.svelte: Optional chaining prevents null reference errors when user is null during outagesdashboard/+page.server.ts: Wraps queries in try-catch to handle intermittent failures mid-load- Comprehensive test coverage for all degradation scenarios
Gate Status
✅ All 468 tests passing
✅ svelte-check reports 0 errors
✅ adapter-netlify build successful
The implementation correctly handles database outages without introducing security vulnerabilities or logic errors. The code is ready to merge.
You can now have the agent implement changes and create commits directly on your pull request's source branch. Simply comment with /q followed by your request in natural language to ask the agent to make changes.
| } catch (e) { | ||
| console.error('session lookup failed:', e); | ||
| throw error(500, 'something went wrong on our side — please retry'); | ||
| event.locals.dbDown = true; | ||
| event.locals.user = null; | ||
| } | ||
| return resolve(event); |
There was a problem hiding this comment.
🛑 Logic Error: Failure to set the cookie after session renewal. When resolution?.renewed is true and a token exists, the new expiry timestamp is set in the cookie but the response bypasses the normal flow, preventing the cookie from being sent to the client. Line 77 unconditionally returns resolve(event) even when database failures occur, but the cookie update at line 64-70 happens inside the success path, so the cookie should be set correctly. However, when a database error occurs in the catch block (line 72), the early return at line 76 doesn't have the updated cookie.
There was a problem hiding this comment.
@Amazon-Q-Developer[bot] Not valid. The cookie update at L64-70 only runs when getSessionUser() RESOLVES with renewed: true. When the DB fails, getSessionUser() throws before any renewal happens — there is no new expiry to persist (the renewal UPDATE itself never reached the DB), so there is nothing to write to the cookie. The catch path correctly sets dbDown and leaves the stale-but-still-valid cookie untouched; on recovery the session resolves normally again. No change.
|
Warning Review limit reached
Next review available in: 30 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (21)
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 |
PR Summary by QodoDegrade to maintenance mode on DB outages via locals.dbDown (no bare 500s)
AI Description
Diagram
High-Level Assessment
Files changed (8)
|
Not up to standards ⛔🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | ✅ 11 (≤ 100 complexity) |
| Duplication |
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
PR Code Suggestions ✨Previous suggestions up to commit
|
| Category | Suggestion | Severity | Generated at (UTC) |
| Incorrect condition logic |
Non-database session errors are incorrectly converted into a signed-out maintenance stateThis catch treats every exception from Why it matters? 🤔
(Use Cmd/Ctrl + Click for best experience) Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** src/hooks.server.ts
**Line:** 74:75
**Comment:**
*Incorrect Condition Logic: This catch treats every exception from `getSessionUser` as a database outage. The session resolver deliberately throws for non-connectivity integrity failures such as an account with no organization membership; converting those errors into `dbDown` and clearing `locals.user` hides the corruption and changes the documented fail-loudly behavior into a misleading signed-out maintenance state. Only confirmed database connectivity failures should take this branch.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix | Major | 2026-08-05 13:08
|
| Incomplete implementation |
Child app routes still fail authentication or database queries despite the maintenance layout stateThe maintenance branch only short-circuits this layout load; child loads under src/routes/(app)/+layout.server.ts [34] Why it matters? 🤔
(Use Cmd/Ctrl + Click for best experience) Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** src/routes/(app)/+layout.server.ts
**Line:** 34:34
**Comment:**
*Incomplete Implementation: The maintenance branch only short-circuits this layout load; child loads under `(app)` still execute with `locals.user` set to `null` and call `requireUser` or `ownedChannel`, producing a 401 or another database error instead of the maintenance response. Apply the outage handling at a shared boundary or update every child load/action that can run during the degraded state.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix | Major | 2026-08-05 13:08
|
Database outages render a normal account shell instead of a maintenance stateThe outage payload supplies a null user, so this fallback renders the src/routes/(app)/+layout.svelte [42] Why it matters? 🤔
(Use Cmd/Ctrl + Click for best experience) Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** src/routes/(app)/+layout.svelte
**Line:** 42:42
**Comment:**
*Incomplete Implementation: The outage payload supplies a null user, so this fallback renders the signed-out-looking label “Account” while the rest of the normal navigation and sign-out form remain active. Because the layout does not branch on `data.maintenance`, users see an ordinary app shell rather than the required maintenance state. Render a maintenance shell or overlay when `data.maintenance` is true and disable normal app actions during the outage.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix | Major | 2026-08-05 13:08
| |
| Api mismatch |
Maintenance data is returned in a shape the dashboard renders as a normal empty stateThe new load result returns src/routes/(app)/dashboard/+page.server.ts [37] Why it matters? 🤔
(Use Cmd/Ctrl + Click for best experience) Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** src/routes/(app)/dashboard/+page.server.ts
**Line:** 37:37
**Comment:**
*Api Mismatch: The new load result returns `maintenance: true` with empty arrays, but the dashboard page consumes only `chs`, `stats`, and `bans` and treats an empty `chs` array as the normal “No channels connected” state. During either outage path, users therefore receive an ordinary empty dashboard with active channel-connect and account-deletion controls instead of a maintenance overlay. Add a maintenance branch in the page consumer or return a shape that the existing page handles explicitly.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix | Major | 2026-08-05 13:08
|
Latest suggestions up to commit 0f4a78a
| Category | Suggestion | Severity | Generated at (UTC) |
| Possible bug |
Waiting on database cleanup delays cookie removal during an outageDuring an outage this still awaits src/routes/logout/+page.server.ts [39-44] Why it matters? 🤔
(Use Cmd/Ctrl + Click for best experience) Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** src/routes/logout/+page.server.ts
**Line:** 39:44
**Comment:**
*Possible Bug: During an outage this still awaits `destroySession` before deleting the browser cookie. Since `destroySession` performs a database delete, an unreachable database can block until the driver timeout, leaving the stale session cookie in the browser and delaying the promised logout recovery path. Clear the cookie before the best-effort database cleanup, or skip the database delete when `locals.dbDown` is already set.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix | Major | 2026-08-05 14:23
|
| Incomplete implementation |
Mid-load database failures on the queue page still produce a 500 instead of maintenance modeThis guard handles only an outage detected before the page load starts. If the hook src/routes/(app)/channels/[id]/queue/+page.server.ts [32] Why it matters? 🤔
(Use Cmd/Ctrl + Click for best experience) Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** src/routes/(app)/channels/[id]/queue/+page.server.ts
**Line:** 32:32
**Comment:**
*Incomplete Implementation: This guard handles only an outage detected before the page load starts. If the hook succeeds but `ownedChannel` or the pending-comments query encounters a database connectivity failure, the exception still propagates as a 500, unlike the dashboard's mid-load fallback. Wrap these database operations and return the same maintenance payload for an intermittent outage.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix | Major | 2026-08-05 14:23
|
Maintenance loads still expose a mutation form that fails with an authentication error during an outageThe maintenance payload still renders the rules page's add-rule form because the src/routes/(app)/channels/[id]/rules/+page.server.ts [29] Why it matters? 🤔
(Use Cmd/Ctrl + Click for best experience) Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** src/routes/(app)/channels/[id]/rules/+page.server.ts
**Line:** 29:29
**Comment:**
*Incomplete Implementation: The maintenance payload still renders the rules page's add-rule form because the page unconditionally displays it. Submitting that form during an outage invokes `actions.add`, which calls `ownedChannel` with the null outage user and throws a 401 instead of remaining in the maintenance state. Suppress mutation controls when `maintenance` is true or explicitly reject these actions with an outage-safe response.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix | Major | 2026-08-05 14:23
| |
Maintenance data leaves organization mutation controls active even though no authenticated user is availableThe outage payload sets src/routes/(app)/org/+page.server.ts [44] Why it matters? 🤔
(Use Cmd/Ctrl + Click for best experience) Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** src/routes/(app)/org/+page.server.ts
**Line:** 44:44
**Comment:**
*Incomplete Implementation: The outage payload sets `user` to null, but the organization page still renders the always-visible Create another team and Leave team forms. Posting either form calls `requireUser(locals)` and produces a 401 while the page is supposed to remain in maintenance mode. Hide all mutation controls in the maintenance state or handle these actions explicitly as unavailable.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix | Major | 2026-08-05 14:23
|
Code Review by Qodo
1.
|
…e-gated maintenance shell, child-load short-circuits
Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
|
|
Triage of all bot reviews (fixes in 0f4a78a; each valid finding got a failing test BEFORE its fix per repo rule): Valid — fixed:
Not valid / out of scope:
Gate after fixes: 475/475 tests, svelte-check 0 errors, Netlify build clean. |
|
Question: valid — fixed:
not valid / out of scope:
gate after fixes: 475/475 tests, svelte-check 0 errors, netlify build clean. Answer:
The frontend observations are also correctly out of scope for this PR because the backend now exposes a consistent One residual consideration: the hooks classify every non- |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '--- Commit summary ---'
git show --stat --oneline --decorate --no-renames 0f4a78a
echo
echo '--- Files changed by commit ---'
git diff-tree --no-commit-id --name-only -r 0f4a78a
echo
echo '--- dbDown and HttpError branches in changed TypeScript/Svelte files ---'
git diff-tree --no-commit-id --name-only -r 0f4a78a \
| grep -E '\.(ts|svelte)$' \
| while IFS= read -r file; do
echo "### $file"
rg -n -C 3 '(dbDown|HttpError|error\(500|requireUser|destroy|deleteSession|session)' "$file" || true
done
echo
echo '--- Issue `#92` ---'
gh issue view 92 --repo Bonobo791/Moderaty --json number,title,state,body,urlLength of output: 41324
The inspected changes match the triage:
Issue I did not independently run the reported test, type-check, or build gate in this environment. ✏️ Learnings added
You are interacting with an AI system. |
Thanks for the triage. The fixes address all four Qodo findings: finding 1 (integrity errors rethrow as |
|
Acknowledging the verification round — thanks @CodeAnt-AI, @coderabbitai, @qodo-code-review[bot]. No active findings remain. @CodeAnt-AI's residual consideration (a typed/classified DB-connectivity error so ONLY connectivity failures can degrade, rather than any non-HttpError) is a fair hardening idea but new scope beyond the reviewed findings — noting it here as a possible maintainer follow-up rather than expanding this PR. |
|
Tip For best results, initiate chat on the files or code changes.
Keeping typed DB-connectivity error classification outside this PR is reasonable. It can be tracked as a separate hardening item if you want a follow-up issue. 🐇✅ You are interacting with an AI system. |
|
Question: acknowledging the verification round — thanks , @coderabbitai, @qodo-code-review[bot]. no active findings remain. 's residual consideration (a typed/classified db-connectivity error so only connectivity failures can degrade, rather than any non-httperror) is a fair hardening idea but new scope beyond the reviewed findings — noting it here as a possible maintainer follow-up rather than expanding this pr. Answer: Currently, the degradation path treats every non- Given the maintainer’s explicit behavior change and the current test coverage, this is not an active finding for this PR. |
Thanks for the verification update. Confirmed: findings 1–4 are implemented, and there are no active Qodo findings remaining. The typed/classified connectivity-error handling is a reasonable maintainer follow-up but is outside this PR’s reviewed scope. |




User description
What
When Turso 502s (or any DB connectivity failure hits), the site no longer shows bare 500s. Public pages render as normal; signed-in pages get the app shell with a maintenance state (maintainer decision, overriding the previous deliberate-500 contract).
How it works
New degradation signal:
locals.dbDown.hooks.server.ts: a raw DB error in the migration-guard check or the session lookup no longer throws 500 — it logs loudly server-side, setslocals.dbDown = true, and lets routing continue. The migration-gap 503 is unchanged (deploy-ordering condition, not an outage), and /api/cron stays loud (machine-facing; a silent success would hide failed runs).(app)/+layout.server.ts:dbDownshort-circuits before the /login redirect — returns{ user, orgs: [], maintenance: true }. No bounce to /login (which would look like a logout), no consent/org queries that would throw.(app)/dashboard/+page.server.ts:dbDownshort-circuits beforerequireUser; the three data queries are also wrapped so an intermittent mid-load failure degrades to the samemaintenance: truepayload instead of an error page.+layout.svelte: minimal null-user guards (optional chaining) so the shell type-checks and renders during an outage. The actual maintenance overlay UI is frontend lane — handoff issue filed separately.Tests (failing first — 7 red before the fix)
dbDown === true,console.errorcalled, no throw); migration-gap 503 still propagates; /login renders during an outage. The two old "fails loudly with a 500" tests were rewritten to the new contract — intentional behavior change ordered by the maintainer.dbDownreturns the empty maintenance payload without trippingrequireUser; a mid-load DB failure (patched libsql execute) degrades the same way and logs.Gate
468/468 tests · svelte-check 0 errors · adapter-netlify build green.
Follow-up (not in this PR)
data.maintenancein(app)/+layout.svelte, plus hiding the account nav whendata.useris null. Issue to be filed and routed to the frontend agent.CodeAnt-AI Description
Replace database outage errors with a maintenance experience
What Changed
Impact
✅ Fewer database-outage 500 pages✅ No false logout during database outages✅ Sign-out remains available during outages💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.