My World
A free-to-play MMORPG built as a Turborepo monorepo: a Godot 3D game client talking to a unified Go game/account/economy server over WebSocket and REST; an Angular web platform for the in-game store, blog, and player governance; and an Astro public landing site. Business and design rules (accounts, currency, governance) are tracked as a single source of truth in a project manuscript doc.
Currently a Phase 0-1 vertical slice — a phased roadmap and a milestone checklist track what's actually built versus planned.
What it does
- 3D multiplayer world — third-person movement, real-time player sync, melee combat, basic mob AI (aggro/chase/attack), zone chat, and item pickup, all validated server-side; no client-authoritative gameplay state.
- Accounts — permanent accounts (email/password) and MANUSCRITO.md's temporary "Juego Preview" accounts (access-code based, no password), both able to play and both persisted the same way.
- In-world vault — players deposit items found in the world into a persistent, account-linked inventory that's visible from the web platform.
- Store & auctions — listings, timed auctions with bid escrow/refund, gifting, and a transaction ledger, all under gold — the game's single currency, never purchasable with real money.
- Blog & governance — permanent-account-exclusive news/discussion threads, plus a proposal/voting system with an hour-based eligibility threshold and gold-gated proposal/comment costs.
- REST + WebSocket API — one Go service exposing auth, forum, governance, and market/auction endpoints over REST, and the authoritative game simulation over a WebSocket connection.
Architecture
Turborepo + pnpm workspaces:
| App | Role |
|---|---|
apps/game/world |
Godot 4.7 game client — 3D world, movement, combat, chat, vault UI |
apps/api |
Go + Gin + GORM/Postgres — one process serving both the REST API and the authoritative game WebSocket (/ws) |
apps/platform |
Angular 19 — store, blog, and governance frontend behind a single login |
apps/web |
Astro — public marketing/landing site |
docs/ |
Living design docs: architecture, roadmap, milestones, risk/decision log, and the product-rules manuscript |
apps/api was originally two services (a NestJS backend plus a separate Go
game server) and apps/platform was originally two Angular apps (store and
blog); both pairs were merged into one during the project's build-out once the
duplication (auth, session handling, shell chrome) outweighed the benefit of
keeping them apart.
Tech stack
- Monorepo — Turborepo, pnpm 9 workspaces
- Game client — Godot 4.7 (GDScript), WebSocket networking, simple 3D primitives as placeholder art
- Backend — Go, Gin, GORM, PostgreSQL, JWT auth (HS256 access + refresh tokens with rotation and reuse detection)
- Web frontend — Angular 19, Astro
- Language — Go, TypeScript, GDScript
Highlights
- Server-authoritative game loop: a single-goroutine, channel-driven Hub owns all player/mob/item state with no locking, ticking at 20 Hz and validating every client message (range, cooldown, rate limits) before it affects state.
- Money-safety-first economy: every gold- or inventory-mutating endpoint
(listings, auctions, gifts, proposal costs) runs inside a single DB
transaction with
SELECT ... FOR UPDATErow locks — no client ever submits a balance, only an action for the server to validate and apply. - Refresh-token rotation with reuse detection (a replayed refresh token invalidates the account's active session rather than being silently accepted), plus a closed timing side-channel on login.
- Mid-project backend consolidation: merged a NestJS service and a standalone Go game server into one Go binary, and merged two near-duplicate Angular apps into one — both verified end-to-end against a real Postgres instance and real client connections before the originals were removed.