mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-25 15:08:47 -07:00
Document admin page and refresh architecture docs
This commit is contained in:
@@ -4,8 +4,13 @@ Native Android/iOS admin app for DorkNet, built with .NET MAUI.
|
||||
|
||||
In the microservices deployment, point the app at the public admin host
|
||||
for the stack, usually `https://admin.<domain>`. Cloudflare and
|
||||
`DorkNet.Gateway` keep the public URL stable while admin API requests are
|
||||
routed to the owning backend slice.
|
||||
`DorkNet.Gateway` keep the public URL stable. Requests made through the
|
||||
admin host are handled by the `web` service's same-origin admin route;
|
||||
the `/api/admin/*` path family is also exposed by the moderation slice
|
||||
for non-admin-host routing.
|
||||
|
||||
The browser admin page, route map, and troubleshooting flow are
|
||||
documented in [`../docs/admin.md`](../docs/admin.md).
|
||||
|
||||
## Authentication
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ Both were collapsed in 2026-05-25:
|
||||
no per-feature patches needed.
|
||||
- The PhotonRegion coerce (the only data transform in the block)
|
||||
was moved into `LegacyUpgrades.CoercePhotonRegionAsync`.
|
||||
- The Storage admin page (`admin-ui/src/pages/Storage.tsx`) and
|
||||
- The legacy storage backfill page (`admin-ui/src/pages/Storage.tsx`) and
|
||||
`StorageBackfillController.cs` were deleted — they were the UI for
|
||||
draining the legacy `RoomDataBlobs.Bytes` column into S3, which is
|
||||
no longer needed.
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
|
||||
Generated: 2026-05-09. Source: client URLs from `Cpp2IL_ISIL` ISIL dump (curated list provided to this report); server routes harvested via grep of `[HttpGet]`/`[HttpPost]`/`[HttpPut]`/`[HttpDelete]`/`[Route]` attributes across `Controllers/**/*.cs` plus the namespace-wildcard fall-throughs in `ApiNamespaceStubsController` and the global `ApiCatchAllController` / `GlobalCatchAllController`.
|
||||
|
||||
> Snapshot scope: this file is a historical controller-coverage matrix,
|
||||
> not the live gateway route table. The dedicated microservice hosts
|
||||
> still reuse the shared controller stack behind route guards, so the
|
||||
> endpoint shape notes remain useful. For current service ownership, use
|
||||
> `DorkNet.Contracts/DorkNetRouteOwnership.cs` or the gateway
|
||||
> `/internal/routes` endpoint.
|
||||
|
||||
## How this matrix is built
|
||||
|
||||
Each client URL is matched against the server's full route table. ASP.NET Core routes resolve "specific wins over wildcard", so a route literally registered as `api/foo/v1/bar` always wins over `api/foo/{*path}`. The `Status` column reflects the route that actually wins:
|
||||
|
||||
@@ -245,6 +245,9 @@ For deployment details, including Dokploy env vars, Cloudflare Tunnel
|
||||
routing, external Postgres, and S3 setup, see
|
||||
[docs/deploy.md](docs/deploy.md).
|
||||
|
||||
For the browser admin console, its routes, auth model, and production
|
||||
troubleshooting, see [docs/admin.md](docs/admin.md).
|
||||
|
||||
---
|
||||
|
||||
## Database & migrations
|
||||
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
# DorkNet Admin Page
|
||||
|
||||
The admin page is the browser operations console for DorkNet. In the
|
||||
microservices deployment it lives at `https://admin.<domain>/` and is
|
||||
served by the `web` service from the built Vite SPA assets.
|
||||
|
||||
The admin backend endpoints are under `/api/admin/v1`. Requests from the
|
||||
SPA are same-origin, so `https://admin.<domain>/api/admin/v1/*` is also
|
||||
handled by the `web` service route on the admin host. The same
|
||||
`/api/admin/*` route family is available as a path-owned moderation slice
|
||||
for non-admin-host routing, so `/internal/routes` can show moderation as
|
||||
the owner for that path family.
|
||||
|
||||
## Runtime Routing
|
||||
|
||||
| Item | Value |
|
||||
|---|---|
|
||||
| SPA source | `DorkNet.Server/admin-ui` |
|
||||
| Build output | `DorkNet.Server/wwwroot/admin` |
|
||||
| Container path | `/app/wwwroot/admin` |
|
||||
| Public browser host | `admin.<domain>` |
|
||||
| API base used by the SPA | `/api/admin/v1` |
|
||||
| Login endpoint | `POST /api/admin/v1/login` |
|
||||
| Same-origin admin-host service | `web` |
|
||||
| Path-routed admin API slice | `moderation` |
|
||||
|
||||
`DorkNet.Gateway` preserves the original Host header when it proxies to
|
||||
backend services. That matters for the admin page: the `admin.<domain>`
|
||||
host route must reach `web`, and `web` must contain
|
||||
`/app/wwwroot/admin/index.html`.
|
||||
|
||||
## Authentication
|
||||
|
||||
The first account created on a fresh database is promoted to admin so
|
||||
there is always a bootstrap operator. The login form posts to
|
||||
`/api/admin/v1/login`; the SPA stores the returned values in browser
|
||||
`localStorage`:
|
||||
|
||||
| Key | Contents |
|
||||
|---|---|
|
||||
| `dorknet.admin.token` | DorkNet admin JWT |
|
||||
| `dorknet.admin.me` | Admin identity object used by the layout |
|
||||
|
||||
Every admin API request sends `Authorization: Bearer <token>`. Protected
|
||||
actions are guarded by `AdminOnlyAttribute`, which checks the resolved
|
||||
player row still has `IsAdmin = true`. A `401` clears the local session
|
||||
and sends the browser back to login.
|
||||
|
||||
If the admin host is public, put it behind Cloudflare Access or an
|
||||
equivalent outer access control. The DorkNet JWT is still required after
|
||||
that outer check.
|
||||
|
||||
## Navigation
|
||||
|
||||
| Section | Routes | Workflows |
|
||||
|---|---|---|
|
||||
| Overview | `/` | Live ops dashboard, online players, active sessions, quick kick/ban/broadcast actions |
|
||||
| Moderation | `/players` | Player directory, bans, reports, per-player ban/grant/gift/password/avatar/account actions |
|
||||
| Activity | `/activity` | Admin audit log and per-player request logs |
|
||||
| Content | `/rooms`, `/rooms/:id`, `/import-room`, `/content` | Room list/detail, room import, instances, leaderboards, community board, loading tips |
|
||||
| Operations | `/broadcast`, `/settings` | Server broadcast, server toggles, signup codes, weekly challenges, Play menu tags, Rec Center doors, game config values |
|
||||
|
||||
Several older admin URLs are kept as redirects:
|
||||
|
||||
| Old route | Current route |
|
||||
|---|---|
|
||||
| `/bans` | `/players?tab=bans` |
|
||||
| `/reports` | `/players?tab=reports` |
|
||||
| `/gift`, `/passwords`, `/grants` | `/players` |
|
||||
| `/audit` | `/activity?tab=audit` |
|
||||
| `/logs` | `/activity?tab=logs` |
|
||||
| `/rr-originals`, `/instances`, `/leaderboards` | `/rooms` |
|
||||
| `/community` | `/content?tab=community` |
|
||||
| `/loading-tips` | `/content?tab=tips` |
|
||||
| `/signup-codes` | `/settings?tab=signup` |
|
||||
|
||||
`/import-room-legacy` still exists for the legacy room importer.
|
||||
|
||||
## Build And Deploy
|
||||
|
||||
The service Dockerfile builds the admin SPA for service images that need
|
||||
static assets. In the microservices stack the `web` image must include:
|
||||
|
||||
```text
|
||||
/app/wwwroot/admin/index.html
|
||||
/app/wwwroot/admin/assets/*
|
||||
```
|
||||
|
||||
The admin SPA calls relative URLs, so it does not need a configured API
|
||||
origin as long as the browser is opened on `https://admin.<domain>/`.
|
||||
|
||||
The native admin mobile app points at the same public admin host; see
|
||||
[`../DorkNet.AdminMobile/README.md`](../DorkNet.AdminMobile/README.md).
|
||||
|
||||
## Smoke Checks
|
||||
|
||||
Check the static host:
|
||||
|
||||
```bash
|
||||
curl -I https://admin.yourdomain.com/
|
||||
```
|
||||
|
||||
Check that protected admin API routing is alive. A `401` is expected
|
||||
without a valid admin token:
|
||||
|
||||
```bash
|
||||
curl -i https://admin.yourdomain.com/api/admin/v1/stats
|
||||
```
|
||||
|
||||
Check the built assets inside the running `web` container:
|
||||
|
||||
```bash
|
||||
docker exec <web-container> sh -lc 'find /app/wwwroot/admin -maxdepth 2 -type f | sort | head -50'
|
||||
```
|
||||
|
||||
Useful logs:
|
||||
|
||||
```bash
|
||||
docker logs <stack>-gateway-1 --tail=200
|
||||
docker logs <stack>-web-1 --tail=200
|
||||
docker logs <stack>-moderation-1 --tail=200
|
||||
```
|
||||
|
||||
For normal browser admin traffic, start with `gateway` and `web`.
|
||||
Check `moderation` when you are testing `/api/admin/*` through a
|
||||
non-admin host such as `api.<domain>`.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Symptom | Check |
|
||||
|---|---|
|
||||
| `admin.<domain>/` returns 404 | `web` logs for `probe="/app/wwwroot/admin/index.html" exists=False`; rebuild/redeploy the `web` image |
|
||||
| Admin page loads but actions 404 | Gateway `/internal/routes`, then whether the request host is `admin.<domain>` or a path-routed host |
|
||||
| Login or actions return 401 | Token expired, local session cleared, or the player no longer has `IsAdmin = true` |
|
||||
| Browser spins forever | Open the browser network tab, then check `gateway` and `web` logs for the stuck URL |
|
||||
| Upload/import fails near 100 MB | Use the chunked importer; the SPA uses 50 MB chunks to stay below Cloudflare request limits |
|
||||
@@ -45,8 +45,8 @@ DorkNet.sln
|
||||
| `DorkNet.Services.Social` | Clubs, groups, announcements, player events, subscriptions | .NET 9 |
|
||||
| `DorkNet.Services.Commerce` | Catalog, storefronts, econ, inventory, inventions | .NET 9 |
|
||||
| `DorkNet.Services.Platform` | Service URLs, config, version checks, geo, strings, telemetry-style surfaces | .NET 9 |
|
||||
| `DorkNet.Services.Moderation` | Bug reporting, player reporting, sanitize, admin API, testcase routes | .NET 9 |
|
||||
| `DorkNet.Services.Web` | Public site, admin static host, feed static host, site API | .NET 9 |
|
||||
| `DorkNet.Services.Moderation` | Bug reporting, player reporting, sanitize, path-routed admin API, testcase routes | .NET 9 |
|
||||
| `DorkNet.Services.Web` | Public site, admin static host, same-origin admin browser API, feed static host, site API | .NET 9 |
|
||||
| `DorkNet.ClientMod` | MelonLoader 0.6.x IL2CPP mod — the client patcher, JSON config | .NET 6 |
|
||||
|
||||
`ClientMod` applies the client-side patches needed to point the 2020
|
||||
@@ -119,6 +119,10 @@ SPAs for service images that need static assets, publishes the selected
|
||||
.NET project, and runs that DLL in the runtime image. The root
|
||||
`Dockerfile` builds only the standalone/fallback `DorkNet.Server` image.
|
||||
|
||||
For the admin browser console specifically, including the host routing
|
||||
split between the admin static host and `/api/admin/v1`, see
|
||||
[`admin.md`](admin.md).
|
||||
|
||||
### Controllers/ groupings
|
||||
|
||||
20 top-level groups, each responsible for one product surface the
|
||||
|
||||
+10
-2
@@ -29,8 +29,8 @@ while route slices move out of the fallback server.
|
||||
| `social` | Clubs, groups, announcements, player events, subscriptions |
|
||||
| `commerce` | Catalog, storefronts, econ, inventory, inventions |
|
||||
| `platform` | Service directory, config, version checks, geo, strings |
|
||||
| `moderation` | Bug reports, player reports, sanitize, admin API, testcase routes |
|
||||
| `web` | Apex/www/admin/feed static hosts and site API |
|
||||
| `moderation` | Bug reports, player reports, sanitize, path-routed admin API, testcase routes |
|
||||
| `web` | Apex/www/admin/feed static hosts, same-origin admin browser API, and site API |
|
||||
| `monolith` | Fallback shared server for route families not split yet |
|
||||
| `postgres` | Bundled Postgres for the compose network |
|
||||
| `redis` | Bundled Redis for ephemeral state and fan-out |
|
||||
@@ -240,11 +240,15 @@ Expected key files:
|
||||
slice or to the monolith fallback. `/internal/services/health` reports
|
||||
gateway-visible health for each backend service.
|
||||
|
||||
For the admin page's browser routes, auth flow, same-origin API calls,
|
||||
and focused troubleshooting, see [`admin.md`](admin.md).
|
||||
|
||||
### Useful Logs
|
||||
|
||||
```bash
|
||||
docker logs <stack>-gateway-1 --tail=200
|
||||
docker logs <stack>-web-1 --tail=200
|
||||
docker logs <stack>-moderation-1 --tail=200
|
||||
docker logs <stack>-platform-1 --tail=200
|
||||
docker logs <stack>-cloudflared-1 --tail=200
|
||||
```
|
||||
@@ -260,6 +264,10 @@ That means the `web` image did not include the built SPA assets or the
|
||||
old container is still running. Force a clean Dokploy rebuild on the
|
||||
latest branch commit.
|
||||
|
||||
Admin browser traffic on `admin.<domain>` is routed to `web`. The
|
||||
`moderation` service is still useful when testing the `/api/admin/*`
|
||||
path family through non-admin hosts.
|
||||
|
||||
---
|
||||
|
||||
## Local Microservices
|
||||
|
||||
+15
-12
@@ -3,7 +3,9 @@
|
||||
Cloudflare Tunnel is used in two DorkNet workflows:
|
||||
|
||||
- Local standalone testing, where cloudflared forwards `*.localhost`
|
||||
traffic to a locally running `DorkNet.Server`.
|
||||
traffic to a locally running `DorkNet.Server`. The default origin is
|
||||
`http://localhost:8080`; use local HTTPS only when you intentionally
|
||||
run the standalone server with a wildcard dev certificate.
|
||||
- Dokploy production microservices, where the compose sidecar forwards
|
||||
the apex and wildcard hostnames to `http://gateway:8080`.
|
||||
|
||||
@@ -26,10 +28,9 @@ friends to reach it through Cloudflare.
|
||||
1. **`localhost` is on a Cloudflare account you control.** The DNS
|
||||
nameservers for the domain need to be Cloudflare's. Check at
|
||||
<https://dash.cloudflare.com/> — the zone should be Active.
|
||||
2. **Local standalone server running** on `0.0.0.0:443` with the wildcard cert
|
||||
that covers `*.localhost` (re-run `tools/patch-client.ps1` if your
|
||||
cert is still the `+1` rec.net-only one — it'll regenerate as
|
||||
`+3` covering both domains).
|
||||
2. **Local standalone server running.** The current quickstart listens
|
||||
on `http://localhost:8080`. Older local TLS setups can still run on
|
||||
`0.0.0.0:443` with a wildcard certificate that covers `*.localhost`.
|
||||
3. **Patched client** with `tools/patch-domain.ps1` so the in-game
|
||||
URLs resolve to `*.localhost`. (Players using the public deployment
|
||||
need to run this on their own client too.)
|
||||
@@ -97,7 +98,7 @@ visitor -> https://api.localhost/api/versioncheck/v4
|
||||
-> Cloudflare edge
|
||||
-> cloudflared tunnel
|
||||
-> cloudflared running on your machine
|
||||
-> https://localhost:443 (Host preserved)
|
||||
-> http://localhost:8080 (Host preserved)
|
||||
-> DorkNet.Server
|
||||
```
|
||||
|
||||
@@ -112,12 +113,14 @@ visitor -> https://api.yourdomain.com/api/versioncheck/v4
|
||||
-> dedicated service slice or monolith fallback
|
||||
```
|
||||
|
||||
For the local standalone template, the leg from cloudflared to localhost
|
||||
has `noTLSVerify: true` because the local server's cert is from mkcert
|
||||
(private CA only trusted on your machine). The Cloudflare-edge to
|
||||
cloudflared leg is still TLS-encrypted with Cloudflare's cert. In the
|
||||
Dokploy microservices stack, the tunnel sidecar uses plain HTTP on the
|
||||
private Compose network and sends everything to the gateway.
|
||||
For default local testing, point the local cloudflared origin at
|
||||
`http://localhost:8080`. If you intentionally test a local HTTPS origin,
|
||||
the leg from cloudflared to localhost can use `noTLSVerify: true`
|
||||
because that certificate is usually from a private dev CA. The
|
||||
Cloudflare-edge to cloudflared leg is still TLS-encrypted with
|
||||
Cloudflare's cert. In the Dokploy microservices stack, the tunnel
|
||||
sidecar uses plain HTTP on the private Compose network and sends
|
||||
everything to the gateway.
|
||||
|
||||
## Tearing down
|
||||
|
||||
|
||||
Reference in New Issue
Block a user