Removing subsystems
Remove an optional integration as a complete vertical slice.
Removing optional subsystems
Use the executable optional subsystem removal golden path. This page classifies the current product surface so an agent starts from a real inventory rather than a feature name.
Disabling a key is not removal. A complete removal covers runtime, package, environment, persistence, public routes, deployment, generated buyers, documentation, and commercial claims.
Current classification
| Capability | v1 status | Removal boundary |
|---|---|---|
| Historical Cloudflare worker | removed and reproduced | no apps/worker, workspace/package/importer/env/deployment/runtime claim; Decision 0001 records re-entry criteria |
| Sentry | optional, not removal-rehearsed | browser init/error boundaries, Vite plugin/source maps, API tunnel, typed environment, project allowlist, packages |
| Slack operational messages | optional, not removal-rehearsed | typed environment, Slack client, auth/marketing/deploy callers, server package, docs/tests |
| Google OAuth | optional, not removal-rehearsed | Better Auth provider config, typed environment, login state/UI, callback deployment docs/tests |
| Public profile uploads | optional, not removal-rehearsed | upload contracts/domain/migration, storage adapters, web service/profile UI, environment, docs/tests |
| PWA/offline install | optional, not removal-rehearsed | Vite PWA/Workbox packages and plugin, manifest/icons/offline page, service-worker tests/deployment behavior |
| Billing | product-optional, high risk | billing package/domain/migration, adapters, plans/gates, settings UI, webhooks, email, provider environment, commercial claims |
| Better Auth and email auth | core supported path | removing either replaces the authentication/product contract; it is not a small optional-integration task |
| Postgres/dbmate and contracts | core architecture | removal is a new product architecture, not a supported subsystem-removal path |
“Not removal-rehearsed” is deliberate wording. The generic runbook describes how to prove those removals; it does not claim every combination has already passed.
Narrowing authentication to social providers
Setting emailAndPassword.enabled: false in apps/server/src/lib/auth.ts does not remove email
authentication. Better Auth 1.6 gates /auth/sign-in/email and /auth/sign-up/email on that flag,
but gates two other endpoints on the presence of a callback instead:
| Endpoint | Actual gate |
|---|---|
/auth/request-password-reset | emailAndPassword.sendResetPassword is defined |
/auth/send-verification-email | emailVerification.sendVerificationEmail is defined |
Both callbacks ship defined, so both endpoints stay live after the flag is turned off:
/auth/request-password-resetstill emails a reset link for any registered address, including an account that has only ever signed in through a social provider. Completing the link creates a credential account for that user and, becauserevokeSessionsOnPasswordResetis enabled, revokes their live sessions./auth/send-verification-emailstill sends for any account whoseemail_verifiedis false. The shippedemailVerification.autoSignInAfterVerification: truethen makes/auth/verify-emailset a session cookie, which is a complete email-link route to a session that never reaches the social provider.- The magic-link plugin is a third email route to a session. It is registered in
plugins, soemailAndPassword.enablednever applies to it.
A complete narrowing removes the callbacks rather than only the flag:
- delete
emailAndPassword.sendResetPasswordandemailAndPassword.onPasswordReset; - delete
emailVerification.sendVerificationEmail, and decide explicitly whetherautoSignInAfterVerificationstill has a purpose; - remove the
magicLinkplugin fromplugins; - remove the matching login UI, email templates, sensitive-route rate limits, and typed environment;
- add a negative integration test per removed endpoint proving it now fails closed.
The delivered foundation is not exposed by this: it ships email authentication enabled, and every listed endpoint is a supported flow.
Reproduced worker removal
The pre-release template previously contained a disconnected Cloudflare/Gemini document-processing worker. It was removed because it had no production Better Auth-to-executor authorization, durable job ownership, product data model, billing/abuse limits, or paid evidence.
The reproduced removal covered:
- the entire
apps/workerworkspace and its direct packages; - workspace and root commands;
- worker environment examples and deployment configuration;
- generated-buyer output and current product claims;
- a decision fixture that rejects re-adding provider/runtime code when a PRD has not earned the capability;
- frozen install, static checks, tests, production builds, dependency audit, and a custom generated buyer.
Current contract tests assert that apps/worker is absent and that the no-worker decision remains
documented. This is same-context maintainer evidence, not a cold independent-agent claim.
Inventory starting points
Use these terms only to build an inventory; classify every result before deleting:
| Capability | Search terms |
|---|---|
| Sentry | SENTRY_, sentry, /tunnel |
| Slack | SLACK_, slack, sendSlackMessage |
GOOGLE_CLIENT, google, socialProviders | |
| Storage/upload | STORAGE_, CLOUDFLARE_, PROFILE_PIC, upload, presign, object_key |
| PWA | VitePWA, workbox, site.webmanifest, offline, serviceWorker |
| Billing | BILLING_PROVIDER, POLAR_, STRIPE_, DODO_PAYMENTS_, subscription, billing, plan, webhook_events |
Search source, manifests, lockfile importers, migrations, environment schemas/examples, CI, deployment settings, tests, docs, generated output, and sales copy. Historical ADRs may retain classified evidence; current buyer claims may not.
Persistence and pre-release changes
This product is not live. Before the first commercial tag, a baseline migration may be corrected
only under the documented pre-release exception and only with empty-database up → down → up,
DB-enabled tests, and a clean generated buyer.
After the first tag, never edit a released migration to make a removal look clean. Add an explicit retirement migration, data export/retention decision, and safe rollback or forward-recovery plan. Deleting an external provider resource or stored customer data always requires explicit authority, regardless of whether the application is pre-release.
Product-contract consequences
- Removing Sentry or Slack narrows observability/operations but need not change customer behavior.
- Removing Google preserves password/magic-link auth only when those flows and account linking still pass.
- Removing object storage requires removing profile upload UI and its persisted claims; do not leave a broken avatar action.
- Removing PWA requires removing install/offline claims and generated service-worker artifacts.
- Removing billing means the resulting application is not revenue-ready through the supported paid path. Remove gates, plans, portal, lifecycle email, webhook routes/state, and every pricing claim together.
- Removing Better Auth, Postgres, the separate API, or typed contracts is a deliberate architecture fork outside normal support.
Required proof
vp install --frozen-lockfile
vp check
vp run -r test
vp run -r build
pnpm audit --audit-level high
git diff --checkAlso prove zero-key local startup, affected negative behavior, exact residue classification, migration reversal where persistence changed, and an untouched custom-scope/custom-brand generated buyer. Record remaining hits and their owners; an empty unscoped search is not trustworthy evidence.