VIBN Frontend for Coolify deployment
This commit is contained in:
216
firestore.rules
Normal file
216
firestore.rules
Normal file
@@ -0,0 +1,216 @@
|
||||
rules_version = '2';
|
||||
|
||||
service cloud.firestore {
|
||||
match /databases/{database}/documents {
|
||||
|
||||
// Helper functions
|
||||
function isAuthenticated() {
|
||||
return request.auth != null;
|
||||
}
|
||||
|
||||
function isOwner(userId) {
|
||||
return isAuthenticated() && request.auth.uid == userId;
|
||||
}
|
||||
|
||||
// Users collection
|
||||
match /users/{userId} {
|
||||
// Users can read their own data
|
||||
allow read: if isOwner(userId);
|
||||
// Users can create their own user document
|
||||
allow create: if isOwner(userId);
|
||||
// Users can update their own data
|
||||
allow update: if isOwner(userId);
|
||||
// No deletes for now
|
||||
allow delete: if false;
|
||||
}
|
||||
|
||||
// API Keys collection
|
||||
match /apiKeys/{keyId} {
|
||||
// Only the server can create/read API keys (via Admin SDK)
|
||||
// Users cannot directly access API key documents
|
||||
allow read, write: if false;
|
||||
}
|
||||
|
||||
// MCP API Keys collection
|
||||
match /mcpKeys/{keyId} {
|
||||
// Only the server can create/read/delete MCP keys (via Admin SDK)
|
||||
// Users cannot directly access MCP key documents
|
||||
allow read, write: if false;
|
||||
}
|
||||
|
||||
// Projects collection
|
||||
match /projects/{projectId} {
|
||||
// Users can read their own projects
|
||||
allow read: if isAuthenticated() && resource.data.userId == request.auth.uid;
|
||||
// Users can create projects
|
||||
allow create: if isAuthenticated() && request.resource.data.userId == request.auth.uid;
|
||||
// Users can update their own projects
|
||||
allow update: if isAuthenticated() && resource.data.userId == request.auth.uid;
|
||||
// Users can delete their own projects
|
||||
allow delete: if isAuthenticated() && resource.data.userId == request.auth.uid;
|
||||
|
||||
// AI Conversations subcollection
|
||||
match /aiConversations/{conversationId} {
|
||||
// Users can read conversations for their projects
|
||||
allow read: if isAuthenticated() &&
|
||||
get(/databases/$(database)/documents/projects/$(projectId)).data.userId == request.auth.uid;
|
||||
// Server creates conversation entries via Admin SDK
|
||||
allow create: if false; // Only server via Admin SDK
|
||||
// No updates to conversation history (immutable)
|
||||
allow update: if false;
|
||||
// No deletes (audit trail)
|
||||
allow delete: if false;
|
||||
}
|
||||
|
||||
// Vision Board subcollection
|
||||
match /visionBoard/{visionDocId} {
|
||||
// Users can read/write vision board for their projects
|
||||
allow read, write: if isAuthenticated() &&
|
||||
get(/databases/$(database)/documents/projects/$(projectId)).data.userId == request.auth.uid;
|
||||
}
|
||||
|
||||
// Context Sources subcollection (for chat content, files, etc.)
|
||||
match /contextSources/{sourceId} {
|
||||
// Users can read/write context sources for their projects
|
||||
allow read, write: if isAuthenticated() &&
|
||||
get(/databases/$(database)/documents/projects/$(projectId)).data.userId == request.auth.uid;
|
||||
}
|
||||
}
|
||||
|
||||
// Sessions collection
|
||||
match /sessions/{sessionId} {
|
||||
// Users can read their own sessions (by userId or by projectId they own)
|
||||
allow read: if isAuthenticated() && (
|
||||
resource.data.userId == request.auth.uid ||
|
||||
(resource.data.projectId != null &&
|
||||
get(/databases/$(database)/documents/projects/$(resource.data.projectId)).data.userId == request.auth.uid)
|
||||
);
|
||||
// Sessions are created by the server via API (Admin SDK)
|
||||
allow create: if false; // Only server via Admin SDK
|
||||
// Users can update their own sessions
|
||||
allow update: if isAuthenticated() && resource.data.userId == request.auth.uid;
|
||||
// No deletes for sessions (audit trail)
|
||||
allow delete: if false;
|
||||
}
|
||||
|
||||
// Analyses collection
|
||||
match /analyses/{analysisId} {
|
||||
// Users can read analyses for their projects
|
||||
// Note: This requires fetching the project document to verify ownership
|
||||
allow read: if isAuthenticated() &&
|
||||
get(/databases/$(database)/documents/projects/$(resource.data.projectId)).data.userId == request.auth.uid;
|
||||
// Users can create analyses for their projects
|
||||
allow create: if isAuthenticated() &&
|
||||
get(/databases/$(database)/documents/projects/$(request.resource.data.projectId)).data.userId == request.auth.uid;
|
||||
// Users can update analyses for their projects
|
||||
allow update: if isAuthenticated() &&
|
||||
get(/databases/$(database)/documents/projects/$(resource.data.projectId)).data.userId == request.auth.uid;
|
||||
// No deletes for analyses (audit trail)
|
||||
allow delete: if false;
|
||||
}
|
||||
|
||||
// Work Completed collection
|
||||
match /workCompleted/{workId} {
|
||||
// Users can read work completed for their projects
|
||||
allow read: if isAuthenticated() &&
|
||||
get(/databases/$(database)/documents/projects/$(resource.data.projectId)).data.userId == request.auth.uid;
|
||||
// Server creates work completed entries
|
||||
allow create: if false; // Only server via Admin SDK
|
||||
// Users can update work completed for their projects
|
||||
allow update: if isAuthenticated() &&
|
||||
get(/databases/$(database)/documents/projects/$(resource.data.projectId)).data.userId == request.auth.uid;
|
||||
// No deletes
|
||||
allow delete: if false;
|
||||
}
|
||||
|
||||
// Clients collection
|
||||
match /clients/{clientId} {
|
||||
// Users can read their own clients
|
||||
allow read: if isAuthenticated() && resource.data.ownerId == request.auth.uid;
|
||||
// Users can create clients
|
||||
allow create: if isAuthenticated() && request.resource.data.ownerId == request.auth.uid;
|
||||
// Users can update their own clients
|
||||
allow update: if isAuthenticated() && resource.data.ownerId == request.auth.uid;
|
||||
// Users can delete their own clients
|
||||
allow delete: if isAuthenticated() && resource.data.ownerId == request.auth.uid;
|
||||
}
|
||||
|
||||
// ChatGPT Imports collection
|
||||
match /chatgptImports/{importId} {
|
||||
// Users can read their own imports
|
||||
allow read: if isAuthenticated() && resource.data.userId == request.auth.uid;
|
||||
// Server creates imports via Admin SDK
|
||||
allow create: if false; // Only server via Admin SDK
|
||||
// Users can update their own imports (e.g., add notes)
|
||||
allow update: if isAuthenticated() && resource.data.userId == request.auth.uid;
|
||||
// Users can delete their own imports
|
||||
allow delete: if isAuthenticated() && resource.data.userId == request.auth.uid;
|
||||
}
|
||||
|
||||
// User API Keys collection (third-party keys like OpenAI, GitHub)
|
||||
match /userKeys/{keyId} {
|
||||
// Only server can access keys (via Admin SDK)
|
||||
// Keys are encrypted and should never be directly accessible to clients
|
||||
allow read, write: if false;
|
||||
}
|
||||
|
||||
// Knowledge Items collection (documents, notes, chat imports)
|
||||
match /knowledge_items/{itemId} {
|
||||
// Users can read knowledge items for their projects
|
||||
allow read: if isAuthenticated() &&
|
||||
get(/databases/$(database)/documents/projects/$(resource.data.projectId)).data.userId == request.auth.uid;
|
||||
// Server creates knowledge items via Admin SDK
|
||||
allow create: if false; // Only server via Admin SDK
|
||||
// No updates or deletes (immutable)
|
||||
allow update, delete: if false;
|
||||
}
|
||||
|
||||
// Chat Extractions collection (AI-extracted insights)
|
||||
match /chat_extractions/{extractionId} {
|
||||
// Users can read extractions for their projects
|
||||
allow read: if isAuthenticated() &&
|
||||
get(/databases/$(database)/documents/projects/$(resource.data.projectId)).data.userId == request.auth.uid;
|
||||
// Server creates extractions via Admin SDK
|
||||
allow create: if false; // Only server via Admin SDK
|
||||
// No updates or deletes (immutable)
|
||||
allow update, delete: if false;
|
||||
}
|
||||
|
||||
// Chat Conversations collection (conversation history)
|
||||
match /chat_conversations/{conversationId} {
|
||||
// Users can read conversations for their projects
|
||||
allow read: if isAuthenticated() &&
|
||||
get(/databases/$(database)/documents/projects/$(resource.data.projectId)).data.userId == request.auth.uid;
|
||||
// Server creates and updates conversations via Admin SDK
|
||||
allow create, update: if false; // Only server via Admin SDK
|
||||
// No deletes (audit trail)
|
||||
allow delete: if false;
|
||||
}
|
||||
|
||||
// GitHub Connections collection (OAuth tokens and profile)
|
||||
match /githubConnections/{connectionId} {
|
||||
// Users can read their own GitHub connections
|
||||
allow read: if isAuthenticated() && resource.data.userId == request.auth.uid;
|
||||
// Server creates connections via OAuth callback
|
||||
allow create: if false; // Only server via Admin SDK
|
||||
// Users cannot update or delete (managed by server)
|
||||
allow update, delete: if false;
|
||||
}
|
||||
|
||||
// Linked Extensions collection (browser extension connections)
|
||||
match /linkedExtensions/{linkId} {
|
||||
// Users can read their own extension links
|
||||
allow read: if isAuthenticated() && resource.data.userId == request.auth.uid;
|
||||
// Server creates links via API
|
||||
allow create: if false; // Only server via Admin SDK
|
||||
// No updates or deletes
|
||||
allow update, delete: if false;
|
||||
}
|
||||
|
||||
// Default deny all other access
|
||||
match /{document=**} {
|
||||
allow read, write: if false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user