Merged into tinqs/studio: - cmd/tinqs-cli/ — tinqs-cli (Go binary, from bot/cli) - cmd/tea/ — Gitea CLI tool (from tinqs/cli-tea) - services/bot/ — Bot service (from tinqs-ltd/bot on git.arikigame.com) - services/admin/ — Admin panel (from tinqs/admin) - services/team-tool/ — Team Tool (from tinqs/team-tool) - services/proxy/ — tinqs-proxy (from bot/proxy) - web/landing/ — tinqs.com website (from tinqs/website) - web/docs/ — Platform docs (from tinqs/docs) - web/blog/ — Blog (placeholder) - runner/ — Ephemeral CI runner (from tinqs/runner) All source repos will be deleted after verification.
5.5 KiB
admin.arikigame
Custom Git Studio + Team Portal for Tinqs. Next.js is the only UI. Gitea runs headless as the git + API engine (clone/push/SSH/LFS/Actions/Issues/PRs). No Gitea web UI is exposed to the browser.
Architecture
HTTP API: Classical Next.js App Router only — all endpoints under src/app/api/ (route.ts handlers). No parallel Express/Fastify layer. See docs/API-ARCHITECTURE.md.
Browser (Tailscale mesh — WireGuard encrypted)
→ Next.js :8088 (this app) — identity via tailscale serve headers OR whois proxy
→ Gitea REST API v1 (headless, https://git.arikigame.com)
→ PostgreSQL :5432 (users, audit log, portal — optional in dev)
git clone / push / LFS
→ git.arikigame.com → Gitea :443 HTTPS (wire protocol; SSH :22)
No Caddy required. Tailscale is the VPN; optional tailscale serve adds HTTPS + identity headers on the MagicDNS URL, or set TAILSCALE_WHOIS_PROXY_URL so the app resolves tailnet client IPs with tailscale whois --json (see docs/TAILSCALE-PRODUCTION.md).
Gitea is headless. It stores repos, handles git protocol, runs Actions, tracks issues/PRs. This app is the sole web interface — all reads/writes go through src/lib/gitea.ts on the server, never through Gitea's HTML UI.
People auth: On the tailnet, Tailscale identity headers are enough. The login email (tailscale-user-login) is normalized to lowercase and stored as users.email — that is the canonical account key (same as your @tinqs.com identity). Existing rows in Postgres match by email; gitea_username is filled from the local part on first insert if empty. Optional portal secondary passwords live in users.password_hash only when PORTAL_SECONDARY_REQUIRED is on — they are a second factor after Tailscale, not a replacement. Optional tailscale-machine-name can be forwarded by your proxy for audit (client MagicDNS hostname).
Git: Clone/push uses git.arikigame.com only.
Quick start (local dev — npm only)
No Docker required for development. Postgres is optional (the app degrades gracefully without it — user persistence is skipped but repo browsing works).
# 1. Copy env
cp .env.example .env.local
# Edit: set GITEA_URL and GITEA_SERVICE_TOKEN (ask ops for the token)
# 2. Run
npm install
npm run dev
# → http://localhost:3000
With Postgres (for user/org/audit features):
docker compose up postgres -d
npm run dev
Where it runs
| Context | How |
|---|---|
| Production | AWS Lightsail — Tailscale + Docker (docker compose up) or npm start; see docs/TAILSCALE-PRODUCTION.md |
| Local dev | npm run dev — no Docker, no Tailscale |
| Isleborn (game dev) | Does not run here. Unity uses git remote → git.arikigame.com |
Tech stack
- Next.js 16 (App Router, RSC, Server Actions)
- TypeScript (strict)
- Tailwind CSS (dark mode, Ariki design tokens)
- PostgreSQL 17 (raw
pgdriver, no ORM — optional in dev) - TanStack Query (client-side cache)
- Gitea 1.25.5 (headless git backend via REST API v1)
- Tailscale (auth: Serve identity headers and/or whois proxy — no separate reverse proxy required)
API
REST endpoints under /api/v1/ for MCP tools, scripts, and future agents:
| Endpoint | Description |
|---|---|
GET /api/v1/repos |
List repos (sort, order, limit, page) |
GET /api/v1/repos/:owner/:repo |
Repo detail |
GET /api/v1/repos/:owner/:repo/contents/*path |
File tree or file content |
GET /api/v1/repos/:owner/:repo/raw/*path |
Raw file content |
GET /api/v1/repos/:owner/:repo/commits |
Commit history |
GET /api/v1/repos/:owner/:repo/branches |
Branch list |
GET /api/v1/repos/:owner/:repo/tags |
Tag list |
GET /api/v1/repos/:owner/:repo/actions |
CI/CD runs |
GET /api/v1/orgs |
Organizations |
GET /api/v1/me |
Current user identity |
GET /api/health |
Health check |
Infrastructure (optional TS_API_KEY, GITHUB_TOKEN in env — see .env.example):
| Endpoint | Description |
|---|---|
GET /api/v1/infra/overview |
Dashboard aggregates (machines, services, tokens, agents) |
GET /api/v1/infra/tokens |
Token metadata inventory (POST/PATCH/DELETE: admin) |
GET /api/v1/infra/tokens/expiring?days=30 |
Tokens expiring soon |
GET /api/v1/infra/services |
Service registry (POST/PATCH/DELETE: admin) |
POST /api/v1/infra/services/:id/health |
Run HTTP health check (admin) |
GET /api/v1/infra/tailscale/devices |
Live tailnet devices |
GET /api/v1/infra/tailscale/dns |
Split DNS config |
GET /api/v1/infra/github/repos?org=tinqs-ltd |
GitHub org repos |
GET /api/v1/infra/agents |
Repo agent config scan (cached 5 min) |
UI: /infra (admin-only). Apply DB migration db/migrations/003_infra.sql on existing Postgres; optional seed db/seed-infra.sql.
Auth: Tailscale identity headers on the tailnet, or ALLOW_DEV_AUTH for local dev.
Tests
npm test
Vitest unit tests for lib/ functions.
Deployment
Production on AWS Lightsail (medium_3_0, 4 GB RAM):
# Docker (current)
docker compose up -d
# Or direct (npm)
npm run build && npm start
Split DNS / tailscale serve / direct 100.x access routes browsers to Next (:8088) and Git Studio at https://git.arikigame.com (Gitea on :443). Details: docs/TAILSCALE-PRODUCTION.md.