# Skyrama TUI A terminal user interface for a Skyrama-clone airport management game, built with BubbleTea. ## Tech Stack - **Go 1.22** - **github.com/charmbracelet/bubbletea** — TUI framework - **github.com/charmbracelet/lipgloss** — terminal styling - **github.com/charmbracelet/bubbles** — list, textinput, etc. - **github.com/go-sql-driver/mysql** — MySQL driver - **golang.org/x/crypto/bcrypt** — password hashing - **sqlc** — SQL → Go codegen (generated files in `internal/db/`) ## Project Structure ``` cmd/skyrama/main.go # Entry point: rootModel (login → app screen transition) internal/ db/ client.go # Thin wrapper over sqlc Queries; auth, transactions, row mappers db.go / querier.go / queries.sql.go / models.go # sqlc-generated files (do not edit by hand) model/model.go # Domain types: Airport, Plane, PlayerPlane, Building, Contract, … style/style.go # All lipgloss styles and colors ui/ app.go # AppModel: tab bar, 10s tick, window sizing login.go # Login / register screen airport_view.go # Tab 0: resources, XP bar fleet.go # Tab 1: planes, launch/land flights buildings.go # Tab 2: owned buildings + build catalogue contracts.go # Tab 3: active delivery contracts shop.go # Tab 4: buy planes sql/ schema.sql # MySQL DDL (source of truth) queries.sql # sqlc input queries sqlc.yaml # sqlc configuration buidl.bat # build script (go build -o skyrama ./cmd/skyrama/) ``` ## Database - **Engine:** MySQL - **Default DSN:** `skyramaUser:Skyrama1234.@tcp(127.0.0.1:3306)/skyrama_clone?parseTime=true` - Override via `--dsn` flag or `SKYRAMA_DSN` environment variable. - Schema must be applied before first run: `sql/schema.sql` ## Build & Run ```bat # Build buidl.bat # or go build -o skyrama.exe ./cmd/skyrama/ # Run (uses default DSN if SKYRAMA_DSN not set) .\skyrama.exe # Run with custom DSN .\skyrama.exe --dsn "user:pass@tcp(host:port)/dbname?parseTime=true" # Regenerate sqlc files after editing sql/queries.sql sqlc_generate.bat ``` ## Architecture ### Screen flow `rootModel` (main.go) owns two screens: 1. `screenLogin` → `ui.LoginModel` — handles `LoginSuccessMsg` / `LoginErrMsg` 2. `screenApp` → `ui.AppModel` — full game TUI after login On `LoginSuccessMsg`, `rootModel` builds `AppModel` and injects all sub-models (Fleet, Buildings, Contracts, Shop) with the resolved `airportID`. ### AppModel (ui/app.go) - Owns all tab sub-models as value/pointer fields. - Routes `tea.Msg` to the active tab sub-model. - Fires a 10-second tick that: 1. Calls `RefreshResources` (regenerates fuel/passengers via MySQL `TIMESTAMPDIFF`) 2. Auto-lands planes ready to land (`GetPlanesReadyToLand` + `LandFlight`) ### db.Client (internal/db/client.go) Wraps the sqlc `*Queries` object. All multi-step DB operations are wrapped in transactions: - `BuyPlane` — deducts cash, inserts `player_planes`, logs transaction - `LaunchFlight` — deducts fuel, sets plane status to `flying`, logs transaction - `LandFlight` — awards cash + XP, parks plane in hangar, logs transaction - `ConstructBuilding` — deducts cash, inserts `airport_buildings`, logs transaction Some queries use raw `database/sql` (e.g. `GetAirportBuildings`, `GetActiveContracts`) because the sqlc-generated join queries are not yet wired up. ### Domain model (internal/model/model.go) Key types: `Airport`, `Plane`, `PlayerPlane`, `Building`, `AirportBuilding`, `Contract`, `Country`, `User`. `PlayerPlane.TimeRemainingSeconds()` computes seconds until landing client-side. `Contract.ProgressPct()` returns delivery progress as an integer percentage. Tab index constants: `TabAirport=0`, `TabFleet=1`, `TabBuildings=2`, `TabContracts=3`, `TabShop=4`. ## Key Bindings | Key | Action | |-----|--------| | `1-5` / `tab` / `shift+tab` | Switch tabs | | `↑↓` / `j k` | Navigate lists | | `enter` / `space` | Select / action | | `/` | Filter list | | `r` | Refresh current tab | | `h / l` | Switch sub-tabs (Buildings) | | `q` / `ctrl+c` | Quit | **Fleet tab:** `enter` on idle plane → launch; `enter` on flying plane → check/land if ready. **Buildings tab:** `h/l` or `←→` → toggle Owned ↔ Build catalogue; `enter` in catalogue → construct. **Shop tab:** `enter` / `b` → buy selected plane (deducts cash, parks in first hangar). ## DB Schema Overview Core tables: `users`, `airports`, `planes`, `player_planes`, `buildings`, `airport_buildings`, `countries`, `products`, `airport_contracts`, `airport_inventory`. Log tables: `currency_transaction_logs`, `completed_flight_routes_log`. Stage 1 (not yet active): `recipes`, `building_products`. **Plane statuses:** `idle` | `maintenance` | `boarding` | `taxiing` | `flying` **Building types:** `none` | `storage` | `support` | `operation` | `passive` | `shop` | `production` **Aircraft sizes:** `small` | `medium` | `large` | `huge` **Aircraft types:** `plane` | `helicopter` | `seaplane` | `spaceship` ## Development Stages - **Stage 0 (current):** Launch planes to country's base airport, basic resources, buildings, shop. - **Stage 1:** NPCs, cargo planes, shop buildings, recipes, inventory. - **Stage 2:** Player progression, building upgrades, effects, complex recipes. - **Stage 3:** TBD.