Skip to content

feat(sunset): wind down the hosted service behind SUNSET_MODE - #1777

Closed
AnishSarkar22 wants to merge 199 commits into
MODSetter:devfrom
AnishSarkar22:feat/workstream-b
Closed

AnishSarkar22 wants to merge 199 commits into
MODSetter:devfrom
AnishSarkar22:feat/workstream-b

Conversation

@AnishSarkar22

@AnishSarkar22 AnishSarkar22 commented Sep 14, 2026

Copy link
Copy Markdown
Collaborator

Description

  • Adds SUNSET_MODE, one flag read per request on both sides, turning the hosted service export-only at T-0. Unset means off, so self-hosted installs are unaffected.
  • Backend: new SunsetWriteBlockMiddleware refuses writes with 410. Reads are never blocked, so export keeps working.
  • Allowlisted through the block: all of /auth/ except /auth/register, plus /api/v1/license/* and the Stripe webhook — people still need to sign in to export.
  • /health now reports sunset and accepts 1/true/yes/on. Contract 4 documents SUNSET_MODE=1, which the old comparison read as false.
  • Web: proxy.ts redirects app routes to /sunset while the portal stays reachable. Not NEXT_PUBLIC_*, so sunsetting is a restart, not a rebuild.
  • Extracts lib/public-routes.ts so middleware avoids auth-utils' browser-only helpers; isPublicRoute is re-exported, no call sites change.
  • Adds purge_hosted_accounts.py for T+30 — loops over the existing erase_account so blobs go with the rows. Dry-run by default, refuses without the flag, typed confirmation, resumable.
  • Adds the T-0 sunset and T+30 purge runbooks.
  • Documents the flag in all three .env.example files and both compose files.
  • 157 tests, including every path × method with the flag unset, asserting nothing is blocked or redirected.
  • Separately: desktop update banner becomes a title-bar button, with a new --notice colour token.

Known gap for review: nothing purges artifact blobs when a workspace is deleted, so the purge empties documents/ but not artifacts/ — deleting the storage container is required. Same gap affects single-account deletion today, independent of this PR.

Motivation and Context

FIX #

Screenshots

API Changes

  • This PR includes API changes

Change Type

  • Bug fix
  • New feature
  • Performance improvement
  • Refactoring
  • Documentation
  • Dependency/Build system
  • Breaking change
  • Other (specify):

Testing Performed

  • Tested locally
  • Manual/QA verification

Checklist

  • Follows project coding standards and conventions
  • Documentation updated as needed
  • Dependencies updated as needed
  • No lint/build errors or new warnings
  • All relevant tests are passing

High-level PR Summary

This PR implements the hosted service wind-down infrastructure (Workstream B from the pivot plan). It introduces a SUNSET_MODE flag that transitions the hosted service into an export-only state at T-0, blocking writes while keeping authentication and data export functional. The implementation includes backend middleware to refuse writes with 410 responses, frontend redirects to a /sunset page for app routes, comprehensive runbooks for T-0 sunset and T+30 data purge operations, and a purge script that loops over the existing erase_account function. Additionally, it refactors the desktop app's update notification from a banner to a title bar button styled with a new --notice color. The system is designed to be a no-op for self-hosted installations where SUNSET_MODE remains unset.

⏱️ Estimated Review Time: 30-90 minutes

💡 Review Order Suggestion
Order File Path
1 plans/community-local/00d-pivot-plan.md
2 plans/community-local/sunset-runbook.md
3 plans/community-local/purge-runbook.md
4 surfsense_backend/app/sunset.py
5 surfsense_backend/app/app.py
6 surfsense_backend/scripts/purge_hosted_accounts.py
7 surfsense_backend/tests/unit/test_sunset_flag.py
8 surfsense_backend/tests/unit/test_sunset_write_block.py
9 surfsense_web/lib/sunset.ts
10 surfsense_web/lib/public-routes.ts
11 surfsense_web/proxy.ts
12 surfsense_web/tests/unit/sunset-redirect.test.ts
13 surfsense_backend/.env.example
14 surfsense_web/.env.example
15 docker/.env.example
16 docker/docker-compose.dev.yml
17 docker/docker-compose.yml
18 surfsense_local/frontend/src/features/updates/update-settings.tsx
19 surfsense_local/frontend/src/features/updates/update-settings.test.tsx
20 surfsense_local/frontend/src/features/dashboard/dashboard-page.tsx
21 surfsense_local/frontend/src/app/app-bootstrap.tsx
22 surfsense_local/frontend/src/components/ui/icons.tsx
23 surfsense_local/frontend/src/index.css
24 surfsense_local/frontend/src/test-utils.tsx
25 .cursor/skills/color-system/PALETTE.css

Need help? Join our Discord

@vercel

vercel Bot commented Sep 14, 2026

Copy link
Copy Markdown

@AnishSarkar22 is attempting to deploy a commit to the Rohan Verma's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Sep 14, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: b266197f-7215-4dc6-93ab-4e76e5fd1889

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@AnishSarkar22 AnishSarkar22 changed the title Feat/workstream b feat(sunset): wind down the hosted service behind SUNSET_MODE Sep 14, 2026
AnishSarkar22 and others added 21 commits September 15, 2026 01:07
refactor(local): move the update prompt from a banner to a title bar button
Electron 41+ ships no postinstall; the binary is fetched lazily on the first
require('electron'). electron-vite reads path.txt directly and throws
"Electron uninstall" on a fresh clone, or whenever a peer change renames
the .pnpm folder. Run install-electron (idempotent) as our own postinstall.
feat(local): polish local app UI: artifact filtering, settings, and sidebar
CREDO23 and others added 28 commits September 16, 2026 21:33
feat(local): cancel running jobs, and show how many sources chat uses
…dev catalogue instead of guessing from the name
…ility

fix(local): resolve remote model capabilities from a vendored models.dev catalogue
This migration updates the document status to include a 'cancelled' state, allowing for better management of background document jobs. The downgrade function ensures that cancelled statuses are reverted to 'failed' when necessary.
…itioning, add optional tooltip toggle to relative-time
Records the values a deployment that sells licenses must set: the Stripe
price the webhook matches a Payment Link against, Resend's SMTP strings,
and the Keygen CE connection.
The pricing card now has a primary Buy action driven by NEXT_PUBLIC_STRIPE_LICENSE_INDIVIDUAL_URL, with a secondary trial button beside it.
…estructure

refactor(dashboard): restructure sidebar and chats navigation, polish studio, onboarding, and model settings UI
The v1.0.x tags belong to the old project versioning, so the relaunch starts at 2.0.0. The release workflow now refuses a tag that disagrees with surfsense_local/VERSION, since extraMetadata.version patches the Electron package but not pyproject.toml.
…isclosure, matching /sunset's compact layout
…estructure

feat(marketing): polish onboarding, /sunset, and /license pages to match site design system
…rials for 30 days

A trial is handed to an email address, not to an installation, so the email now opens with an install link built from NEXT_FRONTEND_URL. Deployments without a portal keep the original steps rather than printing a dead link.

Trial length moves to 30 days so the week before the first plugin ships does not eat half of it. The number is read from LICENSE_TRIAL_DAYS everywhere, including the subject line and the pricing copy, which previously hardcoded 14.
# Conflicts:
#	surfsense_web/app/(home)/license/page.tsx
Wire the licence purchase flow to Stripe, and set the app to 2.0.0
# Conflicts:
#	surfsense_local/frontend/src/components/ui/icons.tsx
#	surfsense_local/frontend/src/features/updates/update-settings.test.tsx
#	surfsense_local/frontend/src/features/updates/update-settings.tsx
#	surfsense_web/lib/auth-utils.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants