Team Pakistan
Online
Overwatch World Cup · Built independently
Official website for the Overwatch World Cup Team Pakistan organization. Roster, schedule, news, VODs, merch, and a fan community forum — all managed through a private admin dashboard. Bilingual in English and Urdu with RTL support. Self-hosted on a homelab via Docker, Caddy, and Cloudflare Tunnel.
Overview
Built for
the whole org.
Fan-First Platform
A central hub for fans, players, and staff. Roster profiles, match schedule, news coverage, VOD library, merch, and a community forum — all in one place. Bilingual in English and Urdu with full RTL support for Pakistan's national language, using the Noto Nastaliq Urdu font.
Admin-Driven Content
Team admins and committee members control all content through a private dashboard
at admin.teampakistan.online — roster updates, news posts, VOD uploads,
schedule entries, merch listings, and site-wide announcements — with no code
deploys required.
Fully Self-Hosted
The entire stack — app, database, and media — runs on a homelab server inside Docker Compose. Cloudflare Tunnel routes production traffic without exposing any inbound ports. Media is served from a self-managed library rather than external image hosts.
Public Site
~20 pages
for fans & players.
Hero & Feed
Announcement ticker, featured news and VODs, upcoming schedule — a live pulse of the team surfaced immediately on load.
Player Profiles
Full roster with group filter tabs (Players, Committee, Coaches, Staff, Creators). Each player gets a dedicated profile page: bio, hero pool, socials, fun facts, and Liquipedia link.
VOD Library
Match recordings, highlights, scrims, and interviews filterable by type. Thumbnails and bilingual titles managed from the admin dashboard.
Fan Forum
Fan-posted content with a flair system, upvotes, and threaded comments. Verified members get elevated trust. Reports feed directly into the admin moderation queue.
Match Schedule
Upcoming matches and events with opponent info and external links. Admin can set override entries to surface one-off events alongside calendar-synced matches.
Merchandise
Merchandise listings with bilingual names and descriptions, pricing, purchase URL, stock status, sizes, colors, and custom badge labels managed entirely from the admin panel.
News & Coverage
Team news and external coverage aggregation. Pinnable articles, platform tags, full bilingual content, and external URL passthrough for linking to third-party coverage.
Contact & Inquiry
Three form types: general contact, Ask a Player, and sponsor inquiries. All submissions are logged in the database and push a notification to the team's devices via a self-hosted ntfy instance.
Admin Dashboard
Full control,
no code deploys.
The private admin area at admin.teampakistan.online is gated by subdomain
and role check. Every piece of site content is manageable here — day-to-day operations
require zero engineering involvement.
Add / edit / delete players; handle, real name, role, pronouns, group, bilingual bio, hero pool, socials, fun facts, image, Liquipedia URL, sort order, published toggle.
Add / edit / delete VODs; bilingual title, YouTube URL, thumbnail, type (match / highlight / scrim / interview), tags, featured flag, published toggle.
Full bilingual articles, external URL, platform tag, pin and publish controls. Supports both original articles and external coverage aggregation.
Add / edit / delete events; date/time, opponent, external URL, override flag for manually injected one-off entries.
Pricing, purchase URL, sizes, colors, customization options, stock status badge, bilingual names and descriptions.
Upload images to server storage; organize into named folders; copy full URL for use in other admin fields; rename and delete; search by filename.
View and moderate posts; pin, lock, or delete content; review flagged reports from the community report queue.
View all users; promote or demote roles (superadmin → admin → verified_member → user); ban and unban with reason tracking.
Create and toggle site-wide announcement banners shown in the ticker on the homepage.
Site-wide configuration via a key/value JSONB store — no hardcoded config values required in the codebase.
Infrastructure
Self-hosted,
zero open ports.
Containerized Stack
Two containers: teampk-app (Astro Node.js server) and
teampk-db (PostgreSQL 16 Alpine). Both share an external
proxy Docker network with the rest of the homelab so Caddy
can route traffic to them. Named volumes persist the database and all
uploaded media across container rebuilds.
Reverse Proxy & Subdomain Routing
Caddy handles HTTPS termination and routes two domains to the same
container: teampakistan.online for the public site and
admin.teampakistan.online for the admin dashboard.
Caddy injects an X-Admin-Subdomain: true header on admin
traffic — the app reads this header to gate the admin role check without
requiring a second deployment.
No Exposed Ports
Cloudflare Tunnel sits in front of Caddy. The homelab initiates an outbound connection to Cloudflare's network — no inbound firewall rules, no exposed home IP. All traffic flows through Cloudflare, providing DDoS protection, HTTPS everywhere, and a stable public address regardless of the server's dynamic IP.
Self-Hosted Asset Storage
Admins upload images directly to the server via the Media admin section. Files
land on a named Docker volume at /app/uploads/<folder>/<uuid>.ext
and are tracked in the media_items table. A custom Astro route
serves them with MIME detection, path traversal protection, and immutable
cache headers. No external image hosts.
better-auth + OAuth
better-auth handles sessions and OAuth with two providers —
Google and Discord. Four roles: superadmin, admin,
verified_member, and user. Superadmin emails are
defined in an environment variable; matching accounts are auto-promoted on
first sign-in.
Self-Hosted Push via ntfy
Contact form submissions and community reports push real-time notifications
to the team's devices through a self-hosted ntfy instance
on the homelab. Configured via NTFY_URL and
NTFY_TOPIC environment variables — no third-party notification
services required.
Stack
Modern tools,
practical choices.
Astro 5 SSR
Server-rendered pages via the Node.js standalone adapter. React islands used only where client interactivity is needed — login forms, filter tabs, community voting. Most pages are pure server HTML for SEO and fast initial loads.
Tailwind CSS
Custom design token palette built around the Pakistan green brand color. Dark esports aesthetic with RadianceBeverage (Overwatch's display font) for headings and TASA Orbiter for body text.
Drizzle ORM + PostgreSQL
Schema-as-code with type-safe queries. 15+ tables covering auth, roster, VODs, news, schedule, merch, community posts/comments/votes, media, and site settings. All managed by Drizzle migrations.
better-auth
Modern auth library handling Google and Discord OAuth, session management, and token lifecycle. Role-based access with four tiers enforced server-side on every request. No rolling custom session logic.
Bilingual EN / UR
All major content types carry parallel English and Urdu fields in the database. Urdu text areas use dir="rtl" throughout the admin forms. Rendered with the Noto Nastaliq Urdu font via Google Fonts CDN.
Docker + Caddy
Full stack runs as a Docker Compose deployment on private hardware. Caddy handles reverse proxying, HTTPS, and subdomain-based admin gating. Cloudflare Tunnel exposes the homelab without opening inbound ports.