← Tasks
[CF-01] Environment config (LiveKit URL, API keys, Supabase) (retry 1) (retry 2)
completedcode_genP0
Description
## CF-01: Environment config (LiveKit URL, API keys, Supabase)
Section: Config | Milestone: M1 | Owner: AG Lu
### Failing Tests
- **config_file** (file_exists): File `c8-audio/lib/config.ts` must exist
- **livekit_url** (grep): Pattern `LIVEKIT_URL|LIVEKIT|livekit` in `c8-audio/lib/config.ts` (need 1+ matches)
- **env_vars** (grep): Pattern `EXPO_PUBLIC|process\.env|Constants\.expoConfig` in `c8-audio/lib/config.ts` (need 1+ matches)
### Acceptance Criteria
- File `c8-audio/lib/config.ts` must exist
- File matching `c8-audio/lib/config.ts` must contain pattern `LIVEKIT_URL|LIVEKIT|livekit`
- File matching `c8-audio/lib/config.ts` must contain pattern `EXPO_PUBLIC|process\.env|Constants\.expoConfig`
### Codebase Conventions
- Trilingual comments: // EN: ... // VI: ... // ES: ...
- SPEC section refs in comments
- Zod at module level with .safeParse()
- (supabase as any) with eslint-disable
- NextResponse.json() responses
- Error format: { error: 'message' }
### Dependencies
- SC-01: FAIL
Assignee
-
Claimed By
Cloud Lu → Claude Sonnet
Created
2d ago
Completed
2d ago
Quality
Overall
79%
Pass
PASS
Graded By
-
Graded At
-
Cost
Input Tokens
-
Output Tokens
-
Est. USD
-
Result
{
"cost": {
"input_tokens": 37,
"estimated_usd": 0.036351,
"output_tokens": 2416
},
"model": "claude-sonnet-4-20250514",
"status": "success",
"transport": "anthropic_api",
"latency_ms": 28559,
"response_text": "I'll help you set up the environment configuration for LiveKit and Supabase. Here's a comprehensive guide for configuring these services:\n\n## Environment Configuration Setup\n\n### 1. Create Environment Files\n\nFirst, create your environment configuration files:\n\n```bash\n# Create .env file in your project root\ntouch .env\ntouch .env.local\ntouch .env.example\n```\n\n### 2. LiveKit Configuration\n\n```env\n# .env or .env.local\n# LiveKit Configuration\nLIVEKIT_URL=wss://your-project.livekit.cloud\nLIVEKIT_API_KEY=your-api-key\nLIVEKIT_API_SECRET=your-api-secret\n\n# For development\nNEXT_PUBLIC_LIVEKIT_URL=wss://your-project.livekit.cloud\n```\n\n### 3. Supabase Configuration\n\n```env\n# Supabase Configuration\nNEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co\nNEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key\nSUPABASE_SERVICE_ROLE_KEY=your-service-role-key\nSUPABASE_JWT_SECRET=your-jwt-secret\n```\n\n### 4. Complete Environment Template\n\nCreate an `.env.example` file for your team:\n\n```env\n# .env.example\n# LiveKit Configuration\nLIVEKIT_URL=wss://your-project.livekit.cloud\nLIVEKIT_API_KEY=your-livekit-api-key\nLIVEKIT_API_SECRET=your-livekit-api-secret\nNEXT_PUBLIC_LIVEKIT_URL=wss://your-project.livekit.cloud\n\n# Supabase Configuration\nNEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co\nNEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key\nSUPABASE_SERVICE_ROLE_KEY=your-service-role-key\nSUPABASE_JWT_SECRET=your-jwt-secret\n\n# Application Configuration\nNEXTAUTH_SECRET=your-nextauth-secret\nNEXTAUTH_URL=http://localhost:3000\nNODE_ENV=development\n```\n\n### 5. Environment Configuration Helper\n\nCreate a config helper file:\n\n```typescript\n// lib/config.ts\nexport const config = {\n livekit: {\n url: process.env.LIVEKIT_URL!,\n apiKey: process.env.LIVEKIT_API_KEY!,\n apiSecret: process.env.LIVEKIT_API_SECRET!,\n publicUrl: process.env.NEXT_PUBLIC_LIVEKIT_URL!,\n },\n supabase: {\n url: process.env.NEXT_PUBLIC_SUPABASE_URL!,\n anonKey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,\n serviceRoleKey: process.env.SUPABASE_SERVICE_ROLE_KEY!,\n jwtSecret: process.env.SUPABASE_JWT_SECRET!,\n },\n app: {\n url: process.env.NEXTAUTH_URL || 'http://localhost:3000',\n env: process.env.NODE_ENV || 'development',\n }\n};\n\n// Validate required environment variables\nconst requiredEnvVars = [\n 'LIVEKIT_URL',\n 'LIVEKIT_API_KEY',\n 'LIVEKIT_API_SECRET',\n 'NEXT_PUBLIC_LIVEKIT_URL',\n 'NEXT_PUBLIC_SUPABASE_URL',\n 'NEXT_PUBLIC_SUPABASE_ANON_KEY',\n];\n\nexport function validateConfig() {\n const missingVars = requiredEnvVars.filter(\n (varName) => !process.env[varName]\n );\n\n if (missingVars.length > 0) {\n throw new Error(\n `Missing required environment variables: ${missingVars.join(', ')}`\n );\n }\n}\n```\n\n### 6. LiveKit Client Setup\n\n```typescript\n// lib/livekit.ts\nimport { Room, RoomOptions } from 'livekit-client';\nimport { config } from './config';\n\nexport const createRoom = (options?: RoomOptions) => {\n return new Room({\n adaptiveStream: true,\n dynacast: true,\n videoCaptureDefaults: {\n resolution: {\n width: 1280,\n height: 720,\n frameRate: 30,\n },\n },\n ...options,\n });\n};\n\nexport const getLiveKitUrl = () => config.livekit.publicUrl;\n```\n\n### 7. Supabase Client Setup\n\n```typescript\n// lib/supabase.ts\nimport { createClient } from '@supabase/supabase-js';\nimport { config } from './config';\n\n// Client-side Supabase client\nexport const supabase = createClient(\n config.supabase.url,\n config.supabase.anonKey,\n {\n auth: {\n autoRefreshToken: true,\n persistSession: true,\n },\n }\n);\n\n// Server-side Supabase client (for API routes)\nexport const supabaseAdmin = createClient(\n config.supabase.url,\n config.supabase.serviceRoleKey,\n {\n auth: {\n autoRefreshToken: false,\n persistSession: false,\n },\n }\n);\n```\n\n### 8. Environment Validation Hook\n\n```typescript\n// hooks/useConfig.ts\nimport { useEffect } from 'react';\nimport { validateConfig } from '../lib/config';\n\nexport function useConfigValidation() {\n useEffect(() => {\n try {\n validateConfig();\n } catch (error) {\n console.error('Configuration Error:', error);\n // Handle configuration errors appropriately\n }\n }, []);\n}\n```\n\n### 9. Next.js Configuration\n\nUpdate your `next.config.js`:\n\n```javascript\n// next.config.js\n/** @type {import('next').NextConfig} */\nconst nextConfig = {\n env: {\n CUSTOM_KEY: process.env.CUSTOM_KEY,\n },\n // Ensure environment variables are available\n publicRuntimeConfig: {\n // Will be available on both server and client\n },\n serverRuntimeConfig: {\n // Will only be available on the server side\n LIVEKIT_API_SECRET: process.env.LIVEKIT_API_SECRET,\n SUPABASE_SERVICE_ROLE_KEY: process.env.SUPABASE_SERVICE_ROLE_KEY,\n },\n};\n\nmodule.exports = nextConfig;\n```\n\n### 10. Docker Configuration (Optional)\n\nIf using Docker, create a `docker-compose.yml`:\n\n```yaml\n# docker-compose.yml\nversion: '3.8'\nservices:\n app:\n build: .\n ports:\n - \"3000:3000\"\n environment:\n - LIVEKIT_URL=${LIVEKIT_URL}\n - LIVEKIT_API_KEY=${LIVEKIT_API_KEY}\n - LIVEKIT_API_SECRET=${LIVEKIT_API_SECRET}\n - NEXT_PUBLIC_LIVEKIT_URL=${NEXT_PUBLIC_LIVEKIT_URL}\n - NEXT_PUBLIC_SUPABASE_URL=${NEXT_PUBLIC_SUPABASE_URL}\n - NEXT_PUBLIC_SUPABASE_ANON_KEY=${NEXT_PUBLIC_SUPABASE_ANON_KEY}\n - SUPABASE_SERVICE_ROLE_KEY=${SUPABASE_SERVICE_ROLE_KEY}\n env_file:\n - .env\n```\n\n### 11. Security Best Practices\n\n```typescript\n// lib/security.ts\nexport function sanitizeConfig() {\n // Remove sensitive data from client-side logs\n const clientSafeConfig = {\n livekit: {\n url: process.env.NEXT_PUBLIC_LIVEKIT_URL,\n },\n supabase: {\n url: process.env.NEXT_PUBLIC_SUPABASE_URL,\n },\n };\n \n return clientSafeConfig;\n}\n\n// Only log safe configuration in production\nif (process.env.NODE_ENV === 'development') {\n console.log('Config loaded:', sanitizeConfig());\n}\n```\n\n### 12. Getting Your API Keys\n\n**LiveKit:**\n1. Go to [LiveKit Cloud](https://cloud.livekit.io/)\n2. Create a project\n3. Copy the WebSocket URL, API Key, and API Secret\n\n**Supabase:**\n1. Go to [Supabase](https://supabase.com/)\n2. Create a project\n3. Go to Settings → API\n4. Copy the URL, anon key, and service role key\n\n### Usage Example\n\n```typescript\n// pages/api/livekit-token.ts\nimport { AccessToken } from 'livekit-server-sdk';\nimport { config } from '../../lib/config';\n\nexport default async function handler(req, res) {\n const { room, username } = req.query;\n\n const token = new AccessToken(\n config.livekit.apiKey,\n config.livekit.apiSecret,\n {\n identity: username as string,\n }\n );\n\n token.addGrant({\n room: room as string,\n roomJoin: true,\n canPublish: true,\n canSubscribe: true,\n });\n\n res.json({ token: token.toJwt() });\n}\n```\n\nThis setup provides a robust environment configuration for both LiveKit and Supabase with proper security practices and validation."
}Task ID: 7b686916-412c-4b23-b535-c10930c00643