Skip to content

Conversation

@DragonSenseiGuy
Copy link
Contributor

@DragonSenseiGuy DragonSenseiGuy commented Jan 13, 2026

Summary by CodeRabbit

  • New Features
    • Buckshot Roulette: play-with-wager UI, result modal, live stats, balance updates, and error/loading states
    • Hour Goal: adjustable goal (50–150) with slider, save feedback, and progress displays honoring the saved goal
    • Commerce & rewards: shop and transactions support, gift codes, and backend APIs powering purchases and game playplay

✏️ Tip: You can customize this high-level summary in your review settings.

NeonGamerBot-QK and others added 3 commits January 5, 2026 19:59

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
@DragonSenseiGuy DragonSenseiGuy requested a review from rom a team as a code owner January 13, 2026 03:35
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 13, 2026

📝 Walkthrough

Walkthrough

Adds a Buckshot Roulette game and persistent hour-goal feature, including frontend UI, new API endpoints, a GameModule/service/controller, and a large Prisma schema migration introducing shop, transactions, gift codes, and related indexes and constraints.

Changes

Cohort / File(s) Summary
Frontend - Hour Goal Persistence
lark-ui/src/lib/ProgressBar.svelte, lark-ui/src/routes/app/settings/+page.svelte
ProgressBar and settings now use a persistent goalHours (default 50) read from localStorage; calculations and UI thresholds replaced with goalHours. Settings page adds slider (50–150), save flow, and visual feedback.
Frontend - Buckshot Roulette Game
lark-ui/src/lib/auth.ts, lark-ui/src/routes/app/roulette/+page.svelte
Adds GameResult/GameStats types and playBuckshotRoulette/getGameStats client helpers. New roulette page implements wager UI, rules, live stats, modal results, balance/stats refresh, and error/loading handling.
Backend - Game Module & Controllerller
owl-api/src/app.module.ts, owl-api/src/game/game.module.ts, owl-api/src/game/game.controller.ts, owl-api/src/game/game.service.ts
Registers GameModule; adds controller endpoints POST /api/game/buckshot-roulette and GET /api/game/buckshot-roulette/stats. Service enforces balance checks, win/loss logic, records transactions, and aggregates game stats.
Backend - Configuration
owl-api/src/datadog.config.ts
Loads dotenv in non-production before tracer init to pick up environment variables from ../../.env.
Database - Prisma Migration
owl-api/prisma/migrations/.../migration.sql
Adds shop_items, shop_item_variants, transactions, gift_codes, slack_link_tokens, global_settings; alters users, projects, submissions, users_airtable (many TEXT conversions, new boolean flags); adds indexes, unique constraints, and foreign keys linking shop/transactions to users and items.

Sequence Diagram(s)

Loading
sequenceDiagram
    participant Client as Browser/Frontend
    participant Controller as GameController
    participant Service as GameService
    participant Shop as ShopService
    participant Prisma as Database

    Client->>Controller: POST /api/game/buckshot-roulette
    activate Controller
    Controller->>Service: playBuckshotRoulette(userId)
    activate Service
    Service->>Prisma: Query user balance & game item
    Prisma-->>Service: balance & item
    alt Insufficient balance
        Service-->>Controller: throw BadRequest
    else Sufficient balance
        Service->>Service: Determine win/loss, compute wager & payout
        Service->>Prisma: Create transaction record
        Prisma-->>Service: Transaction saved
        Service->>Shop: Request updated balance
        Shop->>Prisma: Query balance
        Prisma-->>Shop: New balance
        Shop-->>Service: New balance
        Service-->>Controller: return GameResult
    end
    deactivate Service
    Controller-->>Client: 200 OK + GameResult
    deactivate Controller

    Client->>Controller: GET /api/game/buckshot-roulette/stats
    activate Controller
    Controller->>Service: getGameStats(userId)
    activate Service
    Service->>Prisma: Aggregate transactions
    Prisma-->>Service: GameStats
    Service-->>Controller: GameStats
    deactivate Service
    Controller-->>Client: 200 OK + GameStats
    deactivate Controller
-->>Controller: GameStats
    deactivate Service
    Controller-->>Client: 200 OK + GameStats
    deactivate Controller
 GameStats
    deactivate Controller

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • techpixel
  • LeafdTK

"I thumped a drum, I spun a wheel,
I hopped on code with nimble zeal,,
Goals saved snug in burrowed night,,
Shop bells ring and coins take flight,,
A rabbit cheers — play on, delight!" 🐇🎲�

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'add hour goals' is vague and does not clearly convey the scope of changes, which includes a buckshot roulette game feature, database migrations, API endpoints, and multiple UI updates beyond just hour goals. Consider a more descriptive title that captures the primary changes, such as 'Add hour goals and buckshot roulette game feature' or break into smaller, more focused PRs.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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 and usage tips.

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🤖 Fix all issues with AI agents
In @lark-ui/src/lib/ProgressBar.svelte:
- Around line 15-18: The code reads savedGoal from localStorage and sets
goalHours = parseInt(savedGoal, 10) without validating, which can produce NaN,
0, or negative values and break percentage math; update the logic in
ProgressBar.svelte to parse and validate savedGoal (use parseInt(savedGoal,
10)), then check Number.isFinite(parsed) and parsed > 0 before assigning to
goalHours, otherwise keep the existing default goalHours; additionally ensure
any percentage calculations using goalHours guard against division by zero/NaN
by using a safe denominator (e.g., fallback to default goalHours) so progress
rendering never divides by zero.

In @lark-ui/src/routes/app/roulette/+page.svelte:
- Around line 87-103: The UI text is inconsistent: the 

says "50/50 gamble" but the rules block's rule span currently reads "40/60 odds"; update the rule span showing odds to "50/50 odds" so it matches the backend WIN_PROBABILITY = 0.5 and the

text. In @owl-api/prisma/migrations/20260113032356_migration/migration.sql: - Around line 60-73: Add a unique constraint/index for the shop_items.name column so names cannot be duplicated and upserts in GameService.findOrCreateGameItem() are safe; update the migration that creates the "shop_items" table to include a unique index or constraint on "name" (e.g., create unique index "shop_items_name_key" on "shop_items"("name") or alter the table to add UNIQUE(name)), then re-run or add a follow-up migration so the database enforces uniqueness. - Around line 131-136: Remove the redundant non-unique indexes: delete the CREATE INDEX statements for "slack_link_tokens_token_idx" on table slack_link_tokens and for "gift_codes_code_idx" on table gift_codes because the UNIQUE indexes "slack_link_tokens_token_key" and "gift_codes_code_key" already provide indexing on those columns; ensure only the UNIQUE index statements remain and update the migration SQL to remove the duplicate CREATE INDEX lines. - Around line 28-30: The migration sets "role" and "onboard_complete" to NOT NULL without backfilling existing NULLs; add a backfill step before changing the constraints by executing UPDATE "users" SET "role" = 'user' WHERE "role" IS NULL and UPDATE "users" SET "onboard_complete" = false WHERE "onboard_complete" IS NULL, or alternately add ALTER COLUMN ... SET DEFAULT ('user' / false) then ALTER COLUMN ... SET NOT NULL for the "role" and "onboard_complete" columns to ensure no NULL values exist when the NOT NULL constraint is applied. - Around line 41-45: The migration drops the "users_airtable" primary key constraint without adding a replacement, which will leave the table without a primary key; modify the migration so you either preserve the existing primary key or explicitly set "email" as the new primary key: either remove the DROP CONSTRAINT for "users_airtable_pkey" (keeping the existing PK) or follow the DROP with an ADD PRIMARY KEY ("email") statement (and ensure "email" is NOT NULL and unique beforehand); update the ALTER TABLE block for "users_airtable" accordingly so the table always has a primary key after the migration. In @owl-api/src/game/game.service.ts: - Around line 59-60: Update the incorrect "50/50" text to reflect the actual 40/60 odds wherever it appears: change the inline comment above the win calculation that reads "Determine win/loss with 50/50 odds" to indicate 40/60 (or reference GAME_CONFIG.WIN_PROBABILITY) near the line with const won = Math.random() < GAME_CONFIG.WIN_PROBABILITY, and update the shop item description string in findOrCreateGameItem that currently says "50/50 odds" to state the correct "40/60 odds" (or mention the WIN_PROBABILITY value) so comments and user-facing text match the implemented probability. - Around line 45-78: The playBuckshotRoulette flow currently reads the user balance then later creates a transaction, allowing a race where concurrent calls pass the balance check; fix by performing the balance check, item lookup (findOrCreateGameItem) and creation of the transaction atomically inside a database transaction with row-level locking so no concurrent request can reuse the same balance: use Prisma's transactional API (prisma.$transaction or prisma.$executeRaw / interactiveTransaction) to lock the user's row (SELECT ... FOR UPDATE / equivalent) before re-reading balance, compute wager/transactionCost/payout, then create the prisma.transaction record within the same transaction and commit; ensure all DB reads/writes in playBuckshotRoulette (including the findOrCreateGameItem logic if it touches DB) happen inside that transaction to prevent races. - Around line 137-157: findOrCreateGameItem has a race condition where concurrent calls can both not find the item and create duplicates; change the implementation to use a database upsert (or create with unique constraint handling) on shopItem by name (BUCKSHOT_ROULETTE_ITEM_NAME) so the operation is atomic, and ensure the shop_items.name column has a unique constraint to prevent duplicates. event duplicates. he shop_items.name column has a unique constraint to prevent duplicates.

says "50/50 gamble" but the rules block's rule span currently reads "40/60 odds"; update the rule span showing odds to "50/50 odds" so it matches the backend WIN_PROBABILITY = 0.5 and the

text. In @owl-api/prisma/migrations/20260113032356_migration/migration.sql: - Around line 60-73: Add a unique constraint/index for the shop_items.name column so names cannot be duplicated and upserts in GameService.findOrCreateGameItem() are safe; update the migration that creates the "shop_items" table to include a unique index or constraint on "name" (e.g., create unique index "shop_items_name_key" on "shop_items"("name") or alter the table to add UNIQUE(name)), then re-run or add a follow-up migration so the database enforces uniqueness. - Around line 131-136: Remove the redundant non-unique indexes: delete the CREATE INDEX statements for "slack_link_tokens_token_idx" on table slack_link_tokens and for "gift_codes_code_idx" on table gift_codes because the UNIQUE indexes "slack_link_tokens_token_key" and "gift_codes_code_key" already provide indexing on those columns; ensure only the UNIQUE index statements remain and update the migration SQL to remove the duplicate CREATE INDEX lines. - Around line 28-30: The migration sets "role" and "onboard_complete" to NOT NULL without backfilling existing NULLs; add a backfill step before changing the constraints by executing UPDATE "users" SET "role" = 'user' WHERE "role" IS NULL and UPDATE "users" SET "onboard_complete" = false WHERE "onboard_complete" IS NULL, or alternately add ALTER COLUMN ... SET DEFAULT ('user' / false) then ALTER COLUMN ... SET NOT NULL for the "role" and "onboard_complete" columns to ensure no NULL values exist when the NOT NULL constraint is applied. - Around line 41-45: The migration drops the "users_airtable" primary key constraint without adding a replacement, which will leave the table without a primary key; modify the migration so you either preserve the existing primary key or explicitly set "email" as the new primary key: either remove the DROP CONSTRAINT for "users_airtable_pkey" (keeping the existing PK) or follow the DROP with an ADD PRIMARY KEY ("email") statement (and ensure "email" is NOT NULL and unique beforehand); update the ALTER TABLE block for "users_airtable" accordingly so the table always has a primary key after the migration. In @owl-api/src/game/game.service.ts: - Around line 59-60: Update the incorrect "50/50" text to reflect the actual 40/60 odds wherever it appears: change the inline comment above the win calculation that reads "Determine win/loss with 50/50 odds" to indicate 40/60 (or reference GAME_CONFIG.WIN_PROBABILITY) near the line with const won = Math.random() < GAME_CONFIG.WIN_PROBABILITY, and update the shop item description string in findOrCreateGameItem that currently says "50/50 odds" to state the correct "40/60 odds" (or mention the WIN_PROBABILITY value) so comments and user-facing text match the implemented probability. - Around line 45-78: The playBuckshotRoulette flow currently reads the user balance then later creates a transaction, allowing a race where concurrent calls pass the balance check; fix by performing the balance check, item lookup (findOrCreateGameItem) and creation of the transaction atomically inside a database transaction with row-level locking so no concurrent request can reuse the same balance: use Prisma's transactional API (prisma.$transaction or prisma.$executeRaw / interactiveTransaction) to lock the user's row (SELECT ... FOR UPDATE / equivalent) before re-reading balance, compute wager/transactionCost/payout, then create the prisma.transaction record within the same transaction and commit; ensure all DB reads/writes in playBuckshotRoulette (including the findOrCreateGameItem logic if it touches DB) happen inside that transaction to prevent races. - Around line 137-157: findOrCreateGameItem has a race condition where concurrent calls can both not find the item and create duplicates; change the implementation to use a database upsert (or create with unique constraint handling) on shopItem by name (BUCKSHOT_ROULETTE_ITEM_NAME) so the operation is atomic, and ensure the shop_items.name column has a unique constraint to prevent duplicates.condition where concurrent calls can both not find the item and create duplicates; change the implementation to use a database upsert (or create with unique constraint handling) on shopItem by name (BUCKSHOT_ROULETTE_ITEM_NAME) so the operation is atomic, and ensure the shop_items.name column has a unique constraint to prevent duplicates.the shop_items.name column has a unique constraint to prevent duplicates." tabindex="0" role="button">

🧹 Nitpick comments (8)
lark-ui/src/routes/app/settings/+page.svelte (3)

18-20: Minor: Missing semicolon on line 19.

For consistency with the rest of the file, add a semicolon after $state(false) on line 19.

-    let goalUpdating = $state(false)

+    let goalUpdating = $state(false);

32-35: Consider validating the parsed goal value.

If localStorage contains a corrupted or out-of-range value, parseInt could return NaN or a value outside the slider bounds (50-150). Consider adding validation:

             const savedGoal = localStorage.getItem('hourGoal');
             if (savedGoal) {

-                hourGoal = parseInt(savedGoal, 10);

+                const parsed = parseInt(savedGoal, 10);

+                if (!isNaN(parsed) && parsed >= 50 && parsed <= 150) {p; parsed <= 150) {

+                    hourGoal = parsed;

+                }
             }}

63-71: The "Saving..." state will never be visible.

localStorage.setItem is synchronous, so goalUpdating is set to true and immediately back to false within the same event loop tick. The button will never show "Saving..." to the user.

If the loading state is intentional for UX consistency, consider keeping goalUpdating but removing its use in the button, or simply remove the goalUpdating state entirely since it serves no practical purpose here.

lark-ui/src/routes/app/roulette/+page.svelte (1)

46-46: Consider: hardcoded balance threshold.

The 0.1 threshold is hardcoded here and on line 118/123. The backend uses GAME_CONFIG.MIN_BALANCE_TO_PLAY which could differ. If the backend minimum changes, the frontend check would be out of sync, potentially allowing users to attempt plays that will fail server-side.

This is low-risk but worth noting for future maintainability.

owl-api/src/game/game.controller.ts (1)

17-20: Add rate limiting to prevent rapid gambling exploitation.

This endpoint allows wagering ALL unspent hours with no cooldown. A user could rapidly hit this endpoint to either exploit favorable outcomes or accidentally lose everything. Consider adding a stricter rate limit via @Throttle() decorator or implementing a cooldown period in the service.

Example rate limit decorator
+import { Throttle } from '@nestjs/throttler';

+
 @Post('buckshot-roulette')

+@Throttle({ default: { limit: 1, ttl: 60000 } }) // 1 request per minute
 async playBuckshotRoulette(@Req() req: Request) {{
owl-api/src/game/game.service.ts (2)

60-60: Consider using cryptographically secure randomness for gambling outcomes.

Math.random() is not cryptographically secure. While this is server-side code (reducing external exploitation risk), for a gambling feature, using crypto.randomInt() or similar would be more appropriate.

Example using Node.js crypto
import { randomInt } from 'crypto';


// Replace Math.random() < 0.4 with:th:

const won = randomInt(100)  40; // 40% win probability

114-130: Consider database-level aggregation for better performance.

Fetching all transactions and filtering in memory (lines 121-123) won't scale well for users with many games. Database aggregation would be more efficient.

Example using Prisma aggregate
const [stats] = await this.prisma.$queryRaw[{wins: bigint, losses: bigint, net: number}]>gt;`

  SELECT 

    COUNT(*) FILTER (WHERE cost < 0) as wins,ns,

    COUNT(*) FILTER (WHERE cost > 0) as losses,es,

    -SUM(cost) as net

  FROM transactions 

  WHERE user_id = ${userId} AND item_id = ${gameItem.itemId}

`;
owl-api/src/game/game.module.ts (1)

8-13: Import ShopModule instead of providing ShopService directly.

ShopModule already provides ShopService, so providing it again here creates unnecessary duplication. Import ShopModule and remove ShopService from the providers array to reuse the existing service instance.

Regarding PrismaService: While providing it directly in each module is not ideal for singleton behavior, this pattern is used consistently throughout the codebase. Consider addressing this separately across all modules if singleton database connections are required.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e6dc78a and 0ae31d1.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (10)
  • lark-ui/src/lib/ProgressBar.svelte
  • lark-ui/src/lib/auth.ts
  • lark-ui/src/routes/app/roulette/+page.svelte
  • lark-ui/src/routes/app/settings/+page.svelte
  • owl-api/prisma/migrations/20260113032356_migration/migration.sql
  • owl-api/src/app.module.ts
  • owl-api/src/datadog.config.ts
  • owl-api/src/game/game.controller.ts
  • owl-api/src/game/game.module.ts
  • owl-api/src/game/game.service.ts
🧰 Additional context used
🧬 Code graph analysis (3)
owl-api/src/game/game.module.ts (1)
owl-api/src/app.module.ts (1)
  • Module (18-45)
lark-ui/src/lib/auth.ts (2)
owl-api/src/game/game.service.ts (3)
  • GameResult (23-29)
  • playBuckshotRoulette (45-92)
  • getGameStats (100-131)
owl-api/src/game/game.controller.ts (2)
  • playBuckshotRoulette (18-20)
  • getGameStats (29-31)
owl-api/src/game/game.service.ts (1)
lark-ui/src/lib/auth.ts (1)
  • GameResult (742-748)
🔇 Additional comments (15)
lark-ui/src/lib/ProgressBar.svelte (3)

25-32: LGTM!

The clamping logic correctly caps hours at the goal, and the percentage calculations are straightforward. This will work correctly once goalHours validation is in place.


35-38: LGTM!

Derived values are correctly computed from the reactive state.


74-83: LGTM!

The conditional rendering logic correctly uses goalHours to determine when to show the pending and remaining hour indicators.

lark-ui/src/routes/app/settings/+page.svelte (2)

129-152: LGTM!

The Hour Goal UI section is well-structured with clear labels, appropriate slider range, and consistent styling with the rest of the settings page.


236-271: LGTM!

Good cross-browser slider styling with both WebKit and Firefox thumb styles. The gradient-based track fill tied to --value is a clean approach.

lark-ui/src/lib/auth.ts (3)

742-755: LGTM!

The GameResult and GameStats types correctly mirror the backend interfaces defined in owl-api/src/game/game.service.ts.


761-775: LGTM!

The function follows the established patterns in this file with proper credentials, error handling, and return structure.


780-791: LGTM!

Clean implementation following the same pattern as other authenticated GET functions in this module.

lark-ui/src/routes/app/roulette/+page.svelte (4)

24-34: LGTM!

Authentication check and initial data loading are properly handled with appropriate redirect for unauthenticated users.


45-63: LGTM!

The play handler properly manages state, prevents concurrent plays, and handles both success and error cases appropriately.


159-191: LGTM!

The result modal is well-designed with clear win/loss differentiation, appropriate feedback messages, and good UX with overlay click-to-close functionality.


193-270: LGTM!

Clean, well-organized CSS with appropriate responsive units and consistent theming. The fixed balance display and pseudo-element title effect add nice visual polish.

owl-api/src/datadog.config.ts (1)

1-6: LGTM!

The dotenv configuration is correctly placed before the tracer import, ensuring environment variables are loaded before Datadog initialization. The conditional check for non-production environments is appropriate.

owl-api/src/app.module.ts (1)

16-16: LGTM!

The GameModule is correctly imported and registered in the root AppModule.

Also applies to: 35-36

owl-api/src/game/game.controller.ts (1)

18-19: Type augmentation for req.user is already properly configured.

The Express Request interface is correctly augmented in owl-api/src/types/express.d.ts with user?: User. No action needed—the type safety concern is already addressed.

Likely an incorrect or invalid review comment.

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>om>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
lark-ui/src/lib/ProgressBar.svelte (1)

12-21: Consider using parseFloat and adding an upper bound check.

The current validation is solid (checking for NaN and positive values), but two potential improvements:

  1. parseInt truncates decimals (e.g., "50.5" becomes 50), which is inconsistent with the decimal hour values used elsewhere in this component.
  2. No upper bound—a maliciously large value in localStorage could cause UI issues.
♻️ Suggested improvement
     const savedGoal = localStorage.getItem('hourGoal');
     if (savedGoal) {

-        const parsed = parseInt(savedGoal, 10);

-        if (!Number.isNaN(parsed) && parsed > 0) {d > 0) {

+        const parsed = parseFloat(savedGoal);

+        if (!Number.isNaN(parsed) && parsed > 0 && parsed <= 1000) {; parsed <= 1000) {
             goalHours = parsed;
         }
     }  }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0ae31d1 and f0f5996.

📒 Files selected for processing (1)
  • lark-ui/src/lib/ProgressBar.svelte
🔇 Additional comments (3)
lark-ui/src/lib/ProgressBar.svelte (3)

28-35: LGTM!

The clamping logic and percentage calculations correctly use the dynamic goalHours value. The approach of capping both approvedHours and totalHours at the goal ensures percentages stay within valid bounds.


38-41: LGTM!

Good use of Svelte 5's $derived rune for reactive computed values. These will correctly update if goalHours or totalHours change.


77-93: LGTM!

The conditional rendering logic correctly uses goalHours to determine visibility of the pending and remaining hour segments. The conditions properly handle edge cases where approved hours meet or exceed the goal.

@techpixel
Copy link
Member

this includes commits that were removed earlier (commits from #84 were removed)

Copy link
Member

@techpixel techpixel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove commits from #84

Copy link
Member

@techpixel techpixel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@techpixel techpixel self-requested a review January 15, 2026 19:36
@techpixel techpixel merged commit mit 67226fc into hackclub:main Jan 15, 2026
1 check passed
@techpixel
Copy link
Member

fyi this will take time to update on the frontend

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.

None yet

3 participants