Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
253fde3
initial commit, set up the the directory, and integrate with the repo
AryanGodara Apr 23, 2025
16b3af2
working hono server with kysely and bun:sqlite dummy db, with API end…
AryanGodara Apr 23, 2025
0a2daf1
add and integrate leaderboard-frontend, forked from demo-react, and s…
AryanGodara Apr 23, 2025
b3bae3f
add tables and schema for swarms, in progress [skip ci]
AryanGodara Apr 23, 2025
0eee30a
update app names for frontend and backend [skip ci]
AryanGodara Apr 24, 2025
ed02bfc
remove unused deps from frontend, temp update bg[skip ci]
AryanGodara Apr 24, 2025
d1d92ba
fix naming of db types to be more consistent, minor formatting fixes …
AryanGodara Apr 24, 2025
71319e1
add hono-sessions [skip ci]
AryanGodara Apr 24, 2025
0ed33dc
add stub components for leaderboards [skip ci]
AryanGodara Apr 24, 2025
efdd304
more refactoring of the server, trying to add zod validator, and sett…
AryanGodara Apr 24, 2025
72983aa
more refactoring of the server, lots of changes, add migrations setup…
AryanGodara Apr 25, 2025
fa8a9f0
refactor repositories [skip ci]
AryanGodara Apr 25, 2025
45360a7
completed users endpoint, tested locally [skip ci]
AryanGodara Apr 25, 2025
a6f1d7c
rename some files, add example CURL commands, add DELETE endpoint, in…
AryanGodara Apr 25, 2025
1e0b3f8
finalize delete endpoint and userSchemas [skip ci]
AryanGodara Apr 25, 2025
1234d6b
add guilds and users endpoints [skip ci]
AryanGodara Apr 25, 2025
07ea6b9
guilds API fixing in progress [skip ci]
AryanGodara Apr 25, 2025
2c039b3
add game schema [skip ci]
AryanGodara Apr 28, 2025
cffeaff
complete schema, tables, API, and migrations file [skip ci]
AryanGodara Apr 28, 2025
6750ee5
completed User and Wallet Repository [skip ci]
AryanGodara Apr 28, 2025
cc3dcdb
all the validation schemas and repository functions, pending URL rout…
AryanGodara Apr 28, 2025
62b21f1
all the validation schemas and repository functions, pending URL rout…
AryanGodara Apr 28, 2025
cbcd0f2
add users and guilds URL routes [skip ci]
AryanGodara Apr 28, 2025
22c968b
add leaderboard routes, backend complete, review pending
AryanGodara Apr 28, 2025
9e6a470
do chaining of routes, when exporting subrouters [skip ci]
AryanGodara Apr 29, 2025
bf35989
export AppType for rpc, fix bugs, server running, tested some endpoin…
AryanGodara Apr 29, 2025
8e6986e
remove tailwind from leaderboard-frontend, keep codebase minimal[skip…
AryanGodara Apr 29, 2025
e1e1fbc
user creation, display and update with profile page
AryanGodara Apr 29, 2025
4dca9fc
in progress, guilds page [skip ci]
AryanGodara Apr 29, 2025
cb3abf2
partially done, guilds page [skip ci]
AryanGodara Apr 29, 2025
8fff82b
comlete guilds functionality [skip ci]
AryanGodara Apr 29, 2025
f9fbe88
boilerplate for games page [skip ci]
AryanGodara Apr 29, 2025
54a7bf2
remove frontend code, reserve for another PR [skip ci]
AryanGodara Apr 30, 2025
a36ec64
remove leaderboard-frontend from bun.lock [skip ci]
AryanGodara Apr 30, 2025
319afda
update game routes, add more routes [skip ci]
AryanGodara Apr 30, 2025
782c3f4
update game score routes [skip ci]
AryanGodara Apr 30, 2025
149af51
rebase and update bun.lock
AryanGodara May 2, 2025
cfb1e42
refactored hono app, added docs endpoints stub, another minor changes…
AryanGodara May 5, 2025
c56f6b0
mid refactor, enable swagger openAPI docs in user routes [skip ci]
AryanGodara May 5, 2025
f556c21
mid refactor, refactoring schemas for user routes [skip ci]
AryanGodara May 5, 2025
3aa8dbf
complete user routes refactoring [skip ci]
AryanGodara May 5, 2025
1470f6a
mid refactor: refactoring guild routes[skip ci]
AryanGodara May 6, 2025
795f19a
refactor guilds routes [skip ci]
AryanGodara May 6, 2025
d786763
refactor leaderboard and game routes
AryanGodara May 6, 2025
d7e90b3
more refactors [skip ci]
AryanGodara May 6, 2025
7521308
update deps [skip ci]
AryanGodara May 6, 2025
05d3a87
refactor: update ID params from number to string and remove redundant…
AryanGodara May 8, 2025
d3335f9
fix: add missing timestamp fields when creating users, games, guilds …
AryanGodara May 8, 2025
cf47c63
feat: implement environment variable validation with zod schema [skip…
AryanGodara May 8, 2025
30ef8a8
remove redundant apispec.md file [skip ci]
AryanGodara May 8, 2025
ab58a13
fix: parse numeric query params and game IDs to integers in leaderboa…
AryanGodara May 13, 2025
74cfd9a
chore: fix bun.lock conflicts after rebase[skip ci]
AryanGodara May 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@ BACKEND_ONLY_PKGS := packages/txm,apps/randomness,apps/faucet
# packages needed to build the backend services
BACKEND_PKGS := support/common,$(BACKEND_ONLY_PKGS)

# all the swarm leaderboard packages
LEADERBOARD_PKGS := apps/leaderboard-backend

# all typescript packages, excluding docs
TS_PKGS := $(ACCOUNT_PKGS),$(DEMOS_PKGS),${BACKEND_ONLY_PKGS}
TS_PKGS := $(ACCOUNT_PKGS),$(DEMOS_PKGS),${BACKEND_ONLY_PKGS},apps/leaderboard-backend

# all packages that have a package.json
NPM_PKGS := $(TS_PKGS),apps/docs,contracts,support/configs
Expand Down Expand Up @@ -169,6 +172,20 @@ submitter.prod: submitter.build
cd apps/submitter && make prod;
.PHONY: submitter.prod

leaderboard-backend.dev: setup.ts shared.dev
cd apps/leaderboard-backend && make migrate;
cd apps/leaderboard-backend && make dev;
.PHONY: leaderboard-backend.dev

leaderboard-backend.build: shared.build
cd apps/leaderboard-backend && make build;
.PHONY: leaderboard-backend.build

leaderboard-backend.prod: leaderboard-backend.build
cd apps/leaderboard-backend && make migrate;
cd apps/leaderboard-backend && make prod;
.PHONY: leaderboard-backend.prod

iframe.dev: shared.dev sdk.dev ## Serves the wallet iframe at http://localhost:5160
cd apps/iframe && make dev
.PHONY: iframe.dev
Expand Down
3 changes: 3 additions & 0 deletions apps/leaderboard-backend/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
PORT=4545
LEADERBOARD_DB_URL="leaderboard-backend.sqlite"
DATABASE_MIGRATE_DIR="migrations"
34 changes: 34 additions & 0 deletions apps/leaderboard-backend/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
include ../../makefiles/lib.mk
include ../../makefiles/bundling.mk
include ../../makefiles/formatting.mk
include ../../makefiles/help.mk

# include .env file and export its env vars
# (-include to ignore error if it does not exist)
-include .env

dev: node_modules reset-dev
@NODE_ENV=development bun --bun --hot src/index.ts;
.PHONY: dev

prod: build ## Start the local dev server for development
@NODE_ENV=production bun --bun run build/index.es.js;
.PHONY: prod

# Migration targets for leaderboard-backend (using Bun)

migrate: ## Runs latest migrations
@echo "Running latest migrations..."
@bun run src/db/migrate.ts
.PHONY: migrate

migrate-fresh: ## Deletes database and starts fresh
@if [ -f ${LEADERBOARD_DB_URL} ]; then rm ${LEADERBOARD_DB_URL}; fi;
@echo "Running latest migrations on fresh DB..."
@bun run src/db/migrate.ts
.PHONY: migrate-fresh

# NOTE: migrate-rollback is not implemented in migrate.ts; add support if needed
migrate-rollback: ## Rollsback latest migrations (not implemented)
@echo "Rollback not implemented in migrate.ts. Implement if needed."
.PHONY: migrate-rollback
11 changes: 11 additions & 0 deletions apps/leaderboard-backend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# leaderboard-backend

## Quickstart

- `make setup` — Install dependencies
- `make dev` — Start the dev server with hot reload
- `make build` — Build the service for production
- `make prod` — Run the built app in production mode
- `make migrate` — Run database migrations (customize as needed)
- `make migrate-fresh` — Reset and re-run migrations
- `make migrate-rollback` — Roll back the last migration
4 changes: 4 additions & 0 deletions apps/leaderboard-backend/biome.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"$schema": "../../node_modules/@biomejs/biome/configuration_schema.json",
"extends": ["../../support/configs/biome.jsonc"]
}
8 changes: 8 additions & 0 deletions apps/leaderboard-backend/build.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { defineConfig } from "@happy.tech/happybuild"

export default defineConfig({
bunConfig: {
target: "bun",
minify: false,
},
})
36 changes: 36 additions & 0 deletions apps/leaderboard-backend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"version": "0.1.0",
"name": "@happy.tech/leaderboard-backend",
"private": true,
"main": "./dist/index.es.js",
"module": "./dist/index.es.js",
"type": "module",
"types": "./dist/index.es.d.ts",
"exports": {
".": {
"types": "./dist/index.es.d.ts",
"default": "./dist/index.es.js"
}
},
"devDependencies": {
"@happy.tech/common": "workspace:0.1.0",
"@happy.tech/configs": "workspace:0.1.0",
"@happy.tech/happybuild": "workspace:0.1.1",
"@types/bun": "latest"
},
"peerDependencies": {
"typescript": "^5.0.0"
},
"dependencies": {
"@hono/zod-openapi": "^0.19.6",
"@hono/zod-validator": "^0.4.3",
"@scalar/hono-api-reference": "^0.8.8",
"hono": "^4.7.2",
"hono-openapi": "^0.4.4",
"kysely": "^0.27.5",
"kysely-bun-sqlite": "^0.3.2",
"viem": "^2.21.53",
"zod": "^3.23.8",
"zod-openapi": "^4.2.3"
}
}
Binary file added apps/leaderboard-backend/public/gameicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions apps/leaderboard-backend/src/db/driver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Database as BunDatabase } from "bun:sqlite"
import { Kysely } from "kysely"
import { BunSqliteDialect } from "kysely-bun-sqlite"
import type { Database } from "./types"

import { env } from "../env"

const dbPath = env.LEADERBOARD_DB_URL || ":memory:"

export const db = new Kysely<Database>({
dialect: new BunSqliteDialect({ database: new BunDatabase(dbPath) }),
// Add plugins here if needed
})
37 changes: 37 additions & 0 deletions apps/leaderboard-backend/src/db/migrate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { type Migration, type MigrationProvider, Migrator } from "kysely"
import { db } from "./driver"
import { migrations } from "./migrations"

class ObjectMigrationProvider implements MigrationProvider {
constructor(private migrations: Record<string, Migration>) {}
async getMigrations(): Promise<Record<string, Migration>> {
return this.migrations
}
}

const migrator = new Migrator({
db,
provider: new ObjectMigrationProvider(migrations),
})

async function migrateToLatest() {
const { error, results } = await migrator.migrateToLatest()

results?.forEach((it) => {
if (it.status === "Success") {
console.log(`migration "${it.migrationName}" was executed successfully`)
} else if (it.status === "Error") {
console.error(`failed to execute migration "${it.migrationName}"`)
}
})

if (error) {
console.error("failed to migrate")
console.error(error)
process.exit(1)
}

await db.destroy()
}

migrateToLatest()
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import type { Kysely } from "kysely"
import { sql } from "kysely"

// biome-ignore lint/suspicious/noExplicitAny: `any` is required here since migrations should be frozen in time. alternatively, keep a "snapshot" db interface.
export async function up(db: Kysely<any>): Promise<void> {
// Users table
await db.schema
.createTable("users")
.addColumn("id", "integer", (col) => col.primaryKey().autoIncrement())
.addColumn("primary_wallet", "text", (col) => col.notNull().unique())
.addColumn("username", "text", (col) => col.notNull().unique())
.addColumn("created_at", "text", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`).notNull())
.addColumn("updated_at", "text", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`).notNull())
.execute()

// User wallets table (multiple wallets per user)
await db.schema
.createTable("user_wallets")
.addColumn("id", "integer", (col) => col.primaryKey().autoIncrement())
.addColumn("user_id", "integer", (col) => col.notNull())
.addColumn("wallet_address", "text", (col) => col.notNull().unique())
.addColumn("is_primary", "boolean", (col) => col.notNull().defaultTo(false))
.addColumn("created_at", "text", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`).notNull())
.addForeignKeyConstraint("user_wallets_user_id_fk", ["user_id"], "users", ["id"])
.execute()

// Guilds table
await db.schema
.createTable("guilds")
.addColumn("id", "integer", (col) => col.primaryKey().autoIncrement())
.addColumn("name", "text", (col) => col.notNull().unique())
.addColumn("icon_url", "text", (col) => col)
.addColumn("creator_id", "integer", (col) => col.notNull())
.addColumn("created_at", "text", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`).notNull())
.addColumn("updated_at", "text", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`).notNull())
.addForeignKeyConstraint("guilds_creator_id_fk", ["creator_id"], "users", ["id"])
.execute()

// Guild members table (many-to-many users <-> guilds)
await db.schema
.createTable("guild_members")
.addColumn("id", "integer", (col) => col.primaryKey().autoIncrement())
.addColumn("guild_id", "integer", (col) => col.notNull())
.addColumn("user_id", "integer", (col) => col.notNull())
.addColumn("is_admin", "boolean", (col) => col.notNull().defaultTo(false))
.addColumn("joined_at", "text", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`).notNull())
.addForeignKeyConstraint("guild_members_guild_id_fk", ["guild_id"], "guilds", ["id"])
.addForeignKeyConstraint("guild_members_user_id_fk", ["user_id"], "users", ["id"])
.addUniqueConstraint("guild_members_unique", ["guild_id", "user_id"])
.execute()

// Games table
await db.schema
.createTable("games")
.addColumn("id", "integer", (col) => col.primaryKey().autoIncrement())
.addColumn("name", "text", (col) => col.notNull().unique())
.addColumn("icon_url", "text", (col) => col)
.addColumn("description", "text", (col) => col)
.addColumn("admin_id", "integer", (col) => col.notNull())
.addColumn("created_at", "text", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`).notNull())
.addColumn("updated_at", "text", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`).notNull())
.addForeignKeyConstraint("games_admin_id_fk", ["admin_id"], "users", ["id"])
.execute()

// User game scores table
await db.schema
.createTable("user_game_scores")
.addColumn("id", "integer", (col) => col.primaryKey().autoIncrement())
.addColumn("user_id", "integer", (col) => col.notNull())
.addColumn("game_id", "integer", (col) => col.notNull())
.addColumn("score", "integer", (col) => col.notNull())
.addColumn("metadata", "text", (col) => col)
.addColumn("created_at", "text", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`).notNull())
.addColumn("updated_at", "text", (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`).notNull())
.addForeignKeyConstraint("user_game_scores_user_id_fk", ["user_id"], "users", ["id"])
.addForeignKeyConstraint("user_game_scores_game_id_fk", ["game_id"], "games", ["id"])
.addUniqueConstraint("user_game_scores_unique", ["user_id", "game_id"])
.execute()
}

// biome-ignore lint/suspicious/noExplicitAny: `any` is required here since migrations should be frozen in time. alternatively, keep a "snapshot" db interface.
export async function down(db: Kysely<any>): Promise<void> {
await db.schema.dropTable("user_game_scores").execute()
await db.schema.dropTable("games").execute()
await db.schema.dropTable("guild_members").execute()
await db.schema.dropTable("guilds").execute()
await db.schema.dropTable("user_wallets").execute()
await db.schema.dropTable("users").execute()
}
5 changes: 5 additions & 0 deletions apps/leaderboard-backend/src/db/migrations/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as M_1745907000000_create_all_tables from "./1745907000000_create_all_tables"

export const migrations = {
"1745907000000_create_all_tables": M_1745907000000_create_all_tables,
}
Loading