Firebase Cloud Functions API
Backend endpoints for AI processing, video chat, and cloud operations.
Overview
On Book Pro uses Firebase Cloud Functions (2nd gen, Node 24) for server-side operations that require:
- Heavy computation (AI script analysis, SVG generation)
- Secure API keys (Daily.co, Postmark, Vertex AI)
- Admin privileges (Firestore writes)
- Event-driven processing (Storage triggers, Firestore triggers)
Architecture
functions/src/index.ts serves as a thin re-export hub (~67 lines). All business logic lives in domain-specific modules:
functions/src/
├── index.ts # Re-export hub + initializeApp()
├── video-chat.ts # Daily.co room/token management
├── svg-generation.ts # Gemini-powered SVG asset generation
├── cache-utils.ts # Vertex AI context caching + retry logic
├── json-utils.ts # JSON repair + concurrency utilities
├── script-import/
│ ├── types.ts # Shared types, constants, Document AI client
│ ├── storage.ts # GCS persistence helpers
│ ├── ocr-parser.ts # Document AI shard → page parsing
│ ├── process-ocr.ts # startOcrJob, processOcrResult, repairScriptImport
├── debug/
│ ├── test-endpoints.ts # triggerScriptAnalysis, testVertexAI
│ └── test-rate-limits.ts # Rate limit testing utility
├── email/ # 14 email Cloud Functions (see Email API)
├── activity-log-triggers.ts # Firestore onWrite triggers for activity
├── auto-link-invitation.ts # Auto-link invitation on auth
├── attendance-sign-in.ts # recordAttendanceSignIn callable
├── calendar-feed.ts # iCal feed generation
└── cleanup-trashed-files.ts # Scheduled file cleanupDeployment
cd functions
npm run build # Compiles TS + copies prompts to lib/
firebase deploy --only functionsFunctions deploy to: us-central1
Script Import Pipeline
The script import pipeline converts PDF scripts into structured data via Document AI (OCR) and Gemini 2.5 Pro (semantic extraction). For detailed architecture, see Script Ingestion Pipeline.
startOcrJob
Starts Document AI batch processing when a PDF is uploaded with script import metadata.
Type: onObjectFinalized (Storage trigger) Source: functions/src/script-import/process-ocr.ts
Configuration:
region: us-central1
Trigger Condition: File in projects/{projectId}/files/ with metadata isScriptImport: 'true' and .pdf extension.
Flow:
- Validates project exists and
uploadedBymetadata is present - Starts Document AI LRO (Long Running Operation)
- Creates
script_jobsdocument with statusprocessing
processOcrResult
Processes OCR shards with Gemini when Document AI writes output to GCS.
Type: onObjectFinalized (Storage trigger) Source: functions/src/script-import/process-ocr.ts
Configuration:
region: us-central1timeoutSeconds: 540 (9 minutes)memory: 2GiB
Trigger Condition: JSON files written to ocr-results/{projectId}/. Only the coordinator shard (suffix -0.json) proceeds.
Flow:
- Polls Document AI operation status until complete (up to 5 min)
- Discovers and downloads all shards with retry for GCS eventual consistency
- Creates Vertex AI context cache with full OCR text
- Phase 1: Extracts script blocks in parallel 5-page batches (concurrency limit 3)
- Phase 2: Extracts structure, props, and sound cues sequentially
- Saves all results to GCS as JSON artifacts
- Updates
script_jobsstatus tocompletedorpartial - Cleans up context cache
Progress Reporting: The pipeline writes granular milestones to the script_jobs Firestore doc at each stage (OCR complete, batch N/M, extracting structure, saving results), enabling real-time UI feedback.
repairScriptImport
Re-runs only the failed batches from a partial import.
Type: onCallSource: functions/src/script-import/process-ocr.ts
Configuration:
region: us-central1timeoutSeconds: 540memory: 2GiB
Request:
{
projectId: string;
jobId: string;
}Response:
{
success: boolean;
repairedBatches: number;
stillFailed: number;
totalBlocks: number;
}Error Codes:
unauthenticated— User not signed innot-found— Job not foundpermission-denied— User doesn't own this jobfailed-precondition— No failed batches or job not inpartialstatus
SVG Generation
generateSvgAsset
Generates a top-down architectural SVG asset for the Set Builder using AI. Includes a global Firestore cache to avoid redundant generations.
Type: onCallSource: functions/src/svg-generation.ts
Configuration:
timeoutSeconds: 60memory: 512MiB
Request:
{
prompt: string; // e.g., "blue victorian sofa"
}Response:
{
id: string;
prompt: string;
svgCode: string; // SVG markup
createdAt: string;
source: 'cache' | 'generated';
}Example:
const generateAsset = httpsCallable(functions, 'generateSvgAsset');
const result = await generateAsset({
prompt: 'blue victorian sofa'
});
// result.data.svgCode contains the SVG code
// result.data.source indicates if it came from cacheVideo Chat
createDailyRoom
Creates a Daily.co video room for a project.
Type: onCallSource: functions/src/video-chat.tsSecret: DAILY_API_KEY
Request:
{
projectId: string;
}Response:
{
roomUrl: string;
roomName: string;
expiresAt: string; // ISO timestamp (2 hours from creation)
}Permissions: Requires owner, stage_manager, or production_manager role.
getDailyToken
Generates a meeting token for a participant to join a Daily room.
Type: onCallSource: functions/src/video-chat.tsSecret: DAILY_API_KEY
Request:
{
roomName: string;
userName?: string;
}Response:
{
token: string;
}Email Distribution Functions
For complete documentation of all email Cloud Functions (8 manual + 6 automated), see the dedicated Email API reference.
Quick Summary:
- 8 Manual Functions (
onCall):sendCallSheet,sendRehearsalReport,sendLineNotes,sendDeadlinePing,sendMeetingInvites,sendProjectInvite,sendCustomAnnouncement,sendBatchInvitations - 6 Automated Functions (Firestore/CRON triggers):
notifyWelcome,notifyScheduleChange,notifyDeadlineApproaching,notifyProfileReminder,notifyMentionPost,notifyMentionComment - Shared module:
functions/src/email/postmark-client.ts - Secret:
POSTMARK_SERVER_TOKEN
Attendance
recordAttendanceSignIn
Records an actor's attendance sign-in for a scheduled event. Validates the sign-in token server-side, determines present/late status based on a 30-minute window, and writes to the Firestore attendance subcollection using the Admin SDK.
Type: onCallSource: functions/src/attendance-sign-in.ts
Request:
{
projectId: string;
token: string; // Sign-in token from QR code / link
actorId: string; // ID of the actor signing in
}Response:
{
status: 'present' | 'late'; // Determined by 30-min window
signedInAt: string; // ISO timestamp
}Error Codes:
invalid-argument— Missing required fieldsnot-found— Invalid token or event not foundfailed-precondition— Sign-in window expiredalready-exists— Actor already signed in for this event
Notes: This function does not require Firebase Auth — it validates via the sign-in token, allowing unauthenticated actors to sign in via QR code link. The function uses the Admin SDK to bypass Firestore security rules.
Utility Functions
File Cleanup
| Function | Type | Description |
|---|---|---|
cleanupOldTrashedFiles | onSchedule | Scheduled cleanup of trashed files |
manualCleanupTrashedFiles | onCall | Manual trigger for file cleanup |
Source: functions/src/cleanup-trashed-files.ts
Calendar
| Function | Type | Description |
|---|---|---|
getCalendarFeed | onRequest | Generates iCal feed for a project |
Source: functions/src/calendar-feed.ts
Activity Log Triggers
| Function | Type | Description |
|---|---|---|
logPropActivity | onDocumentWritten | Tracks prop changes |
logCostumeActivity | onDocumentWritten | Tracks costume changes |
logBlockingActivity | onDocumentWritten | Tracks blocking changes |
logScheduleActivity | onDocumentWritten | Tracks schedule changes |
logActActivity | onDocumentWritten | Tracks act changes |
logSceneActivity | onDocumentWritten | Tracks scene changes |
logCharacterActivity | onDocumentWritten | Tracks character changes |
Source: functions/src/activity-log-triggers.ts
Invitations
| Function | Type | Description |
|---|---|---|
autoLinkInvitation | onDocumentCreated | Auto-links invitation when user signs up |
Source: functions/src/auto-link-invitation.ts
Debug / Test
| Function | Type | Description |
|---|---|---|
triggerScriptAnalysis | onRequest | Re-triggers script analysis for an existing file |
testVertexAI | onRequest | Tests Vertex AI connectivity |
Source: functions/src/debug/test-endpoints.ts
Testing Locally
Emulator Setup
# Install Firebase emulators
firebase init emulators
# Start emulators
firebase emulators:startConnect Client to Emulator
// src/config/firebase.ts
if (import.meta.env.DEV) {
connectFunctionsEmulator(functions, 'localhost', 5001);
}Authentication
All onCall functions require Firebase Auth:
import { onCall, HttpsError } from 'firebase-functions/v2/https';
export const myFunction = onCall(async (request) => {
// Check authentication
if (!request.auth) {
throw new HttpsError('unauthenticated', 'User must be signed in');
}
const userId = request.auth.uid;
// ... function logic
});Security Best Practices
1. Validate Input
if (!request.data.projectId || typeof request.data.projectId !== 'string') {
throw new HttpsError('invalid-argument', 'projectId is required');
}2. Check Permissions
// Verify user has project access
const memberDoc = await db
.collection('projects').doc(projectId)
.collection('members').doc(request.auth.uid)
.get();
if (!memberDoc.exists) {
throw new HttpsError('permission-denied', 'User is not a project member');
}Monitoring
Cloud Functions Logs
# View all logs
firebase functions:log
# Filter by function
firebase functions:log --only processOcrResult
firebase functions:log --only generateSvgAssetError Reporting
import * as logger from 'firebase-functions/logger';
export const myFunction = onCall(async (request) => {
try {
// ... logic
} catch (error) {
logger.error('Function failed', { error, userId: request.auth?.uid });
throw new HttpsError('internal', 'An error occurred');
}
});Further Reading
- Firebase Cloud Functions Documentation
- Callable Functions Guide
- Script Ingestion Pipeline Architecture
- Email API Reference
Last updated: February 12, 2026 (Added recordAttendanceSignIn Cloud Function)