Memory & Conversations
All MIA-owned data lives in Firebase Realtime Database (RTDB). Firestore is read-only from MIA and used only for integration plugin metadata.
Important framing: the AI's tools mostly don't touch RTDB directly. They HTTP-call internal Firebase Function endpoints (which write to RTDB through the standard module repository layer). The "Owner" column below names the module endpoint, not the tool. See Agent SDK for the architecture.
MIA-owned RTDB paths
| Path | Schema (key fields) | Owner (endpoint) | Read by |
|---|---|---|---|
pivotAiAgentMemory/{cid}/companyProfile | typicalRevenue, laborBudget, peakDays, watchedEmployees, hasPatio, location, notes (keyed object), updatedAt | PATCH /ai-memory/company-profile (ai-memory module) | System prompt builder, fetchCompanyMemoryActivity, update_company_memory tool |
pivotAiAgentRules/{cid}/userRules/{ruleId} | id, rule (text), enabled, createdAt, updatedAt | POST/PATCH/DELETE /ai-memory/user-rules* | System prompt builder, fetchUserRulesActivity, set_user_rule / list_user_rules / delete_user_rule tools |
pivotAiAgentCrons/{cid}/{taskId} | See MIA Task Lifecycle | /ai-memory/cron-tasks* | ai-memory list endpoint, Temporal Scheduler (read at fire time), set_cron_task tool |
AIZackboardSessions/{cid}/{uid}/{sessionId} | messages, widgets, widgetLayouts, suggestions, title, createdAt, updatedAt, tokenUsage, pendingJobId? | saveSession (end of pipeline, in functions/pivotAiAgent/session.ts); frontend also writes widgetLayouts directly on drag/resize | Frontend (session list + resume) |
AiTipsRules/{cid}/{ruleId} | See MIA Tips | /companies/:id/ai-tips-rules* (companies module) | Tip-distribution engine, MIA Tips UI, save_ai_tips_rule family of tools |
AiUsageLogs/{cid}/{day}/{rowId} | ts, provider, model, flow, userId, inputTokens, outputTokens, cacheReadTokens, cacheCreateTokens, totalTokens, costUsd | Written at end of every LLM call by the AI service | /companies/:id/ai-usage admin endpoint |
AiUsageLogs/_onboarding/{day}/{rowId} | Same shape as above | Onboarding-flow LLM calls (before companyId is known) | /ai-usage/onboarding admin endpoint |
Companies/{cid}/aiConfig | { provider, model, updatedAt } | PATCH /companies/:id/ai-config (admin only) | callLlm provider resolution |
GlobalAiConfig | { provider, model, updatedAt } | PATCH /ai-config/global (admin only) | callLlm fallback when no per-company override |
pivotAiAgentUploads/{uploadId} | uploadId, filename, type (csv/image/sheet), mediaType, createdAt, base64 (images) | POST /upload (Cloud Run) | Tool calls referencing uploadId |
AIOnboardingSessions/{userId} | progress checklist, current step, captured config | Admin SDK only (no public endpoint) — written by onboarding tools | get_onboarding_status, complete_onboarding, onboarding pipeline state |
ImportStagingArea/{userId}/* | staged employee imports from CSV / Agendrix / 7shifts | Admin SDK only — written by import_competitor_csv, scrape_* | onboarding pipeline |
Note on direct-RTDB writers: create_shift writes WeeklySchedule/{cid}/{date} directly via Firebase REST (legacy, has TODO to migrate). The onboarding-state paths above (AIOnboardingSessions/, ImportStagingArea/) are intentionally not exposed via the public API.
There is no Companies/{cid}/miaSettings path. Earlier docs referenced it; the codebase has no writers for that path. Per-company AI configuration lives at Companies/{cid}/aiConfig (see above).
Cross-cutting RTDB paths MIA reads (via tools / endpoints)
These are owned by other parts of Pivot but routinely accessed by MIA via the standard endpoints:
| Path | Owning module | Accessed by tool |
|---|---|---|
Companies/{cid} | companies | get_company_info, get_company_settings, get_integration_status |
Users/{uid} | (auth context) | get_current_user |
Employees/{cid}/{eid} | employees | get_employees, find_employee, employee CRUD |
EmployeeRates/{cid}/{eid} | employees (sub-resources) | get_employee_rates |
Attendance/{cid}/{date} | attendance | get_attendance, get_payroll_issues |
WeeklySchedule/{cid}/{date} | schedule | get_schedule, shift CRUD |
Firestore (read-only here)
IntegrationSettings/{docId} — read yes, write no
IntegrationPluginSyncs/{pluginSyncId}/... — read-only
PluginSyncJobs/{jobId} — read-only
PluginSyncSlices/{sliceId} — read-only
(everything else) — deny read, deny write
Rules source: firestore.rules.
PostgreSQL
Migration in progress for non-MIA data. The codebase has @google-cloud/cloud-sql-connector + kysely. Several Pub/Sub triggers (onPublishedSchedulePgSync, onCompanyWritePgSync, etc.) propagate RTDB writes to PG. No MIA-specific PG tables exist yet — usage logs, memory, rules, cron tasks all stay in RTDB.
Conversation history details
Note the collection name: AIZackboardSessions (typo that stuck in source — the backend's older ARCHITECTURE.md says AIDashboardSessions but the actual source-of-truth at functions/pivotAiAgent/session.ts and the frontend both use AIZackboardSessions).
A single session record holds:
{
messages: ChatMessage[], // conversation history
widgets: Widget[], // parsed widget config (see AI Dashboard)
widgetLayouts: PlacedWidget[], // per-widget position + size on the canvas
suggestions: string[], // last suggested follow-ups
title: string, // ~40 chars; derived from first user message
createdAt: number,
updatedAt: number,
tokenUsage: { ... }, // aggregate counters for this session
pendingJobId?: string // present while a pipeline run is still streaming
}
pendingJobId is removed when the run finishes. On session resume, the frontend re-subscribes if pendingJobId exists, so a long-running data-path query can survive a page reload.
Token usage is also rolled up to AiUsageLogs/ per-row for cross-session reporting (see Token & Cost Tracking).