Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
30 changes: 15 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Game Server Manager
# Hyveon

A cost-efficient multi-game dedicated server platform on **AWS Fargate** with a
local web UI and a fully serverless Discord bot. Servers only run — and only
cost money — while someone is playing.
local management UI and a fully serverless Discord bot. Servers only run — and
only cost money — while someone is playing.

> 📚 Full documentation lives at **[codercoco.github.io/game-server-deploy](https://codercoco.github.io/game-server-deploy/)**
> 📚 Full documentation lives at **[codercoco.github.io/Hyveon](https://codercoco.github.io/Hyveon/)**
> (built from [`docs/`](./docs) by GitHub Pages). The rest of this README is a
> quick tour; deep-dives, setup steps, and architecture diagrams are on the
> site.
Expand All @@ -31,22 +31,22 @@ cost money — while someone is playing.

## Documentation

The [docs site](https://codercoco.github.io/game-server-deploy/) is
The [docs site](https://codercoco.github.io/Hyveon/) is
organised around three roles. Pick the one that matches what you need to do.

| Guide | You are… |
|---|---|
| [**Setup guide**](https://codercoco.github.io/game-server-deploy/setup/) | Going from a blank AWS account to a running Fargate task. |
| [**User guide**](https://codercoco.github.io/game-server-deploy/guides/user/) | Driving an already-provisioned deployment — the dashboard, Discord commands, day-to-day ops. |
| [**Maintainer guide**](https://codercoco.github.io/game-server-deploy/guides/maintainer/) | Working on this codebase. |
| [**Private parent + submodule guide**](https://codercoco.github.io/game-server-deploy/guides/submodule/) | Wrapping this repo in a private repo that holds `terraform.tfvars` and tfstate. Includes an interactive scaffolder ([`scripts/init-parent.ts`](./scripts/init-parent.ts)) that generates the wrapper Makefile, tfvars, and `.env`. |
| [**Setup guide**](https://codercoco.github.io/Hyveon/setup/) | Going from a blank AWS account to a running Fargate task. |
| [**User guide**](https://codercoco.github.io/Hyveon/guides/user/) | Driving an already-provisioned deployment — the dashboard, Discord commands, day-to-day ops. |
| [**Maintainer guide**](https://codercoco.github.io/Hyveon/guides/maintainer/) | Working on this codebase. |
| [**Private parent + submodule guide**](https://codercoco.github.io/Hyveon/guides/submodule/) | Wrapping this repo in a private repo that holds `terraform.tfvars` and tfstate. Includes an interactive scaffolder ([`scripts/init-parent.ts`](./scripts/init-parent.ts)) that generates the wrapper Makefile, tfvars, and `.env`. |

Component deep-dives:

- [**Architecture**](https://codercoco.github.io/game-server-deploy/architecture/) — full diagram + `/server-start` sequence.
- [**Terraform**](https://codercoco.github.io/game-server-deploy/components/terraform/) — every `.tf` file, variables, outputs, gotchas.
- [**Management app**](https://codercoco.github.io/game-server-deploy/components/management-app/) — Nest.js API, React dashboard, `@gsd/shared`.
- [**Lambdas**](https://codercoco.github.io/game-server-deploy/components/lambdas/) — interactions, followup, update-dns, watchdog.
- [**Architecture**](https://codercoco.github.io/Hyveon/architecture/) — full diagram + `/server-start` sequence.
- [**Terraform**](https://codercoco.github.io/Hyveon/components/terraform/) — every `.tf` file, variables, outputs, gotchas.
- [**Management app**](https://codercoco.github.io/Hyveon/components/management-app/) — Nest.js API, React dashboard, `@gsd/shared`.
- [**Lambdas**](https://codercoco.github.io/Hyveon/components/lambdas/) — interactions, followup, update-dns, watchdog.

## Quick start

Expand All @@ -73,7 +73,7 @@ docker compose up --build
# http://localhost:5000 (dashboard prompts for $API_TOKEN)
```

See the [setup guide](https://codercoco.github.io/game-server-deploy/setup/)
See the [setup guide](https://codercoco.github.io/Hyveon/setup/)
for the full walkthrough, including the IAM policy, Discord bot setup, and
troubleshooting.

Expand Down Expand Up @@ -114,7 +114,7 @@ pennies/month. Playing 4 hours/day, 5 days/week ≈ **$10–12/month**, vs.
## Repository structure

```text
game-server-deploy/
Hyveon/
├── app/ # Nest.js + React monorepo (npm workspaces)
│ └── packages/
│ ├── shared/ # @gsd/shared
Expand Down
2 changes: 1 addition & 1 deletion app/packages/server/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ async function bootstrap(): Promise<void> {
}

await app.listen(PORT);
logger.info(`Game Server Manager API running on http://localhost:${PORT}`, {
logger.info(`Hyveon API running on http://localhost:${PORT}`, {
mode: isDev ? 'development' : 'production',
port: PORT,
});
Expand Down
2 changes: 1 addition & 1 deletion app/packages/web/e2e/pages/AppLayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export class AppLayout {

/** Top-bar product heading — used as a "the dashboard mounted" smoke check. */
brandHeading(): Locator {
return this.page.getByRole('heading', { name: 'Game Server Manager' });
return this.page.getByRole('heading', { name: 'Hyveon' });
}

/** Sidebar nav link by visible label (e.g. "Logs", "Discord", "Settings"). */
Expand Down
2 changes: 1 addition & 1 deletion app/packages/web/e2e/pages/CostsPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { Page, Locator } from '@playwright/test';
export type CostsRangeLabel = '7d' | '30d';

/**
* Page object for the `/costs` route added in CoderCoco/game-server-deploy#61.
* Page object for the `/costs` route added in CoderCoco/Hyveon#61.
* Wraps the headline KPI, the stacked bar chart, the per-game estimates
* table, and the time-range selector so spec files read as test logic
* rather than locator soup.
Expand Down
2 changes: 1 addition & 1 deletion app/packages/web/e2e/pages/LogsPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { Page, Locator } from '@playwright/test';
export type LogLevelLabel = 'INFO' | 'WARN' | 'ERROR' | 'DEBUG';

/**
* Page object for the `/logs` route added in CoderCoco/game-server-deploy#63.
* Page object for the `/logs` route added in CoderCoco/Hyveon#63.
* Wraps the LIVE/PAUSED pill, the searchable game combobox, the in-stream
* search input, the Levels multi-select, the autoscroll toggle, the
* Pause/Resume button, the log box, and the footer line-count summary so
Expand Down
2 changes: 1 addition & 1 deletion app/packages/web/e2e/specs/costs.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { test, expect, stubApis, MULTI_GAME_COST_DATA } from '../fixtures/index.js';

/**
* Specs for the `/costs` route added in CoderCoco/game-server-deploy#61.
* Specs for the `/costs` route added in CoderCoco/Hyveon#61.
* Filter / sort exercises pass `MULTI_GAME_COST_DATA` so the table has more
* than one row to interact with; the default `COST_DATA` only contains
* `minecraft`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { Button } from './ui/button.component';

const MIN_TOKEN_LENGTH = 16;
const DOCS_URL =
'https://codercoco.github.io/game-server-deploy/setup#api-token';
'https://codercoco.github.io/Hyveon/setup#api-token';

/**
* Blocking dialog shown when the API rejects a request with 401. The operator
Expand Down
2 changes: 1 addition & 1 deletion app/packages/web/src/components/app-layout.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ export function AppLayout({ children }: { children: ReactNode }) {
<Menu className="w-5 h-5" aria-hidden="true" />
</button>

<h1 className="hidden sm:block text-lg font-semibold text-foreground shrink-0">Game Server Manager</h1>
<h1 className="hidden sm:block text-lg font-semibold text-foreground shrink-0">Hyveon</h1>
<span className="inline-flex shrink-0 items-center px-2.5 py-0.5 rounded text-xs font-medium bg-purple-500/10 text-purple-400 border border-purple-500/20">
{envLabel}
</span>
Expand Down
4 changes: 2 additions & 2 deletions app/packages/web/src/pages/costs.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ function useCostsData(days: number): {
* with a delta-vs-prior pill, and a time-range selector.
*
* Per-game split for the historical chart is currently a uniform fallback
* because `/api/costs/actual` only returns daily totals — see CoderCoco/game-server-deploy#61.
* because `/api/costs/actual` only returns daily totals — see CoderCoco/Hyveon#61.
*/
export function CostsPage() {
const [range, setRange] = useState<RangeKey>('7d');
Expand Down Expand Up @@ -272,7 +272,7 @@ export function CostsPage() {
{games.length > 0 && (
<p className="mt-3 text-[0.7rem] text-[var(--color-muted-foreground)]">
Per-game split is a uniform approximation — Cost Explorer returns
daily totals only. See CoderCoco/game-server-deploy#61.
daily totals only. See CoderCoco/Hyveon#61.
</p>
)}
</CardContent>
Expand Down
4 changes: 2 additions & 2 deletions app/packages/web/src/pages/dashboard.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ function NoGamesCard() {
</CardHeader>
<CardContent className="flex flex-wrap gap-4">
<a
href="https://codercoco.github.io/game-server-deploy/setup"
href="https://codercoco.github.io/Hyveon/setup"
target="_blank"
rel="noreferrer"
className="inline-flex items-center gap-1.5 text-sm text-[var(--color-primary-light)] underline-offset-4 hover:underline"
Expand All @@ -132,7 +132,7 @@ function NoGamesCard() {
<ExternalLink className="size-3.5" />
</a>
<a
href="https://github.com/CoderCoco/game-server-deploy/blob/main/terraform/terraform.tfvars.example"
href="https://github.com/CoderCoco/Hyveon/blob/main/terraform/terraform.tfvars.example"
target="_blank"
rel="noreferrer"
className="inline-flex items-center gap-1.5 text-sm text-[var(--color-primary-light)] underline-offset-4 hover:underline"
Expand Down
2 changes: 1 addition & 1 deletion app/packages/web/src/pages/discord.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ function SetupWizard({ cfg }: { cfg: DiscordConfigRedacted }) {
<p className="text-xs text-[var(--color-muted-foreground)] border-t border-[var(--color-border)] mt-4 pt-4">
Full walkthrough:{' '}
<a
href="https://codercoco.github.io/game-server-deploy/setup"
href="https://codercoco.github.io/Hyveon/setup"
target="_blank"
rel="noreferrer"
className="text-[var(--color-primary-light)] underline-offset-4 hover:underline"
Expand Down
10 changes: 5 additions & 5 deletions docs/docs/guides/maintainer.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ You're here to change the code. This page is the shortest path from "clean
clone" to "PR merged" plus the invariants that are load-bearing enough that
CI can't always catch you breaking them.

Read [`CLAUDE.md`](https://github.com/codercoco/game-server-deploy/blob/main/CLAUDE.md)
and [`CONTRIBUTING.md`](https://github.com/codercoco/game-server-deploy/blob/main/CONTRIBUTING.md)
Read [`CLAUDE.md`](https://github.com/CoderCoco/Hyveon/blob/main/CLAUDE.md)
and [`CONTRIBUTING.md`](https://github.com/CoderCoco/Hyveon/blob/main/CONTRIBUTING.md)
first. They are the source of truth for test/lint conventions and PR titles.
This page is documentation over the top of them, not a replacement.

## Repository layout

```text
game-server-deploy/
Hyveon/
├── app/ # npm-workspaces monorepo
│ ├── package.json # workspaces root; `npm run` scripts fan out
│ ├── eslint.config.js # flat config; recommended TS + React presets
Expand Down Expand Up @@ -277,9 +277,9 @@ pattern we recommend for anyone running this for real — see the

## Useful references

- [`CLAUDE.md`](https://github.com/codercoco/game-server-deploy/blob/main/CLAUDE.md) —
- [`CLAUDE.md`](https://github.com/CoderCoco/Hyveon/blob/main/CLAUDE.md) —
project instructions in full, including the "why" for every invariant.
- [`CONTRIBUTING.md`](https://github.com/codercoco/game-server-deploy/blob/main/CONTRIBUTING.md) —
- [`CONTRIBUTING.md`](https://github.com/CoderCoco/Hyveon/blob/main/CONTRIBUTING.md) —
PR rules, review policy, local-check commands.
- [Architecture](/architecture) —
component and sequence diagrams.
Expand Down
32 changes: 16 additions & 16 deletions docs/docs/guides/submodule.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ flowchart LR
PTF["terraform.tfvars"]:::priv
PENV[".env<br/>API_TOKEN=…"]:::priv
PSTAMP[".make/<br/>setup.stamp, tfstate.json"]:::priv
PSUB["game-server-deploy/<br/>→ submodule"]:::priv
PSUB["Hyveon/<br/>→ submodule"]:::priv
end

subgraph Upstream["game-server-deploy (public)"]
subgraph Upstream["Hyveon (public)"]
direction TB
UAPP["app/"]:::public
UTF["terraform/*.tf"]:::public
Expand Down Expand Up @@ -66,7 +66,7 @@ your-private-games/ # private repo you own
├── Makefile # wrapper — see "What the wrapper does" below
├── terraform.tfvars # YOUR copy; checked in (private repo)
├── .make/ # stamp dir (sha of submodule setup.sh, cached tfstate)
└── game-server-deploy/ # submodule → CoderCoco/game-server-deploy
└── Hyveon/ # submodule → CoderCoco/Hyveon
```

That's the whole shape. No `config/` directory, no symlinks, no
Expand All @@ -84,11 +84,11 @@ git clone git@github.com:you/your-private-games.git
cd your-private-games

# 2. Add the submodule.
git submodule add https://github.com/CoderCoco/game-server-deploy.git
git submodule add https://github.com/CoderCoco/Hyveon.git

# 3. Install all deps and run the scaffolder.
(cd game-server-deploy && npm install)
(cd game-server-deploy && npm run scripts:init-parent)
(cd Hyveon && npm install)
(cd Hyveon && npm run scripts:init-parent)
```

The script prompts for project name, AWS region, hosted zone, and
Expand All @@ -112,11 +112,11 @@ Five targets, no surprises:

| Target | What it does |
|---|---|
| `make setup` | One-time bootstrap. Runs `git submodule update --init --recursive`, executes `game-server-deploy/setup.sh` (installs Node/Terraform/AWS CLI on Debian/Ubuntu, npm-installs all workspaces, builds Lambda bundles, runs `terraform init` and bootstraps the S3 backend), then records the sha256 of `setup.sh` in `.make/setup.stamp`. |
| `make plan` | Copies `terraform.tfvars` into `game-server-deploy/terraform/terraform.tfvars`, then runs `make -C game-server-deploy tf-plan` — which itself rebuilds the Lambda bundles before `terraform plan`. |
| `make setup` | One-time bootstrap. Runs `git submodule update --init --recursive`, executes `Hyveon/setup.sh` (installs Node/Terraform/AWS CLI on Debian/Ubuntu, npm-installs all workspaces, builds Lambda bundles, runs `terraform init` and bootstraps the S3 backend), then records the sha256 of `setup.sh` in `.make/setup.stamp`. |
| `make plan` | Copies `terraform.tfvars` into `Hyveon/terraform/terraform.tfvars`, then runs `make -C Hyveon tf-plan` — which itself rebuilds the Lambda bundles before `terraform plan`. |
| `make apply` | Same as `plan`, but delegates to `tf-apply`. The submodule's `tf-apply` recipe prints a post-deploy checklist with the Discord interactions URL when it finishes. |
| `make update` | Bumps the submodule to the tip of `main` (`git submodule update --remote --merge`). If the new `setup.sh` differs from the recorded sha, clears `.terraform/` and re-runs `setup.sh` automatically; otherwise leaves it alone. Reminds you to commit the new submodule pointer. |
| `make dev` | Pulls live tfstate into `.make/tfstate.json` (so the embed step has something to read), wipes stale TS build info under the submodule's `app/packages/*/`, then runs `make -C game-server-deploy dev`, exporting `API_TOKEN` and `TF_STATE_PATH` to the child make. |
| `make dev` | Pulls live tfstate into `.make/tfstate.json` (so the embed step has something to read), wipes stale TS build info under the submodule's `app/packages/*/`, then runs `make -C Hyveon dev`, exporting `API_TOKEN` and `TF_STATE_PATH` to the child make. |

The `tfvars` copy is **always fresh** on plan/apply — the recipe `cp`s
unconditionally, not just when the file is older than the destination. This
Expand All @@ -125,15 +125,15 @@ parent's `terraform.tfvars` between runs.

## Submodule update with idempotent setup.sh re-run

`make update` records `sha256sum game-server-deploy/setup.sh` in
`make update` records `sha256sum Hyveon/setup.sh` in
`.make/setup.stamp` after each successful setup. On every subsequent
`update`, it compares the new file's sha against the stamp:

- **Unchanged** → nothing to do; the existing `.terraform/` and installed
npm dependencies are still valid.
- **Changed** → upstream tweaked the bootstrap (new tool version, S3 backend
config change, Lambda build step, …). The recipe wipes
`game-server-deploy/terraform/.terraform/` and re-runs `setup.sh`, then
`Hyveon/terraform/.terraform/` and re-runs `setup.sh`, then
records the new sha.

You don't have to remember whether the bootstrap moved. The stamp file is
Expand All @@ -159,7 +159,7 @@ to keep the same token across rebuilds.

## tfstate lives in S3 by default

`game-server-deploy/setup.sh` provisions an S3 bucket
`Hyveon/setup.sh` provisions an S3 bucket
(`{project_name}-tf-state`) and a DynamoDB lock table
(`{project_name}-tf-locks`) on first run, then `terraform init`s with the
S3 backend pointing at them. The parent repo never holds `terraform.tfstate`
Expand Down Expand Up @@ -198,8 +198,8 @@ make apply

```bash
make update
git add game-server-deploy
git commit -m "chore: bump game-server-deploy to $(git -C game-server-deploy rev-parse --short HEAD)"
git add Hyveon
git commit -m "chore: bump Hyveon to $(git -C Hyveon rev-parse --short HEAD)"
make plan # eyeball the diff
make apply # if it looks right
```
Expand All @@ -212,7 +212,7 @@ Things that tend to need attention after a bump:

- New or renamed Terraform variables → add them to your
`terraform.tfvars`. Compare against
`game-server-deploy/terraform/terraform.tfvars.example`.
`Hyveon/terraform/terraform.tfvars.example`.
- New environment variables on the Lambdas → typically Terraform handles
this automatically, but verify in the plan output.
- Changes to the four slash-command descriptors → re-click **Register
Expand Down Expand Up @@ -276,7 +276,7 @@ than stashing long-lived keys. The role's policy is the same

| Symptom | Cause | Fix |
|---|---|---|
| `make plan` says "No such file or directory" pointing at `game-server-deploy/` | Submodule wasn't initialised | `make setup` (or `git submodule update --init --recursive`). |
| `make plan` says "No such file or directory" pointing at `Hyveon/` | Submodule wasn't initialised | `make setup` (or `git submodule update --init --recursive`). |
| `make apply` runs against an old `terraform.tfvars` | You edited the parent's tfvars but ran terraform inside the submodule directly | Always run `make apply` from the parent — the `copy-tfvars` recipe forces a fresh copy. |
| `make update` silently pulls main and breaks apply | Upstream changed something incompatible | The stamp file's job is to flag setup.sh changes; for non-bootstrap breakage, run `make plan` and read the diff. Pin to a SHA in `.gitmodules` if you want stricter control. |
| After bumping upstream, Discord commands have wrong arguments | Descriptors in `@gsd/shared/commands.ts` changed | Click **Register commands** for each guild in the dashboard. |
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ sidebar_position: 1
slug: /
---

# Game Server Deploy
# Hyveon

A cost-efficient, multi-game dedicated server platform on **AWS Fargate** with a
local management UI and a fully serverless Discord bot. Servers only run — and
Expand Down Expand Up @@ -70,7 +70,7 @@ the `/server-start` sequence) see the
## Repository map

```text
game-server-deploy/
Hyveon/
├── app/ # Nest.js + React monorepo (npm workspaces)
│ └── packages/
│ ├── shared/ # @gsd/shared
Expand Down
10 changes: 5 additions & 5 deletions docs/docs/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ On the AWS side you need:
## 1. Create and authorise an IAM user

1. In the **[AWS IAM console](https://console.aws.amazon.com/iam/)** →
**Users → Create user**, give it a name like `game-server-deploy`.
**Users → Create user**, give it a name like `hyveon`.
2. On the permissions step, choose **Attach policies directly** and skip
through without selecting any managed policy. Create the user.
3. Open the new user → **Permissions → Add permissions → Create inline
Expand Down Expand Up @@ -127,17 +127,17 @@ instead — the management app will pick them up too.
**Linux / macOS:**

```bash
git clone https://github.com/codercoco/game-server-deploy.git
cd game-server-deploy
git clone https://github.com/CoderCoco/Hyveon.git
cd Hyveon
chmod +x setup.sh
./setup.sh
```

**Windows (PowerShell 5.1+):**

```powershell
git clone https://github.com/codercoco/game-server-deploy.git
cd game-server-deploy
git clone https://github.com/CoderCoco/Hyveon.git
cd Hyveon
.\setup.ps1
```

Expand Down
Loading
Loading