Director Service Quick Start Guide
Created: Tue 29 Jul 2025 07:50:45 CEST
Document Version: 1.0 - MVP implementation guide
Security Classification: Internal Technical Documentation
Target Audience: Developers implementing the Director service
Author: Paul Wisén
🚀 From Zero to Working Edge Function
This guide provides step-by-step instructions to get s.plings.io operational as quickly as possible.
Step 1: Create GitHub Repository
# Create new repository (do this on GitHub.com)
Repository name: Plings-Director
Description: Edge server for QR/NFC scanning and routing
Private/Public: Your choice
Initialize with: README.md, .gitignore (Node), No license yet
# Clone locally
git clone https://github.com/[your-org]/Plings-Director.git
cd Plings-Director
Step 2: Initialize Vercel Edge Functions Project
# Initialize npm project
npm init -y
# Install dependencies
npm install --save-dev @vercel/node typescript @types/node
npm install --save-dev vitest @vitest/ui
# Create TypeScript config
cat > tsconfig.json << 'EOF'
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["ES2020"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"moduleResolution": "node",
"outDir": "./dist",
"rootDir": "./",
"declaration": true,
"declarationMap": true
},
"include": ["api/**/*", "lib/**/*", "types/**/*"],
"exclude": ["node_modules", "dist"]
}
EOF
Step 3: Create Basic Project Structure
# Create directories
mkdir -p api lib types tests
# Create .gitignore
cat > .gitignore << 'EOF'
node_modules/
.env
.env.local
.vercel
dist/
*.log
.DS_Store
EOF
# Create minimal edge function
cat > api/index.ts << 'EOF'
export const config = {
runtime: 'edge',
};
export default async function handler(request: Request): Promise<Response> {
const url = new URL(request.url);
// Extract parameters
const params = {
t: url.searchParams.get('t'), // Tag type (q/n/r)
i: url.searchParams.get('i'), // Instance key
p: url.searchParams.get('p'), // Path
cp: url.searchParams.get('cp'), // Class pointer (optional)
};
// Basic validation
if (!params.t || !params.i || !params.p) {
return Response.redirect('https://plings.io/error/invalid-scan', 302);
}
// For now, redirect all scans to main app
const targetUrl = new URL('https://plings.io/welcome');
targetUrl.searchParams.set('ikey', params.i);
targetUrl.searchParams.set('path', params.p);
targetUrl.searchParams.set('src', 'scan');
return Response.redirect(targetUrl.toString(), 302);
}
EOF
Step 4: Create Vercel Configuration
# Create vercel.json
cat > vercel.json << 'EOF'
{
"name": "plings-director",
"functions": {
"api/index.ts": {
"runtime": "edge",
"maxDuration": 5
}
},
"rewrites": [
{
"source": "/(.*)",
"destination": "/api/index"
}
]
}
EOF
Step 5: Deploy to Vercel
# Install Vercel CLI globally if not already installed
npm install -g vercel
# Login to Vercel
vercel login
# Deploy (first time - follow prompts)
vercel
# When prompted:
# - Set up and deploy: Y
# - Which scope: [Select your team/account]
# - Link to existing project: N
# - Project name: plings-director
# - Directory: ./
# - Override settings: N
Step 6: Link s.plings.io Domain
# Add domain to project
vercel domains add s.plings.io
# Or do this in Vercel Dashboard:
# 1. Go to project settings
# 2. Navigate to Domains
# 3. Add s.plings.io
# 4. Follow DNS configuration instructions
Step 7: Test Basic Functionality
# Test locally first
vercel dev
# Open browser to: http://localhost:3000?t=q&i=TEST123&p=1.1.1
# Test production after DNS propagates
curl -I "https://s.plings.io?t=q&i=TEST123&p=1.1.1"
# Should return 302 redirect to https://plings.io/welcome
Step 8: Add MVP Routing Logic
Update api/index.ts with basic routing:
import { validateParams } from '../lib/validation';
import { determineRoute } from '../lib/routing';
export const config = {
runtime: 'edge',
};
export default async function handler(request: Request): Promise<Response> {
try {
const url = new URL(request.url);
// Extract parameters
const params = {
t: url.searchParams.get('t'),
i: url.searchParams.get('i'),
p: url.searchParams.get('p'),
cp: url.searchParams.get('cp'),
};
// Validate
if (!validateParams(params)) {
return Response.redirect('https://plings.io/error/invalid-scan', 302);
}
// Determine route (MVP: all go to welcome for now)
const targetUrl = await determineRoute(params);
return Response.redirect(targetUrl, 302);
} catch (error) {
console.error('Director error:', error);
return Response.redirect('https://plings.io/error/system', 302);
}
}
Create lib/validation.ts:
export function validateParams(params: any): boolean {
// Required parameters
if (!params.t || !params.i || !params.p) return false;
// Type validation
if (!['q', 'n', 'r'].includes(params.t)) return false;
// Basic format validation (can enhance later)
if (params.i.length < 20 || params.i.length > 48) return false;
return true;
}
Create lib/routing.ts:
interface RouteParams {
t: string;
i: string;
p: string;
cp?: string;
}
export async function determineRoute(params: RouteParams): Promise<string> {
// MVP: Simple routing logic
const baseUrl = 'https://plings.io';
// Build target URL with parameters
const url = new URL(`${baseUrl}/welcome`);
url.searchParams.set('ikey', params.i);
url.searchParams.set('path', params.p);
url.searchParams.set('src', 'scan');
if (params.cp) {
url.searchParams.set('cptr', params.cp);
}
return url.toString();
}
Step 9: Deploy MVP
# Deploy updated version
vercel --prod
# Your edge function is now live at s.plings.io!
Next Steps (Priority Order)
- Add Plings public key verification (See director-system-overview.md)
- Implement resolveIdentifier API call to check if objects exist
- Add proper routing logic for different object states
- Set up monitoring (Vercel Analytics or custom)
- Add rate limiting with Upstash Redis
- Implement scan event logging
Environment Variables (Add via Vercel Dashboard)
# Minimal MVP variables
PLINGS_API_ENDPOINT=https://api.plings.io/graphql
PLINGS_PUBLIC_KEY=[Base58 encoded public key]
# Add more as you implement features
Testing QR Codes
Generate test QR codes at: https://qr-code-generator.com/
Example URL to encode:
https://s.plings.io?t=q&i=4kyQCd5tMDjJVWJH5h95gUcjq3qTX2cj5nwjVyqBRwLo&p=2.1.1.1.1
🎉 Congratulations! You now have a working edge function at s.plings.io that can handle QR scans and redirect users. This MVP can be enhanced incrementally following the todo list.