feat(#18): orphan events migration - #35
Merged
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
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.
Closes #18.
Existing deployments have
logs,api_keys, andsettingswith noproject_id. Without a migration, shipping multi-tenancy makes all of that data invisible. Logger now adopts it into aDefaultproject before it serves traffic.How it works
toolbox/data/migrate.goholds the DB-level work:CountOrphanedDocumentscounts documents whoseproject_idis missing, null, or an empty stringMigrateOrphansToDefaultProjectreturns a nil report and does nothing when that count is zero — this is what makes reruns a no-op. Otherwise it finds-or-creates projectDefault/default(duplicate-key safe), stamps each collection withUpdateMany, then upserts an ownerProjectMemberper allowlisted login with$setOnInsert, so an existing membership is never downgradedParseGithubLoginstrims and dedupesLOGWOLF_ALLOWED_GITHUB_USERSbut preserves case — memberships are matched against the login GitHub returns at sign-in, so folding case would lock a mixed-case user out of the project created for themlogger/cmd/api/migrate.goreads the env var, logs the summary, and warns when the allowlist is empty (the project would have no owners and stay invisible in the dashboard). It is called frommain.gobeforeserve(), so the RPC port only opens on a fully migrated database. Failures are logged rather than fatal — the migration is idempotent, so the next start retries instead of crash-looping the stack.Two additions beyond the issue text
EnsureProjectIndexes()was never called in production — only from an integration test, so the uniqueslugindex did not exist on a real deployment. The migration's find-or-create relies on it. Now called at logger startup.logs.created_at; left in place it keeps purging on the old global schedule and overrides per-project retention (a project set to "forever" would still lose data).docker-compose.ymlnow passesLOGWOLF_ALLOWED_GITHUB_USERSto logger — without it an upgrade migrates the data but leaves theDefaultproject ownerless.Also bundled (not part of #18)
Two unrelated fixes rode along on this branch; they are independent and can be reviewed separately:
CLEANUP_INTERVALnever reached the logger container. It was documented in.env.examplebut absent fromdocker-compose.yml, so setting it had no effect. Also added CI steps for the logger and listener modules —logger/cmd/api/rpc_test.goexisted but had never run in CI.startProcessran services viago runand killed only that parent; on Windows the service survived. Strays accumulated across runs and a stray Listener reconnecting to a recycled RabbitMQ port ate messages a later test was waiting for, causing false failures in theTestProjectIsolation_*tests.startProcessnow builds each service once and execs the binary directly, so the killed process is the service.Verification
migrate_test.go), logger — all passintegration/startup_migration_test.goseeds a pre-multi-tenancy database, boots the real logger, and asserts after the RPC port opens; a second boot with an extra allowlist entry proves idempotency; a third test reads the legacy events back through the broker's publicGET /logsusing the legacy API keyA second boot printed nothing.
Note for upgrades
The broker caches an API key's project for 60s, so a key validated in the seconds before the migration can read empty until that entry expires. Self-healing; documented in the logger overview.
🤖 Generated with Claude Code