Rearchitect services and deployments#139
Conversation
|
Caution Review failedThe pull request is closed. WalkthroughReplaces Convex with a new ORPC/Hono-based backend in apps/backend using Drizzle/PostgreSQL and Redis, adds auth via BetterAuth and Polar, introduces plugin KV/players routers, updates the web app to ORPC, removes the fumadocs app and Convex backend package, adds Docker Compose services (postgres, redis, api, migrate), and switches CI and scripts to Bun. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Plugin as Minecraft Plugin
participant API as Hono API (apps/backend)
participant ORPC as ORPC Router
participant DB as Postgres (Drizzle)
participant KV as Redis
Plugin->>API: HTTP (Bearer API_SECRET_KEY) GET /plugin/players/{uuid}/document?joinEvent=true
API->>ORPC: Route dispatch (pluginPlayersRouter.getPlayerDocument)
ORPC->>DB: getPlayerDocument(uuid)
DB-->>ORPC: Player row + bans (or none)
alt Not found
ORPC->>DB: createInitialPlayerDocument(uuid)
end
opt joinEvent=true
ORPC->>DB: handlePlayerJoinEvent(uuid) (tx: insert join event, inc stats)
end
ORPC-->>API: PlayerDocument
API-->>Plugin: 200 JSON PlayerDocument
sequenceDiagram
autonumber
actor Web as Web App (React)
participant RPC as @orpc/client
participant API as Hono API
participant ORPC as ORPC Router
participant DB as Postgres
participant KV as Redis
Web->>RPC: useQuery(rpc.healthCheck.queryOptions())
RPC->>API: POST /rpc (healthCheck)
API->>ORPC: Execute healthCheck (dbProvider, kvProvider)
ORPC->>DB: SELECT 1 (latency)
ORPC->>KV: set/get (latency)
ORPC-->>API: { status, dbCheckDurationMs, kvSetGetDurationMs, timestamp }
API-->>RPC: JSON
RPC-->>Web: Data to render
sequenceDiagram
autonumber
actor Plugin
participant API
participant ORPC
participant KV as Redis
Plugin->>API: POST /plugin/kv/{key} { value }
API->>ORPC: pluginKvRouter.set
ORPC->>KV: set(key, value)
KV-->>ORPC: OK
ORPC-->>API: { message: "KV set" }
API-->>Plugin: 200 JSON
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (12)
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 |
There was a problem hiding this comment.
Actionable comments posted: 25
🧹 Nitpick comments (11)
package.json (1)
15-23: MoveconcurrentlytodevDependencies.
concurrentlyis only used by the development scripts, so it needlessly inflates the production install when kept underdependencies. Please relocate it todevDependencies(and drop the now-emptydependenciesblock if nothing else belongs there).- "dependencies": { - "concurrently": "^9.2.1" - }, "devDependencies": { "alchemy": "^0.67.0", + "concurrently": "^9.2.1", "dotenv": "^17.2.1",README.md (1)
38-38: Fix heading level and bare URL lint errors.
markdownlintis flagging the H6 jump and the bare Neon URL here. Bump the heading to H3 and wrap the URL in link markdown to keep the docs lint-clean.-###### Obtain the NEON_API_KEY from https://neon.com +### Obtain the NEON_API_KEY from [Neon](https://neon.com)apps/backend/src/routers/index.ts (1)
17-21: Avoid unbounded KV writes in health checkEvery GET health check currently performs a KV write with no TTL and to a very generic key, which turns a read-only probe into a stateful, billable operation that accumulates writes indefinitely. Please switch to a namespaced key and set a short expiration so the probe remains idempotent and low-cost.
- const kvCheckStart = performance.now(); - await env.KV.put("test", "test"); - await env.KV.get("test"); + const kvCheckStart = performance.now(); + const kvKey = "health-check:last"; + await env.KV.put(kvKey, "ok", { expirationTtl: 60 }); + await env.KV.get(kvKey);apps/backend/src/schemas/player-document.ts (1)
5-20: Validate dates and defaults; prefer nullish over nullable.
- Use z.string().datetime() for ISO dates (lastJoinDate, bannedAt, expiresAt).
- Prefer nullish for optional fields and default [] for arrays to avoid null handling in callers.
Apply:
- lastJoinDate: z.string(), - headSkinBase64: z.string().nullable(), + lastJoinDate: z.string().datetime(), + headSkinBase64: z.string().nullish(), stats: z.record(z.string(), z.union([z.string(), z.number(), z.boolean()])), - banData: z - .array( - z.object({ - id: z.string(), - isBanned: z.boolean(), - reason: z.string(), - expiresAt: z.string().nullable(), - bannedAt: z.string(), - bannedBy: z.string(), - }), - ) - .nullable(), + banData: z + .array( + z.object({ + id: z.string(), + isBanned: z.boolean(), + reason: z.string(), + expiresAt: z.string().datetime().nullish(), + bannedAt: z.string().datetime(), + bannedBy: z.string(), + }), + ) + .default([]),apps/wiki/astro.config.mjs (1)
8-35: Set site for correct canonical URLs and sitemaps.Adding site improves SEO and link generation.
Apply:
export default defineConfig({ output: "server", + site: "https://wiki.ssmbrawl.com", adapter: cloudflare({ imageService: "compile", }),apps/web/src/contexts/rpc-context.ts (2)
2-3: Prefer useContext for broader React compatibility.use() requires React 19+ context reading; useContext works across versions.
Apply:
-import { createContext, use } from "react"; +import { createContext, useContext } from "react";
9-14: Use useContext and fix error text.Safer hook and consistent name.
Apply:
export function useRpc(): RpcReactUtils { - const rpc = use(RpcContext); + const rpc = useContext(RpcContext); if (!rpc) { - throw new Error("ORPCContext is not set up properly"); + throw new Error("RpcContext is not set up properly"); }If the app targets React 19+ and intentionally uses use(), feel free to keep it.
alchemy.run.ts (4)
22-26: Nit: task name duplication.Both Exec blocks are named "db-generate". Rename the migrate step for clarity.
Apply:
-await Exec("db-generate", { +await Exec("db-generate", { cwd: "apps/backend", command: "pnpm run db:generate", });And below:
-await Exec("db-generate", { +await Exec("db-migrate", { cwd: "apps/backend", command: `pnpm run db:migrate`,
83-113: Consider deriving CORS origin for non-dev.Optionally set CORS_ORIGIN to https://{webDomainName} when stage ≠ dev to avoid misconfig if env var is absent.
Apply (requires moving webDomainName computation above backend or duplicating logic):
- CORS_ORIGIN: process.env.CORS_ORIGIN || "http://localhost:3000", + CORS_ORIGIN: + process.env.CORS_ORIGIN || + (app.stage === "dev" ? "http://localhost:3000" : `https://${app.stage === "prod" ? "ssmbrawl.com" : `${app.stage}-ssmbrawl.com"}`),Alternatively, compute webDomainName earlier and reference it here.
13-20: Stage variable vs app.stage.You compute stage from env and also use app.stage. Prefer a single source (app.stage) to avoid drift.
61-67: Guard secrets early.If any required secret is missing (NEON_API_KEY, BETTER_AUTH_SECRET, POLAR_ACCESS_TOKEN, PLUGIN_SECRET_KEY), fail fast with a clear error.
I can add a small preflight check if you want.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (7)
apps/wiki/public/favicon.svgis excluded by!**/*.svgpackages/backend/convex/_generated/api.d.tsis excluded by!**/_generated/**packages/backend/convex/_generated/api.jsis excluded by!**/_generated/**packages/backend/convex/_generated/dataModel.d.tsis excluded by!**/_generated/**packages/backend/convex/_generated/server.d.tsis excluded by!**/_generated/**packages/backend/convex/_generated/server.jsis excluded by!**/_generated/**pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (107)
.cursor/rules/convex-rules.mdc(0 hunks).env.example(1 hunks).github/workflows/deploy.yml(1 hunks).gitignore(1 hunks).prettierignore(1 hunks)README.md(1 hunks)alchemy.run.ts(1 hunks)apps/backend/.env.example(1 hunks)apps/backend/drizzle.config.ts(1 hunks)apps/backend/env.d.ts(1 hunks)apps/backend/package.json(1 hunks)apps/backend/src/db/cache.ts(1 hunks)apps/backend/src/db/index.ts(1 hunks)apps/backend/src/db/migrations/0000_bitter_loners.sql(1 hunks)apps/backend/src/db/migrations/0001_sweet_wendell_vaughn.sql(1 hunks)apps/backend/src/db/migrations/meta/0000_snapshot.json(1 hunks)apps/backend/src/db/migrations/meta/0001_snapshot.json(1 hunks)apps/backend/src/db/migrations/meta/_journal.json(1 hunks)apps/backend/src/db/queries/player-documents.ts(1 hunks)apps/backend/src/db/queries/search-player-usernames.ts(1 hunks)apps/backend/src/db/schema/auth.ts(1 hunks)apps/backend/src/db/schema/index.ts(1 hunks)apps/backend/src/db/schema/players.ts(1 hunks)apps/backend/src/index.ts(1 hunks)apps/backend/src/lib/auth.ts(1 hunks)apps/backend/src/lib/context.ts(1 hunks)apps/backend/src/lib/orpc.ts(1 hunks)apps/backend/src/lib/payments.ts(1 hunks)apps/backend/src/routers/index.ts(1 hunks)apps/backend/src/routers/plugin/index.ts(1 hunks)apps/backend/src/routers/plugin/player.ts(1 hunks)apps/backend/src/schemas/pagination-options.ts(1 hunks)apps/backend/src/schemas/player-document.ts(1 hunks)apps/backend/src/sdks/mc-heads.ts(1 hunks)apps/backend/tsconfig.json(1 hunks)apps/fumadocs/.gitignore(0 hunks)apps/fumadocs/README.md(0 hunks)apps/fumadocs/content/docs/index.mdx(0 hunks)apps/fumadocs/content/docs/test.mdx(0 hunks)apps/fumadocs/next.config.mjs(0 hunks)apps/fumadocs/package.json(0 hunks)apps/fumadocs/postcss.config.mjs(0 hunks)apps/fumadocs/source.config.ts(0 hunks)apps/fumadocs/src/app/(home)/layout.tsx(0 hunks)apps/fumadocs/src/app/(home)/page.tsx(0 hunks)apps/fumadocs/src/app/api/search/route.ts(0 hunks)apps/fumadocs/src/app/docs/[[...slug]]/page.tsx(0 hunks)apps/fumadocs/src/app/docs/layout.tsx(0 hunks)apps/fumadocs/src/app/global.css(0 hunks)apps/fumadocs/src/app/layout.tsx(0 hunks)apps/fumadocs/src/lib/layout.shared.tsx(0 hunks)apps/fumadocs/src/lib/source.ts(0 hunks)apps/fumadocs/src/mdx-components.tsx(0 hunks)apps/fumadocs/tsconfig.json(0 hunks)apps/web/package.json(2 hunks)apps/web/src/contexts/rpc-context.ts(1 hunks)apps/web/src/lib/auth-client.ts(1 hunks)apps/web/src/routeTree.gen.ts(1 hunks)apps/web/src/router.tsx(2 hunks)apps/web/src/routes/__root.tsx(2 hunks)apps/web/src/routes/index.tsx(1 hunks)apps/web/src/server.ts(0 hunks)apps/web/tsconfig.json(1 hunks)apps/web/vite.config.ts(1 hunks)apps/wiki/.gitignore(1 hunks)apps/wiki/.vscode/extensions.json(1 hunks)apps/wiki/.vscode/launch.json(1 hunks)apps/wiki/README.md(1 hunks)apps/wiki/astro.config.mjs(1 hunks)apps/wiki/package.json(1 hunks)apps/wiki/src/content.config.ts(1 hunks)apps/wiki/src/content/docs/guides/get-started.md(1 hunks)apps/wiki/src/content/docs/index.mdx(1 hunks)apps/wiki/src/content/docs/kits/blaze.md(1 hunks)apps/wiki/src/content/docs/kits/creeper.md(1 hunks)apps/wiki/src/content/docs/kits/enderman.md(1 hunks)apps/wiki/src/content/docs/kits/guardian.md(1 hunks)apps/wiki/src/content/docs/kits/horse.md(1 hunks)apps/wiki/src/content/docs/kits/iron-golem.md(1 hunks)apps/wiki/src/content/docs/kits/magma-cube.md(1 hunks)apps/wiki/src/content/docs/kits/mooshroom.md(1 hunks)apps/wiki/src/content/docs/kits/pig.md(1 hunks)apps/wiki/src/content/docs/kits/sheep.md(1 hunks)apps/wiki/src/content/docs/kits/slime.md(1 hunks)apps/wiki/src/content/docs/kits/snowman.md(1 hunks)apps/wiki/src/content/docs/kits/spider.md(1 hunks)apps/wiki/src/content/docs/kits/squid.md(1 hunks)apps/wiki/src/content/docs/kits/villager.md(1 hunks)apps/wiki/src/content/docs/kits/witch.md(1 hunks)apps/wiki/src/content/docs/kits/wither-skeleton.md(1 hunks)apps/wiki/src/content/docs/kits/wolf.md(1 hunks)apps/wiki/src/content/docs/kits/zombie.md(1 hunks)apps/wiki/src/custom.css(1 hunks)apps/wiki/tsconfig.json(1 hunks)package.json(1 hunks)packages/backend/.gitignore(0 hunks)packages/backend/convex/README.md(0 hunks)packages/backend/convex/auth.config.ts(0 hunks)packages/backend/convex/common.ts(0 hunks)packages/backend/convex/healthCheck.ts(0 hunks)packages/backend/convex/http.ts(0 hunks)packages/backend/convex/kv.ts(0 hunks)packages/backend/convex/players.ts(0 hunks)packages/backend/convex/schema.ts(0 hunks)packages/backend/convex/schemas.ts(0 hunks)packages/backend/convex/tsconfig.json(0 hunks)packages/backend/package.json(0 hunks)
⛔ Files not processed due to max files limit (2)
- plugin/src/main/kotlin/dev/betrix/superSmashMobsBrawl/models/brawlData/AbilityDef.kt
- plugin/src/main/kotlin/dev/betrix/superSmashMobsBrawl/models/player/PlayerDocument.kt
💤 Files with no reviewable changes (33)
- packages/backend/convex/players.ts
- apps/fumadocs/src/app/global.css
- apps/fumadocs/README.md
- packages/backend/convex/README.md
- apps/fumadocs/src/app/(home)/layout.tsx
- packages/backend/convex/schemas.ts
- apps/fumadocs/src/lib/source.ts
- apps/fumadocs/src/mdx-components.tsx
- apps/fumadocs/src/app/docs/layout.tsx
- apps/fumadocs/content/docs/test.mdx
- packages/backend/convex/schema.ts
- apps/fumadocs/source.config.ts
- apps/fumadocs/src/app/(home)/page.tsx
- packages/backend/convex/healthCheck.ts
- apps/fumadocs/src/lib/layout.shared.tsx
- packages/backend/.gitignore
- apps/fumadocs/package.json
- packages/backend/convex/common.ts
- apps/fumadocs/postcss.config.mjs
- .cursor/rules/convex-rules.mdc
- apps/web/src/server.ts
- packages/backend/convex/auth.config.ts
- apps/fumadocs/src/app/layout.tsx
- apps/fumadocs/src/app/api/search/route.ts
- apps/fumadocs/.gitignore
- packages/backend/package.json
- apps/fumadocs/tsconfig.json
- apps/fumadocs/next.config.mjs
- apps/fumadocs/src/app/docs/[[...slug]]/page.tsx
- apps/fumadocs/content/docs/index.mdx
- packages/backend/convex/tsconfig.json
- packages/backend/convex/http.ts
- packages/backend/convex/kv.ts
🧰 Additional context used
📓 Path-based instructions (1)
package.json
📄 CodeRabbit inference engine (.cursor/rules/convex-rules.mdc)
Add @types/node to package.json when using Node.js built-in modules
Files:
package.json
🧠 Learnings (5)
📚 Learning: 2025-09-22T00:08:49.174Z
Learnt from: CR
PR: BetrixDev/ssm-brawl#0
File: .cursor/rules/convex-rules.mdc:0-0
Timestamp: 2025-09-22T00:08:49.174Z
Learning: Applies to convex/**/*.{ts,js} : Define paginated queries using paginationOptsValidator and .paginate(opts); return the paginate result object
Applied to files:
apps/backend/src/schemas/pagination-options.ts
📚 Learning: 2025-09-22T00:08:49.174Z
Learnt from: CR
PR: BetrixDev/ssm-brawl#0
File: .cursor/rules/convex-rules.mdc:0-0
Timestamp: 2025-09-22T00:08:49.174Z
Learning: Applies to package.json : Add types/node to package.json when using Node.js built-in modules
Applied to files:
package.json
📚 Learning: 2025-09-22T00:08:49.174Z
Learnt from: CR
PR: BetrixDev/ssm-brawl#0
File: .cursor/rules/convex-rules.mdc:0-0
Timestamp: 2025-09-22T00:08:49.174Z
Learning: Applies to convex/**/*.{ts,js} : Add "use node" to the top of files containing actions that use Node.js built-in modules
Applied to files:
package.json
📚 Learning: 2025-09-22T00:08:49.174Z
Learnt from: CR
PR: BetrixDev/ssm-brawl#0
File: .cursor/rules/convex-rules.mdc:0-0
Timestamp: 2025-09-22T00:08:49.174Z
Learning: Applies to convex/schema.ts : Import schema helpers (defineSchema, defineTable) from convex/server in the schema file
Applied to files:
apps/backend/src/db/schema/index.ts
📚 Learning: 2025-09-22T00:08:49.174Z
Learnt from: CR
PR: BetrixDev/ssm-brawl#0
File: .cursor/rules/convex-rules.mdc:0-0
Timestamp: 2025-09-22T00:08:49.174Z
Learning: Applies to convex/**/*.{ts,js} : Organize public Convex functions (query/mutation/action) within the convex/ directory, leveraging file-based routing
Applied to files:
apps/web/src/routes/__root.tsx
🧬 Code graph analysis (18)
apps/backend/src/db/queries/search-player-usernames.ts (2)
apps/backend/src/schemas/pagination-options.ts (1)
PaginationOptions(8-8)apps/backend/src/db/index.ts (2)
db(11-15)Table(17-17)
apps/backend/src/lib/context.ts (1)
apps/backend/src/lib/auth.ts (1)
auth(10-52)
apps/backend/src/db/index.ts (1)
apps/backend/src/db/cache.ts (1)
CloudflareKvCache(6-105)
apps/backend/src/routers/plugin/index.ts (1)
apps/backend/src/routers/plugin/player.ts (1)
pluginPlayersRouter(6-38)
apps/web/src/lib/auth-client.ts (1)
apps/backend/src/lib/payments.ts (1)
polarClient(7-10)
apps/backend/src/routers/plugin/player.ts (3)
apps/backend/src/lib/orpc.ts (1)
pluginProcedure(31-31)apps/backend/src/schemas/player-document.ts (1)
playerDocumentSchema(3-20)apps/backend/src/db/queries/player-documents.ts (2)
getPlayerDocument(7-33)updatePlayerDocument(59-100)
apps/backend/src/index.ts (3)
apps/backend/src/lib/auth.ts (1)
auth(10-52)apps/backend/src/routers/index.ts (1)
appRouter(7-30)apps/backend/src/lib/context.ts (1)
createContext(8-17)
apps/web/src/contexts/rpc-context.ts (1)
apps/backend/src/routers/index.ts (1)
AppRouterClient(33-33)
apps/backend/src/lib/auth.ts (2)
apps/backend/src/db/index.ts (1)
db(11-15)apps/backend/src/lib/payments.ts (1)
polarClient(7-10)
apps/backend/src/db/queries/player-documents.ts (5)
plugin/src/main/kotlin/dev/betrix/superSmashMobsBrawl/models/player/PlayerDocument.kt (1)
uuid(92-92)apps/backend/src/schemas/player-document.ts (1)
PlayerDocument(22-22)apps/backend/src/db/index.ts (2)
db(11-15)Table(17-17)apps/backend/src/db/schema/players.ts (2)
players(4-17)playerBans(23-34)apps/backend/src/sdks/mc-heads.ts (1)
getPlayerHeadSkinBase64(1-14)
apps/backend/env.d.ts (1)
alchemy.run.ts (1)
backend(52-81)
apps/backend/src/routers/index.ts (3)
apps/backend/src/lib/orpc.ts (1)
publicProcedure(29-29)apps/backend/src/db/index.ts (1)
db(11-15)apps/backend/src/routers/plugin/index.ts (1)
pluginRouter(3-5)
apps/backend/src/lib/orpc.ts (1)
apps/backend/src/lib/context.ts (1)
Context(19-19)
apps/web/src/routeTree.gen.ts (1)
apps/web/src/router.tsx (1)
getRouter(13-41)
apps/web/src/routes/index.tsx (1)
apps/web/src/contexts/rpc-context.ts (1)
useRpc(9-17)
apps/web/src/router.tsx (2)
apps/backend/src/routers/index.ts (1)
AppRouterClient(33-33)apps/web/src/contexts/rpc-context.ts (1)
RpcContext(7-7)
apps/web/src/routes/__root.tsx (1)
apps/backend/src/routers/index.ts (1)
AppRouterClient(33-33)
apps/backend/src/db/cache.ts (1)
apps/backend/src/db/index.ts (1)
Table(17-17)
🪛 dotenv-linter (3.3.0)
.env.example
[warning] 4-4: [EndingBlankLine] No blank line at the end of the file
(EndingBlankLine)
[warning] 4-4: [UnorderedKey] The CLOUDFLARE_ZONE_ID key should go before the NEON_API_KEY key
(UnorderedKey)
apps/backend/.env.example
[warning] 2-2: [UnorderedKey] The BETTER_AUTH_SECRET key should go before the CORS_ORIGIN key
(UnorderedKey)
[warning] 3-3: [UnorderedKey] The BETTER_AUTH_URL key should go before the CORS_ORIGIN key
(UnorderedKey)
[warning] 6-6: [EndingBlankLine] No blank line at the end of the file
(EndingBlankLine)
[warning] 6-6: [UnorderedKey] The PLUGIN_SECRET_KEY key should go before the POLAR_ACCESS_TOKEN key
(UnorderedKey)
🪛 markdownlint-cli2 (0.18.1)
apps/wiki/README.md
5-5: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
15-15: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
README.md
38-38: Heading levels should only increment by one level at a time
Expected: h3; Actual: h6
(MD001, heading-increment)
38-38: Bare URL used
(MD034, no-bare-urls)
🪛 GitHub Actions: autofix.ci
.github/workflows/deploy.yml
[error] 1-1: The autofix.ci action is not allowed to modify the .github directory.
🔇 Additional comments (12)
apps/wiki/.vscode/extensions.json (1)
1-4: Helpful Astro tooling recommendationAdding the Astro VSCode extension keeps the wiki workspace aligned with the new Astro setup and improves dev ergonomics. Looks good.
.env.example (1)
1-4: Thanks for expanding the root env templateDocumenting these deployment credentials up front will make local/scoped CLI runs smoother for newcomers. No further action needed.
apps/wiki/tsconfig.json (1)
1-5: Astro TS config is spot onExtending the strict preset with the usual include/exclude mirrors Astro guidance and should keep typings tidy.
apps/backend/.env.example (1)
1-6: Backend env placeholders look completeCapturing the auth and Polar secrets here will help avoid misconfigured deployments. All good.
.gitignore (1)
3-6: Ignore additions make senseKeeping plugin artifacts, Alchemy state, local envs, and JSONC configs out of Git aligns with the new tooling.
apps/wiki/src/content/docs/kits/squid.md (1)
1-4: Front matter looks good.Thanks for wiring up the Squid kit doc metadata.
apps/wiki/src/content/docs/kits/enderman.md (1)
1-4: Front matter looks good.All metadata fields are in place for the Enderman kit page.
apps/wiki/src/content/docs/kits/iron-golem.md (1)
1-4: Front matter looks good.Metadata for the Iron Golem kit page is correctly defined.
apps/web/tsconfig.json (1)
27-28: backend tsconfig.json already enables “composite”: true – reference build will succeed.apps/backend/src/schemas/player-document.ts (1)
7-7: Confirm stats value shapes.If stats are counters/times, consider z.number().int() where appropriate; otherwise current union is fine.
apps/wiki/astro.config.mjs (1)
10-12: Double-check Cloudflare imageService choice.Verify "compile" is intended; use "cloudflare-images" if you rely on Cloudflare Images.
alchemy.run.ts (1)
46-50: Verify domain patterns exist.Ensure DNS and Cloudflare zones support the hyphenated subdomains (e.g., stage-ssmbrawl.com, stage-wiki.ssmbrawl.com) and the intended routing.
Also applies to: 83-88, 119-123
| external: ["cloudflare:workers"], | ||
| }, | ||
| }, | ||
| plugins: [alchemy(), tsconfigPaths(), tailwindcss(), tanstackStart(), viteReact()], |
There was a problem hiding this comment.
Avoid double-registering the React plugin.
tanstackStart() injects Vite’s React plugin unless customViteReactPlugin is set to true. Because we still invoke viteReact() manually, this change now wires the React plugin twice, which breaks Fast Refresh and can trigger duplicate transform errors. Please keep customViteReactPlugin: true (or drop the manual viteReact() call).
- plugins: [alchemy(), tsconfigPaths(), tailwindcss(), tanstackStart(), viteReact()],
+ plugins: [
+ alchemy(),
+ tsconfigPaths(),
+ tailwindcss(),
+ tanstackStart({
+ customViteReactPlugin: true,
+ }),
+ viteReact(),
+ ],🤖 Prompt for AI Agents
In apps/web/vite.config.ts around line 14, the React plugin is being registered
twice (tanstackStart() injects Vite’s React plugin by default and viteReact() is
also included), which breaks Fast Refresh and can cause duplicate transform
errors; fix it by either removing the manual viteReact() from the plugins array
or configure tanstackStart({ customViteReactPlugin: true }) so tanstackStart
will not auto-inject React, ensuring only one React plugin is registered.
There was a problem hiding this comment.
This is how it's done in the new version of tanstack start
| ``` | ||
| pnpm create astro@latest -- --template starlight | ||
| ``` |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Add languages to fenced code blocks
markdownlint (MD040) is failing because these code fences lack a language hint. Please tag the command block as bash (or similar) and the directory tree as text so the lint pipeline passes. Based on static analysis hints.
-```
+```bash
pnpm create astro@latest -- --template starlight@@
- +text
.
├── public/
├── src/
@@
-└── tsconfig.json
- +└── tsconfig.json +
Also applies to: 15-26
<details>
<summary>🧰 Tools</summary>
<details>
<summary>🪛 markdownlint-cli2 (0.18.1)</summary>
5-5: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
</details>
</details>
<details>
<summary>🤖 Prompt for AI Agents</summary>
In apps/wiki/README.md around lines 5-7 and 15-26, the fenced code blocks are
missing language hints (causing markdownlint MD040); update the first command
block to use a bash language tag (change tobash) and update the
directory tree block to use a text tag (change totext) so the linter
recognizes the languages; apply the same change for all similar fenced blocks
mentioned (lines 15-26) ensuring each opening fence includes the appropriate
language token.
</details>
<!-- fingerprinting:phantom:poseidon:sabertoothed -->
<!-- This is an auto-generated comment by CodeRabbit -->
There was a problem hiding this comment.
Actionable comments posted: 3
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (16)
.github/workflows/deploy.yml(1 hunks)alchemy.run.ts(1 hunks)apps/backend/drizzle.config.ts(1 hunks)apps/backend/package.json(1 hunks)apps/backend/src/db/index.ts(1 hunks)apps/backend/src/db/queries/player-documents.ts(1 hunks)apps/backend/src/db/queries/search-player-usernames.ts(1 hunks)apps/backend/src/index.ts(1 hunks)apps/backend/src/lib/auth.ts(1 hunks)apps/backend/src/lib/context.ts(1 hunks)apps/backend/src/lib/orpc.ts(1 hunks)apps/backend/src/lib/payments.ts(1 hunks)apps/backend/src/routers/index.ts(1 hunks)apps/backend/src/routers/plugin/index.ts(1 hunks)apps/backend/src/routers/plugin/player.ts(1 hunks)apps/backend/src/sdks/mc-heads.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
- apps/backend/src/routers/index.ts
- apps/backend/src/lib/context.ts
- alchemy.run.ts
- apps/backend/src/lib/payments.ts
- .github/workflows/deploy.yml
- apps/backend/drizzle.config.ts
- apps/backend/src/routers/plugin/player.ts
🧰 Additional context used
🧬 Code graph analysis (6)
apps/backend/src/routers/plugin/index.ts (2)
apps/backend/src/lib/orpc.ts (1)
o(7-7)apps/backend/src/routers/plugin/player.ts (1)
pluginPlayersRouter(6-40)
apps/backend/src/db/queries/search-player-usernames.ts (2)
apps/backend/src/schemas/pagination-options.ts (1)
PaginationOptions(8-8)apps/backend/src/db/index.ts (1)
Table(18-18)
apps/backend/src/lib/auth.ts (2)
apps/backend/src/db/index.ts (1)
getDb(5-14)apps/backend/src/lib/payments.ts (1)
polarClient(7-10)
apps/backend/src/index.ts (4)
apps/backend/src/lib/auth.ts (1)
getAuth(10-54)apps/backend/src/db/index.ts (1)
getDb(5-14)apps/backend/src/routers/index.ts (1)
appRouter(6-48)apps/backend/src/lib/context.ts (1)
createContext(7-11)
apps/backend/src/lib/orpc.ts (3)
apps/backend/src/lib/context.ts (1)
Context(13-13)apps/backend/src/db/index.ts (2)
Database(16-16)getDb(5-14)apps/backend/src/lib/auth.ts (1)
getAuth(10-54)
apps/backend/src/db/queries/player-documents.ts (4)
apps/backend/src/db/index.ts (2)
Database(16-16)Table(18-18)apps/backend/src/schemas/player-document.ts (1)
PlayerDocument(22-22)apps/backend/src/db/schema/players.ts (2)
players(4-17)playerBans(23-34)apps/backend/src/sdks/mc-heads.ts (1)
getPlayerHeadSkinBase64(1-16)
🔇 Additional comments (6)
apps/backend/package.json (1)
36-42: Drop the duplicate dotenv entry.
dotenvis already independencies. Keeping it indevDependenciesinstalls it twice and keeps the lockfile noisier. Please remove the duplicate fromdevDependencies."devDependencies": { "@cloudflare/workers-types": "^4.20250822.0", "@types/node": "^22.13.11", "@types/pg": "^8.15.5", "alchemy": "^0.67.0", - "dotenv": "^17.2.1", "drizzle-kit": "^0.31.2", "tsdown": "^0.15.1", "typescript": "^5.8.2", "wrangler": "^4.23.0" }apps/backend/src/lib/auth.ts (1)
12-16: Fix the Drizzle provider string for BetterAuth.
drizzleAdapteronly accepts"postgresql","sqlite", or"mysql"; passing"pg"leaves the adapter on the default path and it will still emit SQLite-style SQL, breaking auth persistence against Postgres. Swap this to"postgresql"so BetterAuth generates the correct statements.- provider: "pg", + provider: "postgresql",apps/backend/src/sdks/mc-heads.ts (1)
3-11: Guard non-OK mc-heads responses before base64 encodingLine 3 currently reads the body even when the service returns 4xx/5xx, so we end up storing a base64-encoded HTML error instead of failing fast. Please check
response.okbefore converting and bail out withnullon failure.- const responsePng = await fetch(`https://mc-heads.net/avatar/${uuid}`).then((res) => - res.arrayBuffer(), - ); - - const uint8Array = new Uint8Array(responsePng); + const response = await fetch(`https://mc-heads.net/avatar/${uuid}`); + + if (!response.ok) { + console.warn( + "mc-heads returned non-OK response", + response.status, + response.statusText, + ); + return null; + } + + const arrayBuffer = await response.arrayBuffer(); + + const uint8Array = new Uint8Array(arrayBuffer);apps/backend/src/db/queries/search-player-usernames.ts (1)
10-11: Useplainto_tsqueryto avoid tsquery syntax errorsLine 10 pipes raw user input through
to_tsquery, which blows up on common inputs like"mario kart"(Postgres expects connectors). Switch toplainto_tsquery(orwebsearch_to_tsquery) so natural text works.- sql`to_tsvector('english', ${Table.players.username}) @@ to_tsquery('english', ${query})`, + sql`to_tsvector('english', ${Table.players.username}) @@ plainto_tsquery('english', ${query})`,apps/backend/src/lib/orpc.ts (1)
9-16: Preserve full context when forwarding from middlewareEach of these middlewares calls
next({ context: { … } })with only the freshly introduced field, which drops everything else (headers,db,auth, etc.) that previous providers injected. AftersessionProviderruns, aprotectedProcedurehandler receives{ session }instead of the full request context, so anything expectingheadersordbimmediately breaks. This is the same regression that was flagged earlier onrequireAuth—please forward the already-mutated context instead of replacing it.- return next({ - context: { - db: context.db, - }, - }); + return next({ context }); … - return next({ - context: { - auth: context.auth, - }, - }); + return next({ context }); … - return next({ - context: { - session: context.session, - }, - }); + return next({ context }); … - return next({ - context: { - session: context.session, - }, - }); + return next({ context });Also applies to: 26-30, 48-51, 64-68
apps/backend/src/db/queries/player-documents.ts (1)
67-71: Stop overwriting the historical first-join timestampWe’re still setting
firstJoinedDatetodocument.lastJoinDate, so every update clobbers the original “first seen” timestamp with the most recent join. Drop this assignment (or source the real first join value) so the historical record survives.await tx .update(Table.players) .set({ lastJoinedDate: new Date(document.lastJoinDate), - firstJoinedDate: new Date(document.lastJoinDate), stats: document.stats, })
There was a problem hiding this comment.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
apps/backend/src/db/index.ts(1 hunks)apps/backend/src/db/queries/player-documents.ts(1 hunks)apps/backend/src/index.ts(1 hunks)apps/backend/src/lib/auth.ts(1 hunks)apps/backend/src/lib/orpc.ts(1 hunks)apps/wiki/src/custom.css(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/wiki/src/custom.css
- apps/backend/src/db/index.ts
🧰 Additional context used
🧬 Code graph analysis (4)
apps/backend/src/lib/auth.ts (2)
apps/backend/src/db/index.ts (1)
Database(14-14)apps/backend/src/lib/payments.ts (1)
polarClient(7-10)
apps/backend/src/lib/orpc.ts (3)
apps/backend/src/lib/context.ts (1)
Context(13-13)apps/backend/src/db/index.ts (2)
Database(14-14)getDb(5-12)apps/backend/src/lib/auth.ts (1)
getAuth(10-54)
apps/backend/src/db/queries/player-documents.ts (4)
apps/backend/src/db/index.ts (2)
Database(14-14)Table(16-16)apps/backend/src/schemas/player-document.ts (1)
PlayerDocument(22-22)apps/backend/src/db/schema/players.ts (2)
players(4-17)playerBans(23-34)apps/backend/src/sdks/mc-heads.ts (1)
getPlayerHeadSkinBase64(1-16)
apps/backend/src/index.ts (4)
apps/backend/src/lib/auth.ts (1)
getAuth(10-54)apps/backend/src/db/index.ts (1)
getDb(5-12)apps/backend/src/routers/index.ts (1)
appRouter(6-48)apps/backend/src/lib/context.ts (1)
createContext(7-11)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build-and-test
🔇 Additional comments (4)
apps/backend/src/db/queries/player-documents.ts (1)
67-70: Stop resettingfirstJoinedDateto the latest joinLine 68 currently rewrites
firstJoinedDatewithdocument.lastJoinDate, so every sync erases the original first-join timestamp and makes it equal to the latest session. That destroys the historical “first seen” data this column is supposed to preserve. Please drop this assignment (or populate it from an actualdocument.firstJoinDatefield if one exists) so we keep the original value intact.lastJoinedDate: new Date(document.lastJoinDate), - firstJoinedDate: new Date(document.lastJoinDate), stats: document.stats,apps/backend/src/lib/auth.ts (1)
12-16: Use the supported Postgres provider identifier
drizzleAdapterswitches on this string and only recognizes"postgresql". Leaving it as"pg"still routes you through the sqlite branch, so auth inserts/queries against Postgres will break. Please restore the correct identifier.- provider: "pg", + provider: "postgresql",apps/backend/src/lib/orpc.ts (2)
64-67: Keep the rest of the context visible inrequireAuthThis still replaces the whole context with
{ session }, so handlers followingprotectedProcedurecan no longer see the DB, headers, or auth client they were given earlier. Merge instead of overwriting the object.return next({ context: { - session: context.session, + ...context, }, });
48-51: Preserve context when returning fromsessionProviderBy returning only
{ session }you strip away the DB/auth/headers that protected procedures rely on. A handler that callsprotectedProcedure.use(dbProvider)ends up withcontext.dbundefinedagain. Merge the current context when you propagate.return next({ context: { - session: context.session, + ...context, }, });
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
apps/backend/Dockerfile.migrate (1)
7-9: Copy the lockfile so installs stay deterministic and cacheable.We only copy
package.jsonbefore runningbun install, so the dependency graph is resolved withoutbun.lockb. That means every build (and CI run) can silently drift to newer dependency ranges and you also miss out on layer caching when the lockfile hasn’t changed. Please copy the lockfile alongsidepackage.jsonbeforebun installso installs remain reproducible.FROM base AS deps -COPY package.json ./ +COPY package.json bun.lockb ./ RUN bun install
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
bun.lockis excluded by!**/*.lockpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (24)
.gitignore(1 hunks)README.md(1 hunks)apps/backend/.dockerignore(1 hunks)apps/backend/Dockerfile(1 hunks)apps/backend/Dockerfile.migrate(1 hunks)apps/backend/drizzle.config.ts(1 hunks)apps/backend/package.json(1 hunks)apps/backend/src/db/index.ts(1 hunks)apps/backend/src/index.ts(1 hunks)apps/backend/src/lib/auth.ts(1 hunks)apps/backend/src/lib/env.ts(1 hunks)apps/backend/src/lib/orpc.ts(1 hunks)apps/backend/src/lib/payments.ts(1 hunks)apps/backend/src/lib/redis.ts(1 hunks)apps/backend/src/routers/index.ts(1 hunks)apps/backend/tsconfig.json(1 hunks)apps/web/.gitignore(0 hunks)apps/web/package.json(2 hunks)apps/web/src/router.tsx(2 hunks)apps/web/vite.config.ts(1 hunks)apps/wiki/astro.config.mjs(1 hunks)apps/wiki/package.json(1 hunks)docker-compose.yml(1 hunks)package.json(1 hunks)
💤 Files with no reviewable changes (1)
- apps/web/.gitignore
✅ Files skipped from review due to trivial changes (2)
- apps/backend/.dockerignore
- apps/backend/Dockerfile
🚧 Files skipped from review as they are similar to previous changes (10)
- apps/backend/package.json
- apps/backend/src/routers/index.ts
- apps/backend/src/lib/auth.ts
- apps/backend/src/db/index.ts
- .gitignore
- apps/wiki/package.json
- apps/backend/tsconfig.json
- apps/backend/src/lib/payments.ts
- apps/backend/src/index.ts
- README.md
🧰 Additional context used
📓 Path-based instructions (1)
package.json
📄 CodeRabbit inference engine (.cursor/rules/convex-rules.mdc)
Add @types/node to package.json when using Node.js built-in modules
Files:
package.json
🧠 Learnings (3)
📚 Learning: 2025-09-22T00:08:49.174Z
Learnt from: CR
PR: BetrixDev/ssm-brawl#0
File: .cursor/rules/convex-rules.mdc:0-0
Timestamp: 2025-09-22T00:08:49.174Z
Learning: Applies to package.json : Add types/node to package.json when using Node.js built-in modules
Applied to files:
package.json
📚 Learning: 2025-09-22T00:08:49.174Z
Learnt from: CR
PR: BetrixDev/ssm-brawl#0
File: .cursor/rules/convex-rules.mdc:0-0
Timestamp: 2025-09-22T00:08:49.174Z
Learning: Applies to convex/**/*.{ts,js} : Organize public Convex functions (query/mutation/action) within the convex/ directory, leveraging file-based routing
Applied to files:
apps/web/src/router.tsx
📚 Learning: 2025-09-22T00:08:49.174Z
Learnt from: CR
PR: BetrixDev/ssm-brawl#0
File: .cursor/rules/convex-rules.mdc:0-0
Timestamp: 2025-09-22T00:08:49.174Z
Learning: Applies to convex/**/*.{ts,js} : Respect file-based routing for function references (e.g., convex/example.ts export f -> api.example.f; nested paths map accordingly)
Applied to files:
apps/web/src/router.tsx
🧬 Code graph analysis (3)
apps/backend/src/lib/redis.ts (1)
apps/backend/src/lib/env.ts (1)
env(18-18)
apps/backend/src/lib/orpc.ts (5)
apps/backend/src/lib/context.ts (1)
Context(13-13)apps/backend/src/lib/redis.ts (1)
getRedis(4-12)apps/backend/src/db/index.ts (2)
Database(14-14)getDb(5-12)apps/backend/src/lib/auth.ts (1)
getAuth(10-53)apps/backend/src/lib/env.ts (1)
env(18-18)
apps/web/src/router.tsx (2)
apps/backend/src/routers/index.ts (1)
AppRouterClient(51-51)apps/web/src/contexts/rpc-context.ts (1)
RpcContext(7-7)
🪛 Biome (2.1.2)
apps/web/vite.config.ts
[error] 9-9: This array contains an empty slots..
The presences of empty slots may cause incorrect information and might be a typo.
Unsafe fix: Replace hole with undefined
(lint/suspicious/noSparseArray)
🔇 Additional comments (5)
apps/backend/src/lib/orpc.ts (3)
25-29: Stop clobbering context indbProvider.Line 27 still replaces the accumulated context with
{ db }, dropping headers and thekvinstance. This is the same blocker called out in the previous review; we must preserve everything gathered so far.Apply this diff:
return next({ - context: { - db: context.db, - }, + context: { + ...context, + }, });
38-42: Keep the accumulated context when settingauth.Line 40 throws away
db,kv, andheadersby replacing the context with{ auth }. That exact regression was already flagged; without the spread, the downstreamsessionProvidercan’t see the database or headers.Apply this diff:
return next({ - context: { - auth: context.auth, - }, + context: { + ...context, + }, });
77-81: Forward the whole context insiderequireAuth.Line 79 once more shrinks the context to
{ session }, undoing all prior merges. WhenpluginProcedurecomposes this middleware,context.headersvanishes. Keep forwarding the merged context.Apply this diff:
return next({ - context: { - session: context.session, - }, + context: { + ...context, + }, });apps/web/vite.config.ts (1)
9-9: Respect TanStack Start's React plugin opt-out.
TanStack Start still auto-registers the React plugin unless you passcustomViteReactPlugin: true; leaving it out while also callingviteReact()double-loads the plugin and breaks Fast Refresh. Please restore the opt-out flag.
(tanstack.com)- plugins: [tsconfigPaths(), tailwindcss(), tanstackStart(), nitro(), , viteReact()], + plugins: [ + tsconfigPaths(), + tailwindcss(), + tanstackStart({ + customViteReactPlugin: true, + }), + nitro(), + viteReact(), + ],apps/backend/drizzle.config.ts (1)
8-10: Fail fast whenDATABASE_URLis missing.
The non-null assertion letsundefinedreach Drizzle, so the CLI fails later with an opaque connection error. Guard the env var up front and throw a clear message instead.-import { defineConfig } from "drizzle-kit"; - -export default defineConfig({ +import { defineConfig } from "drizzle-kit"; + +const databaseUrl = process.env.DATABASE_URL; + +if (!databaseUrl) { + throw new Error("DATABASE_URL is not set. Configure the database connection before running drizzle-kit."); +} + +export default defineConfig({ schema: "./src/db/schema", out: "./src/db/migrations", casing: "snake_case", dialect: "postgresql", dbCredentials: { - url: process.env.DATABASE_URL!, + url: databaseUrl, }, });
| tanstackStart({ customViteReactPlugin: true, target: "vercel" }), | ||
| viteReact(), | ||
| ], | ||
| plugins: [tsconfigPaths(), tailwindcss(), tanstackStart(), nitro(), , viteReact()], |
There was a problem hiding this comment.
Remove the stray sparse slot in the plugins array.
There’s an extra comma after nitro() leaving an empty slot, so Vite receives an undefined plugin entry; drop the extra comma to keep the array dense.
- plugins: [tsconfigPaths(), tailwindcss(), tanstackStart(), nitro(), , viteReact()],
+ plugins: [tsconfigPaths(), tailwindcss(), tanstackStart(), nitro(), viteReact()],📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| plugins: [tsconfigPaths(), tailwindcss(), tanstackStart(), nitro(), , viteReact()], | |
| plugins: [tsconfigPaths(), tailwindcss(), tanstackStart(), nitro(), viteReact()], |
🧰 Tools
🪛 Biome (2.1.2)
[error] 9-9: This array contains an empty slots..
The presences of empty slots may cause incorrect information and might be a typo.
Unsafe fix: Replace hole with undefined
(lint/suspicious/noSparseArray)
🤖 Prompt for AI Agents
In apps/web/vite.config.ts around line 9, the plugins array contains a stray
extra comma after nitro() creating an undefined plugin entry; remove the extra
comma so the array reads plugins: [tsconfigPaths(), tailwindcss(),
tanstackStart(), nitro(), viteReact()] (no empty slot) to prevent Vite from
receiving an undefined plugin.
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.github/workflows/autofix.yml (1)
3-5: Restore the pull_request trigger for autofix-ci
autofix-ci/actionneeds PR context to push formatting fixes back to contributor branches. By restricting the workflow topushonmain/reimagined, the action never runs for feature branches, so PRs lose the intended auto-formatting feedback loop. Please add back thepull_requesttrigger (or otherwise ensure PR events invoke this job).
🧹 Nitpick comments (2)
turbo.json (1)
8-8: Broaden the server binary output glob.Right now only
server.exeis cached, so binaries emitted on non-Windows runners (e.g.,server,server-linux-x64) will be missed and need rebuilding every time. Please widen the pattern—something likeserver*or a dedicatedbin/**directory—to cover all platforms..env.development.example (1)
1-6: Align env keys withdotenv-linterexpectations.
dotenv-linteris flagging this file because the keys aren’t ordered alphabetically and there’s no trailing newline. Reordering the entries and adding a blank line at the end will silence those warnings and keep the lint job quiet.-BETTER_AUTH_SECRET= -POLAR_ACCESS_TOKEN= -POLAR_SUCCESS_URL= -PLUGIN_SECRET_KEY= -REDIS_URL= -DATABASE_URL= +BETTER_AUTH_SECRET= +DATABASE_URL= +PLUGIN_SECRET_KEY= +POLAR_ACCESS_TOKEN= +POLAR_SUCCESS_URL= +REDIS_URL= +
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (16)
.env.development.example(1 hunks).github/workflows/autofix.yml(1 hunks).github/workflows/build-and-test.yml(2 hunks).gitignore(1 hunks)apps/backend/package.json(1 hunks)apps/backend/src/db/migrations/meta/0001_snapshot.json(1 hunks)apps/backend/src/db/migrations/meta/_journal.json(1 hunks)apps/web/.env.example(1 hunks)apps/web/package.json(2 hunks)apps/web/vite.config.ts(1 hunks)docker-compose.yml(1 hunks)package.json(1 hunks)plugin/package.json(1 hunks)plugin/scripts/run-gradle.mjs(1 hunks)pnpm-workspace.yaml(0 hunks)turbo.json(1 hunks)
💤 Files with no reviewable changes (1)
- pnpm-workspace.yaml
🚧 Files skipped from review as they are similar to previous changes (3)
- .gitignore
- apps/backend/src/db/migrations/meta/0001_snapshot.json
- apps/web/vite.config.ts
🧰 Additional context used
📓 Path-based instructions (1)
package.json
📄 CodeRabbit inference engine (.cursor/rules/convex-rules.mdc)
Add @types/node to package.json when using Node.js built-in modules
Files:
package.json
🧠 Learnings (2)
📚 Learning: 2025-09-22T00:09:59.281Z
Learnt from: CR
PR: BetrixDev/ssm-brawl#0
File: .cursor/rules/plugin-overview.mdc:0-0
Timestamp: 2025-09-22T00:09:59.281Z
Learning: Applies to plugin/src/main/kotlin/dev/betrix/superSmashMobsBrawl/SuperSmashMobsBrawl.kt : Keep the plugin main class at plugin/src/main/kotlin/dev/betrix/superSmashMobsBrawl/SuperSmashMobsBrawl.kt
Applied to files:
plugin/package.json
📚 Learning: 2025-09-22T00:08:49.174Z
Learnt from: CR
PR: BetrixDev/ssm-brawl#0
File: .cursor/rules/convex-rules.mdc:0-0
Timestamp: 2025-09-22T00:08:49.174Z
Learning: Applies to package.json : Add types/node to package.json when using Node.js built-in modules
Applied to files:
package.json
🪛 dotenv-linter (3.3.0)
.env.development.example
[warning] 4-4: [UnorderedKey] The PLUGIN_SECRET_KEY key should go before the POLAR_ACCESS_TOKEN key
(UnorderedKey)
[warning] 6-6: [EndingBlankLine] No blank line at the end of the file
(EndingBlankLine)
[warning] 6-6: [UnorderedKey] The DATABASE_URL key should go before the PLUGIN_SECRET_KEY key
(UnorderedKey)
apps/web/.env.example
[warning] 2-2: [EndingBlankLine] No blank line at the end of the file
(EndingBlankLine)
🔇 Additional comments (1)
apps/backend/package.json (1)
24-35: Remove the duplicatedotenventry.
Line 24 already declaresdotenvunderdependencies, but Line 35 repeats it indevDependencies, which forces Bun/npm to resolve it twice and bloats the lockfile. Please keep it in a single section (runtime here) and drop the duplicate.Apply this diff to clean it up:
"devDependencies": { "@types/node": "^22.18.6", "@types/pg": "^8.15.5", - "dotenv": "^17.2.2", "drizzle-kit": "^0.31.5", "tsdown": "^0.15.5", "typescript": "^5.9.2",
| BETTER_AUTH_SECRET= | ||
| BETTER_AUTH_URL= No newline at end of file |
There was a problem hiding this comment.
Restore Vite prefixes so frontend gets the auth config.
In Vite apps only variables starting with VITE_ are exposed to the browser. Renaming these keys drops the prefix, so import.meta.env.* will be undefined at runtime and the auth client cannot reach BetterAuth. Please keep the prefix when swapping to the new auth flow.
-BETTER_AUTH_SECRET=
-BETTER_AUTH_URL=
+VITE_BETTER_AUTH_SECRET=
+VITE_BETTER_AUTH_URL=📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| BETTER_AUTH_SECRET= | |
| BETTER_AUTH_URL= | |
| VITE_BETTER_AUTH_SECRET= | |
| VITE_BETTER_AUTH_URL= |
🧰 Tools
🪛 dotenv-linter (3.3.0)
[warning] 2-2: [EndingBlankLine] No blank line at the end of the file
(EndingBlankLine)
🤖 Prompt for AI Agents
In apps/web/.env.example around lines 1 to 2, the environment variable names
were changed to BETTER_AUTH_* which removes the VITE_ prefix required by Vite to
expose values to the browser; restore the VITE_ prefixes so the frontend can
access them (e.g., VITE_BETTER_AUTH_SECRET and VITE_BETTER_AUTH_URL) and update
any code or docs that reference the old names to use the VITE_... variables so
import.meta.env.* provides the auth config at runtime.
There was a problem hiding this comment.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
apps/web/.env.example(1 hunks)docker-compose.yml(1 hunks)package.json(1 hunks)plugin/scripts/run-gradle.mjs(1 hunks)turbo.json(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- plugin/scripts/run-gradle.mjs
🧰 Additional context used
📓 Path-based instructions (1)
package.json
📄 CodeRabbit inference engine (.cursor/rules/convex-rules.mdc)
Add @types/node to package.json when using Node.js built-in modules
Files:
package.json
🧠 Learnings (3)
📚 Learning: 2025-09-27T22:29:26.793Z
Learnt from: BetrixDev
PR: BetrixDev/ssm-brawl#139
File: docker-compose.yml:5-19
Timestamp: 2025-09-27T22:29:26.793Z
Learning: PostgreSQL 18 Docker image (postgres:18) is available on Docker Hub and is a valid tag for use in Docker Compose configurations.
Applied to files:
docker-compose.yml
📚 Learning: 2025-09-27T22:29:26.793Z
Learnt from: BetrixDev
PR: BetrixDev/ssm-brawl#139
File: docker-compose.yml:5-19
Timestamp: 2025-09-27T22:29:26.793Z
Learning: PostgreSQL 18 Docker image (postgres:18) is confirmed available on Docker Hub as of September 2025. It is the latest major PostgreSQL version and should be used instead of suggesting downgrades to postgres:17.
Applied to files:
docker-compose.yml
📚 Learning: 2025-09-22T00:08:49.174Z
Learnt from: CR
PR: BetrixDev/ssm-brawl#0
File: .cursor/rules/convex-rules.mdc:0-0
Timestamp: 2025-09-22T00:08:49.174Z
Learning: Applies to package.json : Add types/node to package.json when using Node.js built-in modules
Applied to files:
package.json
🪛 dotenv-linter (3.3.0)
apps/web/.env.example
[warning] 1-1: [EndingBlankLine] No blank line at the end of the file
(EndingBlankLine)
🔇 Additional comments (2)
apps/web/.env.example (1)
1-1: Restore Vite prefix for the BetterAuth URL.Vite only exposes environment variables that start with
VITE_. Dropping the prefix meansimport.meta.envwon’t surface the BetterAuth URL, so the frontend auth client will readundefinedat runtime. Please keep the prefix.-BETTER_AUTH_URL= +VITE_BETTER_AUTH_URL=docker-compose.yml (1)
32-34: Migrate container still fails env validation
apps/backend/src/lib/env.tscontinues to parse the full Better Auth/Polar/Redis schema even during migrations. Whenbun run db:migrateboots it imports that module (via the Drizzle config) and immediately throws aZodErrorbecause this service only exposesDATABASE_URL. Result: the container exits before applying migrations, sodocker compose upnever finishes. Either relax the schema for CLI usage or inject the same env defaults you provide toapi.environment: + BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET:-changeme} + BETTER_AUTH_URL: ${BETTER_AUTH_URL:-http://localhost:3000/api/auth} + POLAR_ACCESS_TOKEN: ${POLAR_ACCESS_TOKEN:-} + POLAR_SUCCESS_URL: ${POLAR_SUCCESS_URL:-http://localhost:3000/checkout/success} + POLAR_SERVER: ${POLAR_SERVER:-sandbox} + PLUGIN_SECRET_KEY: ${PLUGIN_SECRET_KEY:-changeme} + REDIS_URL: ${REDIS_URL:-redis://redis:6379/0} DATABASE_URL: "postgres://${POSTGRES_USER:-brawl}:${POSTGRES_PASSWORD:-brawl}@${POSTGRES_HOST:-postgres}:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-brawl}"
Summary by CodeRabbit
New Features
Refactor
Chores