Skip to content

Admin Portal Setup Guide

Last Updated: 2026-01-27

This guide covers setting up and running the Lantern Admin Portal, an internal-only application for managing documentation and platform data.


Overview

The admin portal is a separate Vite + React application that:

  • Uses Firebase Auth with admin role checking
  • Links to StackEdit or GitHub.dev for markdown editing
  • Edits sync directly to GitHub (no intermediate service)
  • Deploys to admin.ourlantern.app (prod) / admin.dev.ourlantern.app (dev)

Tech Stack:

  • Vite + React (same as main app)
  • StackEdit / GitHub.dev (external editors with GitHub integration)
  • Firebase Auth (admin role required)
  • Cloudflare Pages (admin portal deployment)

Quick Start (Local Development)

bash
# From repo root
npm install
npm run admin:dev

The admin portal runs on http://localhost:3001 (separate from main app on 3000).

Note: Uses the root .env.local file - same Firebase config as main app.


Architecture

admin/
├── src/
│   ├── App.jsx              # Main app with auth flow
│   ├── firebase.js          # Firebase config + admin role checking
│   ├── main.jsx             # React entry point
│   ├── styles.css           # Dark theme (matches main app)
│   └── components/
│       ├── AdminDashboard.jsx   # Feature dashboard
│       ├── DocsEditor.jsx       # Links to StackEdit/GitHub.dev
│       ├── LoadingScreen.jsx
│       ├── LoginScreen.jsx      # Email/passphrase login
│       └── AccessDenied.jsx     # Non-admin rejection
├── public/
│   ├── _headers             # Cloudflare security headers
│   ├── _redirects           # SPA routing
│   └── icons/               # App icons
├── vite.config.mjs          # Uses root .env.local
└── package.json             # Workspace package

Authentication Flow

  1. User clicks "Sign in with GitHub"
  2. Firebase Auth redirects to GitHub OAuth
  3. On success, Firebase returns user + GitHub token
  4. App checks Firestore users/{uid} for role: 'admin'
  5. If admin → show dashboard; else → show "Access Denied"

Setting Up Admin Users

To grant admin access, add role: 'admin' to the user's Firestore document:

javascript
// Firestore path: users/{userId}
{
  email: "admin@example.com",
  displayName: "Admin User",
  role: "admin",  // <-- This field grants admin access
  // ... other fields
}

You can do this via:

  • Firebase Console → Firestore → users collection
  • Firebase Admin SDK script
  • The main app's user management (if implemented)

Documentation Editing

The admin portal provides links to external editors that integrate directly with GitHub. No self-hosted services required!

Editor Options

EditorBest ForDark ModeSetup
StackEditNon-technical usersOne-time GitHub link
GitHub.devDevelopersNone (press . on GitHub)
GitHubQuick editsNone

StackEdit Setup (One-time)

StackEdit is a WYSIWYG markdown editor with dark mode support.

  1. Go to: https://stackedit.io/app

  2. Click the folder icon in the sidebar

  3. Click "Add a GitHub workspace"

  4. Link your GitHub account if prompted

  5. Configure:

    FieldValue
    Repository URLhttps://github.com/cattreedev/lantern_app
    Branchdev
    Pathdocs
  6. Click OK - your docs folder will appear!

GitHub.dev (Zero Setup)

GitHub.dev is VS Code in your browser.

How Changes Are Saved

  1. Edit a file in StackEdit or GitHub.dev
  2. Commit changes (both editors have commit UI)
  3. Changes go directly to the dev branch
  4. CI/CD automatically deploys updates

VitePress Integration

Documentation edits in /docs are used by VitePress to generate public documentation.

New Docs Not Appearing?

When you add a new page, VitePress needs to know about it:

If VitePress auto-discovers files:

  • New .md files appear automatically on next build/deploy

If VitePress has manual sidebar config:

  • Update docs/.vitepress/config.js to add new pages to navigation
  1. Create/edit doc in StackEdit or GitHub.dev
  2. Commit changes to dev branch
  3. Update VitePress sidebar if needed (for new pages)
  4. CI/CD deploys automatically

Deployment

The admin portal is deployed automatically via GitHub Actions when changes are pushed to dev or main.

Cloudflare Pages Projects

EnvironmentProject NameURL
Developmentlantern-admin-devadmin.dev.ourlantern.app
Productionlantern-adminadmin.ourlantern.app

Creating the Cloudflare Pages Project

If the project doesn't exist yet:

  1. Go to Cloudflare Dashboard → Pages → Create a project
  2. Select "Direct Upload" (we deploy via GitHub Actions)
  3. Name: lantern-admin-dev (or lantern-admin for prod)
  4. Create project
  5. Go to Custom domains → Add: admin.dev.ourlantern.app

Build Settings (If Using Git Integration)

If you connect via GitHub instead of "Direct Upload", use these settings:

SettingValue
Framework presetVite
Build commandnpm run build
Build output directorydist
Root directoryadmin
Node.js version18 (or 20)

Environment Variables (set in Cloudflare Pages Settings → Environment Variables):

VariableDescription
VITE_FIREBASE_API_KEYFirebase API key
VITE_FIREBASE_AUTH_DOMAINFirebase auth domain
VITE_FIREBASE_PROJECT_IDlantern-app-dev (dev) or lantern-app-prod (prod)
VITE_FIREBASE_STORAGE_BUCKETFirebase storage bucket
VITE_FIREBASE_APP_IDFirebase app ID
VITE_RECAPTCHA_SITE_KEYreCAPTCHA v3 site key for App Check (see Security Considerations)
VITE_APP_ENVdevelopment (dev) or production (prod)

Note: We typically use "Direct Upload" with GitHub Actions for more control over the deploy process. The build settings above are for reference if connecting Cloudflare directly to GitHub.

Manual Build & Deploy

bash
# Build
npm run admin:build

# Deploy (requires wrangler CLI + auth)
npx wrangler pages deploy admin/dist --project-name=lantern-admin-dev

Security Considerations

Firebase App Check (reCAPTCHA v3)

The admin portal uses Firebase App Check with reCAPTCHA v3 to verify that requests to Cloud Functions come from legitimate app instances, not from attackers using stolen API keys.

How It Works

  1. When the admin portal loads, App Check obtains a reCAPTCHA token from Google
  2. This token is automatically attached to all Firebase callable function requests
  3. Cloud Functions verify the token via consumeAppCheckToken: true option
  4. Requests without valid tokens are rejected

reCAPTCHA v3 Setup

Step 1: Create reCAPTCHA Keys

  1. Go to Google reCAPTCHA Admin Console
  2. Click Create (+ icon)
  3. Configure:
    • Label: Lantern Admin Portal
    • reCAPTCHA type: reCAPTCHA v3 (score-based, invisible)
    • Domains: Add all domains where the admin portal runs:
      • localhost
      • web.app (covers Firebase preview URLs like *.web.app)
      • admin.ourlantern.app
      • admin.dev.ourlantern.app
      • ourlantern.app
  4. Accept Terms of Service and click Submit
  5. Copy the Site Key and Secret Key

Step 2: Register App Check Provider in Firebase

  1. Go to Firebase Console → Your Project
  2. Navigate to Build → App Check
  3. Click on your Web app
  4. Select reCAPTCHA v3 as the provider
  5. Paste the Secret Key from Step 1
  6. Click Save

Step 3: Configure Environment Variables

For local development, add to admin/.env.local:

bash
VITE_RECAPTCHA_SITE_KEY=your-recaptcha-site-key-here

For GitHub Actions deployments, add repository secrets:

Secret NameDescription
VITE_RECAPTCHA_SITE_KEY_DEVreCAPTCHA site key for dev environment
VITE_RECAPTCHA_SITE_KEY_PRODreCAPTCHA site key for prod environment

Go to: GitHub → Repository → Settings → Secrets and variables → Actions → New repository secret

Note: You can use the same reCAPTCHA site key for both dev and prod if all domains are registered, or create separate reCAPTCHA entries for each environment.

Verifying App Check is Working

  1. Open browser DevTools → Network tab
  2. Trigger a Cloud Function call (e.g., create admin user)
  3. Look for the request to your function
  4. The request headers should include X-Firebase-AppCheck

If App Check is misconfigured, you'll see errors like:

  • AppCheck: ReCAPTCHA error - Domain not registered in reCAPTCHA console
  • UNAUTHENTICATED - App Check token missing or invalid on server

Cloud Functions Configuration

All admin Cloud Functions have App Check enabled via:

javascript
const callableOptions = {
  cors: [...],
  invoker: 'public',
  consumeAppCheckToken: true  // Requires valid App Check token
};

Access Control

  1. Firebase Auth - User must be signed in to admin portal
  2. Admin Role Check - User must have role: 'admin' in Firestore
  3. GitHub Auth - StackEdit/GitHub.dev use GitHub OAuth
  4. No Public Links - Admin portal is never linked from the main app

Headers & CSP

The admin/public/_headers file sets security headers:

X-Frame-Options: DENY
X-Robots-Tag: noindex, nofollow
Content-Security-Policy: ...

Preventing Public Access

  • Admin portal: X-Robots-Tag: noindex, nofollow
  • Docs editing: Requires GitHub account with repo access
  • No links from main app or public documentation

Troubleshooting

Admin Portal Issues

"Access Denied" even though I'm an admin

Check that your Firestore user document has role: "admin" (exact string match).

Admin portal won't load

  1. Check browser console for errors
  2. Verify Firebase config is correct
  3. Check that the deployment has the right environment variables

StackEdit Issues

Can't connect to GitHub

  1. Make sure you've authorized StackEdit for your GitHub account
  2. Check that your GitHub account has access to the repository
  3. Try unlinking and re-linking your GitHub account

Changes not saving

  1. Make sure you've committed your changes (click the sync icon)
  2. Check that you have write access to the repository
  3. Verify the branch name is correct (dev)

Future Expansion (Phase 3)

The admin dashboard is designed for expansion. Future features may include:

  • 📊 Analytics Dashboard - Firebase Analytics integration
  • 🏪 Merchant Management - View/approve merchant applications
  • 👥 User Management - View, disable, delete users
  • 🔧 System Health - Service status monitoring
  • 💡 Feature Tracker - GitHub issues integration

These features are marked as "Coming Soon" in the dashboard.


Built with VitePress