# Key Lair

A self-hosted game key distribution portal for sending review/influencer keys
to creators — no account or login required on their end.

**Stack:** PHP + MySQL + Apache2. No external services, no Node/PostgreSQL, no
paid dependencies.

## What it does

- Send a creator a single link. They pick their platform (Steam, Xbox,
  PlayStation 4/5, Switch/Switch 2, or any other platform you've added) and
  get an unused key — no registration.
- Manage multiple products ("games"), each with its own cover image,
  screenshots, YouTube trailer, and custom intro/outro text — a Steam-page-like
  claim experience.
- Campaigns, creator groups, and per-link claim limits with a clear override →
  creator-group → campaign resolution chain.
- Admin panel: dashboard, key import (CSV/paste with dedup), claim link
  generation, redemption log, analytics, and a **Design** page that lets a
  designer download/upload/preview/publish each page's CSS independently —
  changes never go live until explicitly published.
- Security: atomic key allocation (`SELECT ... FOR UPDATE`, so two people can
  never receive the same key), CSRF protection, rate limiting, session-based
  admin auth, and modular two-factor authentication (TOTP via any
  authenticator app today; built so email/SMS/etc. can be added later without
  touching the login flow).

## Documentation

See the project [Wiki](../../wiki) for architecture, admin panel, design
system, security notes, bug history, deployment, and licensing details.

## Getting started

See [`install/INSTALL.md`](install/INSTALL.md) for a full step-by-step guide —
written for someone with little to no Linux experience, from a fresh Ubuntu
24.04 server to a working installation with HTTPS. After uploading the files
and setting up Apache, visit `/setup.php` in a browser for a WordPress-style
setup wizard that tests your database connection, writes `config/config.php`,
and installs the schema for you — no manual file editing required.

## Project structure

```
config/       Configuration (copy config.sample.php to config.php)
sql/          Database schema
src/          Application logic (PHP, namespaced under KeyLair\)
resources/    Shipped default CSS templates (never overwritten by the app)
public/       Apache document root — everything web-accessible lives here
  admin/      Admin panel
  assets/     Fonts/JS; CSS is served dynamically via css.php (see below)
  uploads/    Product images (created at runtime, must be writable)
install/      INSTALL.md
```

## Customizing the design

Every themed page's CSS can be downloaded, edited, and re-uploaded from
**Admin → Design** — no code changes needed. Uploads land as a draft first;
use the **Preview** button (visible only to logged-in admins) to see it live
before **Publishing** it for real visitors. **Download default template**
always gets you back to the originally shipped version, even after
publishing changes.
