Repository navigation
refactor(backend): remove waitlist, CRM, Gemini Free, free models, GitHub stars and error pages - #60
Conversation
Thinker is self-hosted only, so the inherited Manifest Cloud UI goes. The frontend leaves first so no screen breaks when #14/#15 drop the matching backend endpoints. - Billing/plans: delete PlanPicker, UpgradeSuccessModal, UsageLimitBanner, the /upgrade page, the Register ?step=plan picker, the plan stores, the plan-based range locks on the analytics pages, the plan-limit upgrade CTAs in the request views, the Account billing and usage-email sections, and the @better-auth/stripe client plugin and dependency. - API Bot: delete the banner, the sidebar card, the dithered ground, their stylesheet and the SVG asset. - GitHub stars: drop the header star button and its /api/v1/github call. - Free Models: delete the page, its route, its API client and the assets only it used. - Managed Gemini Free: drop the provider entry, icon alias, background /ensure provisioning call and the Calendly key URL. - Cloud branches: checkIsSelfHosted() is gone and every screen behaves as self-hosted (Local providers always listed, local logs copy, CLI login pinned to this host, discovery after signup and setup). Drop the Manifest Cloud origin mapping, the cloud email card, the VITE_MANIFEST_SELFHOSTED read and the Dockerfile ENV that set it. - Help: drop the Manifest Calendly booking link. - Remove the dead CSS for all of the above, update the tests and the inherited dev guide. Closes #12 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Billing, Stripe and the Free/Pro plans belong to the SaaS layer that Thinker drops (docs/decisoes-iniciais.md section 3). - Delete packages/backend/src/billing (PlanService, billing controller, billing emails, request quota window, subscription status) and drop BillingModule from the app, proxy and analytics modules. - Proxy: remove the per-request plan gate (assertWithinRequestLimit) and the PLAN_LIMIT_REQUESTS / M204 handling in the controller and the exception filter. The proxy no longer answers 402 on its own; a 402 follows the generic error path. - Auth: remove the @better-auth/stripe plugin; drop the stripe and @better-auth/stripe dependencies from the backend. - Recording retention: keep only the global path (365-day default or REQUEST_RECORDING_RETENTION_DAYS); per-plan retention is gone. - Tenant entity: drop limit_overrides and billing_email_preferences; delete the TenantRequestUsage entity. - Shared: delete plan-limits and its exports. - Remove the STRIPE_* / PLAN_LIMIT_* / PLAN_REQUEST_QUOTA_RESET_AT variables from .env.example. - New migration DropBillingSchema1803200000000 drops the quota trigger and function, requests.quota_counted, tenant_request_usage, billing_email_logs and the two tenant columns. The old AddTenantRequestUsage migration keeps only its self-hosted path (a no-op up) so it no longer imports deleted billing code. /api/v1/billing/* no longer exists, and the STRIPE_* and PLAN_LIMIT_* variables are ignored if set. Closes #14 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tHub stars and error pages Remove the Manifest Cloud and marketing surfaces from the backend: - waitlist/ (pivot and Autofix claims) and its open-CORS pivot route (applyPivotClaimCors, PIVOT_CLAIM_PATH, PIVOT_CLAIM_CLOUD_ORIGIN). - crm-metrics/ and CRM_METRICS_SECRET. - The managed Gemini Free provider: routing/managed-free-provider/, common/constants/managed-free-providers.ts, the CREDITS_* variables, and its entries in provider-endpoints, provider-client, provider.service, provider-model-fetcher and routing.module. No other provider's endpoint, prefix handling, fallback order or tier resolution changes. - free-models/ (sync from mnfst/awesome-free-llm-apis), github/ (stars from api.github.com) and error-pages/ (public and Peacock push routes, seeders, discovery), MANIFEST_PUBLIC_STATS and ERROR_PAGE_PUSH_SECRET. - gemini-free and the managedFree flag from manifest-shared, and the regenerated CLI provider catalog. - The plan_request_limit_exceeded error class left over from #14. DropSaasFeatureSchema1803300000000 sets a transaction-local lock_timeout, drops waitlist_claims, public_error_pages and the cloud-only IDX_requests_autofix_healed index, and deletes every gemini-free connection with its agent grants. Request history keeps its provider label, and routes that still name gemini-free resolve as unavailable and fall through to their fallbacks, as after a disconnect. down() restores the two tables as the self-hosted path created them. Closes #15 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Revisão do PR #60 (#15): remoção de waitlist, CRM, Gemini Free, free-models, GitHub stars e páginas de erroEscopo revisado: PR empilhado. Revisei Nenhum bloqueador. O PR entra em risco alto por um critério: ele adiciona uma migration que destrói dados. O O que verifiquei1. Migration
2. Hot path
3. CORS/CSP
4. Rotas removidas
5. Shared e CLI
Projeto e segurança
Execuções que fiz neste head (
|
| Verificação | Resultado |
|---|---|
npm run build em packages/shared |
limpo |
tsc --noEmit em backend, frontend e cli (npm run typecheck) |
limpo |
| Regeneração do catálogo do CLI | sem diff |
| Unit do backend afetado (migration, provider-endpoints, provider-client, model-discovery, cors-csp-config, routing-core, resolve, responses-*) | 47 suítes, 1793 testes, verdes |
| Unit do shared | 21 suítes, 462 testes, verdes |
e2e com Postgres 16 descartável, TZ=UTC: drop-saas-feature-schema-migration, removed-saas-routes, routing-flow, proxy-fallback-auth, multi-key-providers, drop-billing-schema-migration, proxy, proxy-no-plan-gate |
8 suítes, 61 testes, verdes |
O relatório local do autor cobre lint, tsc e build do backend, typecheck do CLI, unit dos quatro pacotes e e2e completo. Ele não lista o build do shared nem o typecheck e o build do frontend. Rodei os dois primeiros acima e estão limpos.
Achados
Bloqueadores: nenhum.
Should-fix: nenhum.
Nits:
packages/backend/test/removed-saas-routes.e2e-spec.ts:22-43: parte das asserções de 404 não testa nada. OcreateTestApp(test/helpers.ts) nunca registrouGithubModule,FreeModelsModulenemErrorPagesModule, nem antes deste PR. Por isso/github/stars,/free-models,/public/error-pages*e/internal/error-pages*já respondiam 404 nesse app antes da remoção. Só waitlist, crm-metrics e/providers/gemini-free/ensuretinham módulo registrado e provam algo.- Impacto hoje: baixo, porque o código foi apagado.
- Correção: dizer isso no comentário do spec e deixar a prova contra o
AppModulepara oqa-dockerna imagem real, que o próprio PR já sugere.
- Falta um teste de regressão específico para rotas que citam
gemini-free. O comportamento "rota que citagemini-freevira indisponível e cai no fallback" aparece no PR e na doc, mas nenhum teste cita esse id. A cobertura é genérica:provider-key.service.spec.ts:550e os casos de override órfão emresolve.service*.spec.ts. Como o tratamento de erro não mudou, isso não é bloqueador.- Correção opcional: um caso em
resolve.service.speccom um override{provider: 'gemini-free'}e um fallbackopenaiconectado. O resultado esperado é o fallback promovido.
- Correção opcional: um caso em
1803300000000-DropSaasFeatureSchema.ts:46:DROP INDEXsemCONCURRENTLY. Quando o índice existe (só em banco que rodou em modo cloud), o comando pegaACCESS EXCLUSIVEemrequestsdentro da transação. Olock_timeoutde 10s limita a espera, e o PR documenta que self-hosted não tem esse índice. Sem instalação Thinker, o impacto é zero. Registro só para quem portar um banco cloud, o que não é suportado..github/workflows/docker-smoke.yml:204-210: nome e mensagem do passo estão desatualizados. O passo "Verify public error pages are gated off by default" e a mensagem citamMANIFEST_PUBLIC_STATS. O passo continua passando (o 404 agora é incondicional) e serve como guarda de regressão. Editar o workflow aqui seria mudança de workflow fora do escopo do CI mínima provisória #38, então é melhor fazer em outro PR com issue, ou na limpeza do Remover Autofix/Phoenix do backend #16 ou Modo único self-hosted: remover MANIFEST_MODE #18. O mesmo vale para o badge de GitHub stars emdocker/DOCKER_README.md:11eREADME.md:24, que já está listado como follow-up de rebrand.- Notas da 0.1.0 (Release, Changesets 0.1.0 e publicação no Docker Hub #31): devem registrar:
- a remoção do provedor "Gemini Free", com a exclusão automática das conexões;
- as rotas removidas;
- as variáveis
CREDITS_*,MANIFEST_PUBLIC_STATS,ERROR_PAGE_PUSH_SECRETeCRM_METRICS_SECRET.
Critério de risco alto
- Migration que destrói dados:
DROP TABLEemwaitlist_claimsepublic_error_pages, eDELETEdas conexõesgemini-free(credencial e grants), sem caminho de volta para os dados. A decisão está justificada no PR: a credencial só funcionava contracredits.manifest.build, não existe instalação Thinker, e importar um banco Manifest não é suportado (docs/decisoes-iniciais.md§1). O critério continua valendo, e quem decide é o mantenedor (ADR 0002).
Gates restantes (não fazem parte deste veredito)
- CI: não roda em PR empilhado, porque
ci.ymlsó dispara paramain. Esse gate é verificado quando o PR for retargetado paramain, depois do merge do refactor(frontend): remove the SaaS layer from the dashboard #51 e do refactor(backend): remove billing, Stripe and plan limits #52. Depois do rebase, o head muda e precisa de nova revisão. qa-docker: obrigatório, porque o comportamento de runtime muda (rotas, saídas de rede, migration no boot). Ainda não rodou, e o PR está em draft. Deve confirmar:- o boot e a migration num volume novo;
- o 404 das rotas removidas na imagem real (cobre o nit 1);
- o fallback do proxy.
Head revisado: 64f31b4
Veredito: risco alto (aguardar mantenedor)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #67 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #67 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nova revisão do PR #60 (#15) depois do retarget para
|
| Check | Resultado |
|---|---|
| Lint | success |
| Unit (shared, backend, frontend, cli) | success |
| Backend e2e (PostgreSQL 16) | success: 64 suítes, 526 testes. drop-saas-feature-schema-migration, removed-saas-routes e drop-billing-schema-migration aparecem como PASS no log |
| Compose smoke test (read-only), install.sh end-to-end | success |
| CodeQL, dependency-review | success |
Nenhum teste instável apareceu nesta execução, nem o de local-providers.e2e-spec.ts (#101).
No meu worktree. O CI não tem job de typecheck, então rodei:
| Verificação | Resultado |
|---|---|
npm ci e build de packages/shared |
ok |
tsc --noEmit no backend e no frontend, npm run typecheck no cli |
limpos |
npm run gen no cli, que regenera provider-catalog.gen.ts e o conteúdo da skill |
sem diff |
A tabela de gates no corpo do PR é do head antigo. Agora vale o CI acima, que já cobre lint, unit e e2e.
Achados
Bloqueadores: nenhum.
Should-fix: nenhum.
Nits
O nit 1 é novo. Os nits 2 a 6 vêm da revisão anterior, com o nit 5 ampliado.
-
packages/backend/src/common/constants/cache.constants.ts:13: export morto.FREE_MODELS_CACHE_TTL_MSera usado só porfree-models.controller.ts, que este PR apaga. Hoje nada o importa. Não quebra nada, mas é resto da feature removida.- Correção: apagar a constante neste PR ou na limpeza do Remover Autofix/Phoenix do backend #16.
-
packages/backend/test/removed-saas-routes.e2e-spec.ts:22-43: parte das asserções de 404 não prova nada. OcreateTestAppnunca registrouGithubModule,FreeModelsModulenemErrorPagesModule. A prova contra oAppModulereal fica com oqa-docker. -
Não existe teste de regressão de uma rota que cite
gemini-free. O caminho de órfão é coberto por testes genéricos. Opcionalmente, dá para adicionar um caso emresolve.service.speccom um override{provider: 'gemini-free'}e fallbackopenai. -
1803300000000-DropSaasFeatureSchema.ts:46:DROP INDEXsemCONCURRENTLY. O índice só existe em bancos que rodaram em modo cloud, e olock_timeoutlimita a espera. -
Documentação herdada ainda cita o que foi removido.
.github/workflows/docker-smoke.yml:204-210: o nome do passo e a mensagem citamMANIFEST_PUBLIC_STATS. O passo continua passando, e mudar workflow está fora do escopo deste PR.README.md:24edocker/DOCKER_README.md:11: o badge de GitHub stars.README.md:100: a linha "Gemini Free", com "Managed key".dashboard-redesign-brief.md:189.
Tudo isso cabe na limpeza de rebrand e README, ou no Remover Autofix/Phoenix do backend #16/Modo único self-hosted: remover MANIFEST_MODE #18.
-
Notas da 0.1.0 (Release, Changesets 0.1.0 e publicação no Docker Hub #31): devem registrar:
- a remoção do provedor Gemini Free, com a exclusão automática das conexões;
- as rotas removidas;
- as variáveis
CREDITS_*,MANIFEST_PUBLIC_STATS,ERROR_PAGE_PUSH_SECRETeCRM_METRICS_SECRET.
Critério de risco alto
Migration que destrói dados. DROP TABLE em waitlist_claims e public_error_pages, DROP INDEX IF EXISTS do índice de CRM e DELETE das conexões gemini-free e das grants delas. O down() recria só o schema. O critério da ADR 0002 se aplica: quem decide o merge é o mantenedor, não o Principal.
O PR não mexe em auth, cripto, isolamento entre tenants, governança, workflows nem release. Não há destino de saída novo. O PR remove três: credits.manifest.build, api.github.com (stars) e raw.githubusercontent.com/mnfst/awesome-free-llm-apis.
Gates restantes (não fazem parte deste veredito)
- CI: verde em
498de23. qa-docker: precisa rodar, porque nunca rodou em nenhum head deste PR. O runtime muda: rotas removidas, saídas de rede removidas e migration no boot. Além disso, a imagem de498de23agora inclui o refactor(backend): remove billing, Stripe and plan limits #52 e o refactor(frontend): remove phone-home and Autofix from the dashboard #57. Deve rodar contra a imagem construída a partir de498de23e confirmar:- o boot e as 147 migrations num volume novo;
- o 404 das rotas removidas no
AppModulereal, o que cobre o nit 2; - o fallback do proxy.
- Mantenedor: a decisão final é dele, por causa do risco alto.
Qualquer commit novo, inclusive um que corrija os nits, invalida este veredito e exige nova revisão.
Head revisado: 498de23
Veredito: risco alto (aguardar mantenedor)
qa-docker: PASSTested SHA:
Egress (PR vs main df6ca96, same procedure)Default env (telemetry and update check not disabled), tcpdump sidecar in the app netns: boot, a Chromium session across 13 dashboard routes, about 75 s idle. Outbound TCP SYNs to public addresses, by destination:
The second raw.githubusercontent.com connection on main is the The on-demand destinations only fire when something calls the removed endpoints, so I checked them separately on the upgrade stack. On the main image, Observations (not blockers)
|
Brings in 498de23 (main plus #60) so #16 can merge into main after #60. Conflicts came from #57's interim dashboard handling of the legacy Autofix backend overlapping with this branch's backend removal: - frontend analytics client: RELIABILITY_PATHS points at the neutral /overview/reliability/* routes. foldLegacyRecoveredKey is dropped: the backend computes the request disposition from success/fallback only and DropAutofixSchema removes requests.autofix_status, so no row can come back as "healed", and the dashboard ships with its own backend. - frontend agents client: the auto-merged autofix_enabled opt-out on create and the PATCH /routing/:agent/autofix after duplicate are dropped (the field and the endpoint no longer exist; create rejects the field). - shared: keep the playground-headers exports, drop the autofix-status ones. - tests: keep this branch's versions (neutral paths, no opt-out, no fold). - e2e specs from main (local providers, reserved local runner aliases): stop sending autofix_enabled on agent create. - manifest guide: keep the "Autofix removed" section and neutral-path wording. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…base guard (#111) * test(backend): fail the unit suite when an e2e spec bypasses the database guard Add test/e2e-db-guard-scan.ts and its spec, which run in the unit suite and parse every .ts file under packages/backend/test with the TypeScript AST. They fail when a file: - wipes the database (dropSchema not literally false, DROP SCHEMA or DROP DATABASE SQL, .dropDatabase(), .synchronize(true)) without calling resolveE2eDatabaseUrl() or createTestApp(); - falls back from process.env.DATABASE_URL with ?? or ||; - has a string naming localhost:5432 or mydatabase (e2e-db-guard.spec.ts is exempt, since it proves the guard refuses those URLs). Fixtures under test/fixtures/e2e-db-guard (*.fixture, outside the scan and outside Jest) reproduce the legacy migration-spec pattern from #52, #60 and #66, a raw DROP SCHEMA reset, and the accepted guarded pattern. A temp-dir tree scan proves that adding the legacy spec fails the check. Closes #108 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(backend): treat a queryRunner.dropSchema() call as a wipe in the guard scan Refs #108 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Closes #15
Summary
This PR removes the Manifest Cloud and marketing surfaces from the backend. Several of them made outbound calls of their own.
waitlist/(pivot and Autofix claims), plus the open-CORS pivot route inmain.ts/cors-csp-config.ts(applyPivotClaimCors,PIVOT_CLAIM_PATH,PIVOT_CLAIM_CLOUD_ORIGIN)crm-metrics/(and its cloud-only registration inapp.module.ts),CRM_METRICS_SECRETrouting/managed-free-provider/,common/constants/managed-free-providers.ts,CREDITS_*credits.manifest.buildfree-models/raw.githubusercontent.com/mnfst/awesome-free-llm-apisgithub/api.github.com/repos/mnfst/llm-gatewayerror-pages/(public + Peacock push controllers, seeders,ErrorDiscoveryService),MANIFEST_PUBLIC_STATS,ERROR_PAGE_PUSH_SECRETFindings from the issue comments are also addressed:
gemini-freeand themanagedFreeflag are removed frompackages/shared/src/providers.ts, and the CLI catalog is regenerated (provider-catalog.gen.ts, 6 lines).CREDITS_*is removed fromdocker/.env.exampleandpackages/backend/.env.example.free-models/.plan_request_limit_exceededleftover is removed frompackages/shared/src/error-taxonomy.ts, including thelimit_exceeded+ 402 special case. M204 no longer appears anywhere outside old migrations and negative assertions.SET LOCAL lock_timeout.Hot path. Only the
gemini-freeentries are removed fromPROVIDER_ENDPOINTS,PROVIDER_CONFIGS,PROVIDER_NON_CHATand thestripModelPrefixexception inprovider-client.ts. Also removed: the one-key limit for managed providers inprovider.service.ts, whose general limit is stillMAX_KEYS_PER_PROVIDER. No other provider's endpoint, prefix handling, fallback order or tier resolution changes.routing-flow,proxy,proxy-fallback-authandmulti-key-providersstay green.Migration
DropSaasFeatureSchema1803300000000The migration is new, runs after
1803200000000and is registered indata-source-definitions.ts. No old migration is edited.up(), in its own transaction (transaction: 'each'):SET LOCAL lock_timeout = '10s'. If the migration cannot get a lock it fails fast instead of holding up writes, and it is retried on the next boot.agent_enabled_providersgrants, then thetenant_providersrows withLOWER(provider) = 'gemini-free'.DROP INDEX IF EXISTS "IDX_requests_autofix_healed". This is the CRM-only index, created only in cloud mode by1802200000000, so on a self-hosted DB it is a no-op that never locksrequests.DROP TABLE IF EXISTSonwaitlist_claimsandpublic_error_pages.down()recreates the two tables (empty) as the earlier migrations created them on the self-hosted path. It does not recreate the CRM index (never part of that path) or the deleted connections.Decision: existing
gemini-freeconnections are deletedcredits.manifest.build, and the provider id no longer exists in the endpoint registry, the discovery registry or the shared catalog. Leaving the rows inert would show the dashboard a connection it cannot render and give routing a key it cannot use. Deactivating them would keep the dead credential stored.agent_messageshistory keepsprovider = 'gemini-free'. Onlytenant_provider_idis nulled, by the existingON DELETE SET NULLFK.override_route/fallback_routes) that still namegemini-freeare left alone.ProviderKeyService.isRouteAvailablereports them unavailable, so resolution falls through to the next fallback, exactly as after a disconnect.docs/decisoes-iniciais.md§1).test/drop-saas-feature-schema-migration.e2e-spec.ts:gemini-freerows in two tenants (one mixed-case) are deleted with their grants;geminiandopenaiconnections and grants of the same tenant are kept;Tests
1803300000000-DropSaasFeatureSchema.spec.tschecks that lock_timeout comes first, that grants are deleted before connections, that every DROP usesIF EXISTS, and the revert shape.test/drop-saas-feature-schema-migration.e2e-spec.ts:test/removed-saas-routes.e2e-spec.ts:/api/v1/waitlist/{pivot,autofix}/claim,/api/v1/internal/crm-metrics[/signups],/api/v1/github/stars,/api/v1/free-models,/api/v1/public/error-pages[/:slug],/api/v1/internal/error-pages[/clusters]and/api/v1/providers/gemini-free/ensureanswer 404;gemini-freeanswers 400.gemini-freeendpoint, andresolveEndpointKey('gemini-free'|'gemini free')isnull;gemini-freethrows before any fetch;limit_exceededstub is classifiedlimit_exceeded.test/waitlist.e2e-spec.ts,test/crm-metrics.e2e-spec.tsand the specs of every removed module.crmtool namespace fixture inresponses-tools.spec.ts/responses-stream-tools.spec.tsis renamed tocontacts, so the acceptance grep only matches real leftovers.Gates (local; CI is still provisional, #38)
npm run lint(root: shared, backend, frontend, cli)tsc --noEmitnpm run buildnpm run typecheck--runInBand, Postgres 16 (disposablepostgres:16-alpine, removed afterwards),TZ=UTC-03)smoke-test.e2e-spec.ts, the known timezone issue tracked in #53/PR #56node dist/database/migrate.json an empty DBwaitlist_claims,public_error_pagesorIDX_requests_autofix_healednpm run migration:revert(revertsDropSaasFeatureSchema1803300000000)migrate.jsFrontend check
grep -rnE "managedFree|gemini-free|free-models|freeModels|/ensure|waitlist|crm|error-pages|github/stars|stargazers" packages/frontend/srchas no matches. The dashboard calls nothing removed here (#12 already removed the UI).Acceptance grep
grep -rniE "waitlist|pivot|crm|credits\.manifest|managed-free|free-models|awesome-free|stargazers|error-pages" packages/backend/srcoutsidedatabase/migrations/still matches three things:data-source-definitions.ts, which the issue allows.notifications/emails/doctor-release.tsx(+ spec), the Autofix "waitlist" announcement e-mail. It is explicitly in Remover Autofix/Phoenix do backend #16's scope, so it was left alone.pivotByKey, "pivot table" scoring keywords and test titles). This is unrelated to the pivot waitlist.Docs
docs/dev/manifest-guide.mdchanges:Out of scope / follow-ups
doctor-release.tsx;/overview/autofix-*reliability metrics (untouched);1802200000000-AddRequestsAutofixHealedIndex.tsthat still describes the CRM feed (left as is; old migration).IF EXISTS, so Remover Autofix/Phoenix do backend #16's migration can repeat the drop harmlessly or skip it.isSelfHostedis no longer imported byapp.module.ts.docker/DOCKER_README.mdstill shows the upstream "GitHub stars" badge, which belongs to README/rebrand work.qa-docker
This should run before the PR leaves draft, because runtime behavior changed (routes removed, outbound calls removed, migration on boot). Suggested checks:
🤖 Generated with Claude Code