Skip to content

SkateHive/singup-admin

Repository files navigation

Skatehive VIP Codes Admin Dashboard

A secure Next.js 15 admin dashboard for managing single-use VIP codes for the Skatehive project.

Features

  • Generate Batch VIP Codes: Create up to 500 codes at once with optional expiry dates, reserved usernames, and notes
  • Secure Secret Hashing: Uses Argon2id with pepper for hashing VIP code secrets
  • Code Management: List, revoke, and delete unused VIP codes
  • Usage Tracking: View usage timeline for each code from vip_code_uses table
  • CSV Export: Export the visible code list to CSV
  • Basic Auth Protection: All admin routes protected with HTTP Basic Authentication

Required Environment Variables

Create a .env file in the root directory with the following variables:

# Supabase Configuration
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key

# VIP Code Security
VIP_PEPPER=your-long-random-string-for-hashing

# Admin Authentication
ADMIN_USER=admin
ADMIN_PASS=your-strong-admin-password

Security Notes

  • SUPABASE_SERVICE_ROLE_KEY: Service role key from Supabase (has full database access, never expose to client)
  • VIP_PEPPER: A long random string used as additional salt for Argon2id hashing (keep secret)
  • ADMIN_PASS: Strong password for Basic Auth (minimum 16 characters recommended)

Installation

# Install dependencies
pnpm install

# Or using npm
npm install

# Or using yarn
yarn install

Development

# Run development server
pnpm dev

# Or
npm run dev

Open http://localhost:3000 in your browser.

  • Home page: http://localhost:3000
  • Admin dashboard: http://localhost:3000/admin

Build

# Build for production
pnpm build

# Start production server
pnpm start

Deployment

Vercel (Recommended)

  1. Push your code to GitHub
  2. Import the repository in Vercel
  3. Add all environment variables in the Vercel project settings:
    • SUPABASE_URL
    • SUPABASE_SERVICE_ROLE_KEY
    • VIP_PEPPER
    • ADMIN_USER
    • ADMIN_PASS
  4. Deploy

Other Platforms

Ensure all environment variables are set in your hosting platform's configuration.

Database Schema

The application expects these Supabase tables:

vip_codes

  • id (uuid, primary key)
  • code_id (text, unique)
  • secret_hash (text)
  • expires_at (timestamptz, nullable)
  • reserved_username (text, nullable)
  • created_by (text, nullable)
  • notes (text, nullable)
  • created_at (timestamptz, default now())
  • consumed_at (timestamptz, nullable)
  • consumed_email (text, nullable)

vip_code_uses

  • id (uuid, primary key)
  • vip_code_id (uuid, foreign key to vip_codes)
  • email (text, nullable)
  • username (text, nullable)
  • hive_account (text, nullable)
  • ip (inet, nullable)
  • user_agent (text, nullable)
  • status (use_status enum)
  • error (text, nullable)
  • created_at (timestamptz, default now())

API Routes

All API routes are protected by Basic Auth middleware.

POST /api/admin/vip-codes/generate

Generate batch VIP codes.

Request Body:

{
  "count": 5,
  "expires_at": "2025-12-31T23:59:59Z",
  "reserved_username": "skater123",
  "created_by": "admin",
  "notes": "Batch for event"
}

Response:

{
  "codes": [
    {
      "id": "uuid",
      "code_id": "ABC123",
      "display_code": "ABC123-XYZ789AB",
      "expires_at": "2025-12-31T23:59:59Z",
      "reserved_username": "skater123"
    }
  ]
}

GET /api/admin/vip-codes/list

Get latest 1000 VIP codes.

Response:

{
  "codes": [
    {
      "id": "uuid",
      "code_id": "ABC123",
      "expires_at": "2025-12-31T23:59:59Z",
      "reserved_username": "skater123",
      "created_by": "admin",
      "notes": "Batch for event",
      "created_at": "2025-10-26T12:00:00Z",
      "consumed_at": null,
      "consumed_email": null
    }
  ]
}

POST /api/admin/vip-codes/revoke

Revoke an unused VIP code (sets expires_at to now).

Request Body:

{
  "id": "uuid"
}

POST /api/admin/vip-codes/delete

Delete an unused VIP code.

Request Body:

{
  "id": "uuid"
}

GET /api/admin/vip-codes/uses?id=<uuid>

Get usage timeline for a VIP code.

Response:

{
  "uses": [
    {
      "id": "uuid",
      "email": "[email protected]",
      "username": "skater123",
      "hive_account": "@skater123",
      "ip": "192.168.1.1",
      "user_agent": "Mozilla/5.0...",
      "status": "success",
      "error": null,
      "created_at": "2025-10-26T12:00:00Z"
    }
  ]
}

Manual Testing

  1. Generate Codes: Create 5 codes with an expiry date and reserved username
  2. Copy Display Codes: Use the "Copy" buttons to copy generated display codes
  3. Revoke Code: Click "Revoke" on an unused code (sets expires_at to current time)
  4. Delete Code: Click "Delete" on an unused code (removes from database)
  5. View Uses: Click "Uses" to see the usage timeline for a code
  6. Export CSV: Click "Export CSV" to download all visible codes

Security Features

  • Server-Only Database Access: Supabase Service Role key only used in Route Handlers
  • Basic Auth Protection: All /admin and /api/admin routes protected by middleware
  • Argon2id Hashing: Secrets hashed with strong memory cost (64 MB) and pepper
  • No Secret Exposure: Display codes only returned on generation, never logged
  • Consumed Code Protection: Revoke and delete operations only work on unused codes

Tech Stack

  • Framework: Next.js 15 (App Router)
  • Language: TypeScript
  • Styling: Tailwind CSS
  • Database Client: @supabase/supabase-js
  • Hashing: argon2 (Argon2id algorithm)
  • Authentication: HTTP Basic Auth via middleware

License

MIT

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •