ByteBrief / docs /backend.json
Gigishot's picture
Upload 2 files
6182c14 verified
Raw
History Blame Contribute Delete
11.8 kB
{
"entities": {
"User": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "User",
"type": "object",
"description": "Represents an individual user of the ByteBrief application, managing their uploaded documents and generated summaries. User authentication details are handled by an external system, with only non-sensitive profile information stored here.",
"properties": {
"id": {
"type": "string",
"description": "Unique identifier for the User entity."
},
"email": {
"type": "string",
"description": "The primary email address of the user, used for identification within the application.",
"format": "email"
},
"firstName": {
"type": "string",
"description": "The first name of the user."
},
"lastName": {
"type": "string",
"description": "The last name of the user."
},
"createdAt": {
"type": "string",
"description": "Timestamp indicating when the user account was created.",
"format": "date-time"
},
"updatedAt": {
"type": "string",
"description": "Timestamp indicating when the user account was last updated.",
"format": "date-time"
}
},
"required": [
"id",
"email",
"firstName",
"lastName",
"createdAt",
"updatedAt"
]
},
"Document": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Document",
"type": "object",
"description": "Represents a document or file uploaded by a user for summarization, securely stored in a cloud-based storage solution.",
"properties": {
"id": {
"type": "string",
"description": "Unique identifier for the Document entity."
},
"userId": {
"type": "string",
"description": "Reference to the User who uploaded this document. (Relationship: User 1:N Document)"
},
"fileName": {
"type": "string",
"description": "The original name of the file when it was uploaded by the user."
},
"cloudStoragePath": {
"type": "string",
"description": "The unique path or key identifying the document's location within the cloud storage system (e.g., S3 object key, Blob storage path)."
},
"fileType": {
"type": "string",
"description": "The MIME type or file extension of the uploaded document (e.g., 'application/pdf', 'text/plain', 'image/jpeg')."
},
"fileSize": {
"type": "number",
"description": "The size of the document in bytes."
},
"uploadDate": {
"type": "string",
"description": "Timestamp indicating when the document was uploaded by the user.",
"format": "date-time"
},
"status": {
"type": "string",
"description": "The current processing status of the document (e.g., 'uploaded', 'processing', 'summarized', 'failed', 'deleted')."
},
"content": {
"type": "string",
"description": "The full text content of the document."
},
"originalContentHash": {
"type": "string",
"description": "A cryptographic hash (e.g., SHA256) of the document's content, useful for integrity checks or duplicate detection."
}
},
"required": [
"id",
"userId",
"fileName",
"fileType",
"fileSize",
"uploadDate",
"status"
]
},
"Summary": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Summary",
"type": "object",
"description": "Represents an AI-generated summary of a specific document, linked to the original document and the owning user.",
"properties": {
"id": {
"type": "string",
"description": "Unique identifier for the Summary entity."
},
"documentId": {
"type": "string",
"description": "Reference to the Document for which this summary was generated. (Relationship: Document 1:N Summary)"
},
"userId": {
"type": "string",
"description": "Reference to the User who owns this summary (derived from the document's owner). (Relationship: User 1:N Summary)"
},
"summaryText": {
"type": "string",
"description": "The actual text content of the AI-generated summary."
},
"summaryLength": {
"type": "string",
"description": "Describes the intended length or verbosity of the summary (e.g., 'concise', 'detailed', 'keypoints')."
},
"generatedAt": {
"type": "string",
"description": "Timestamp indicating when the summary was generated by the AI.",
"format": "date-time"
},
"aiModelUsed": {
"type": "string",
"description": "Identifier for the specific AI model or configuration that was used to generate this summary."
},
"version": {
"type": "number",
"description": "A version number for the summary, useful if multiple summaries are generated or re-generated for the same document over time."
}
},
"required": [
"id",
"documentId",
"userId",
"summaryText",
"generatedAt"
]
}
},
"auth": {
"providers": [
"password"
]
},
"firestore": {
"structure": [
{
"path": "/users/{userId}",
"definition": {
"entityName": "User",
"schema": {
"$ref": "#/backend/entities/User"
},
"description": "Stores individual user profiles. This collection is owned by the user, and access is restricted to the authenticated user matching 'userId'.",
"params": [
{
"name": "userId",
"description": "The unique identifier of the user, corresponding to Firebase Authentication UID."
}
]
}
},
{
"path": "/users/{userId}/documents/{documentId}",
"definition": {
"entityName": "Document",
"schema": {
"$ref": "#/backend/entities/Document"
},
"description": "A subcollection under a specific user, containing metadata for documents uploaded by that user. Each document includes the denormalized 'userId' field for authorization independence.",
"params": [
{
"name": "userId",
"description": "The unique identifier of the user who owns this document, corresponding to Firebase Authentication UID."
},
{
"name": "documentId",
"description": "The unique identifier for the specific document."
}
]
}
},
{
"path": "/users/{userId}/documents/{documentId}/summaries/{summaryId}",
"definition": {
"entityName": "Summary",
"schema": {
"$ref": "#/backend/entities/Summary"
},
"description": "A nested subcollection under a specific document, containing AI-generated summaries for that document. Each summary includes denormalized 'userId' and 'documentId' fields for authorization independence.",
"params": [
{
"name": "userId",
"description": "The unique identifier of the user who owns this summary, corresponding to Firebase Authentication UID."
},
{
"name": "documentId",
"description": "The unique identifier of the document this summary belongs to."
},
{
"name": "summaryId",
"description": "The unique identifier for the specific summary."
}
]
}
}
],
"reasoning": "The Firestore structure for ByteBrief prioritizes secure, scalable, and debuggable access to user-owned documents and their summaries. It adheres strictly to the core design principles, especially Authorization Independence and the enforcement of Query-Authentic Paths (QAPs).\n\n1. **Users Collection (`/users/{userId}`):** This top-level collection stores individual user profiles. Access is strictly private, meaning only the authenticated user (`request.auth.uid`) can read or write their own user document. This path establishes path-based ownership, making user profile rules straightforward (e.g., `allow read, write: if request.auth.uid == userId;`).\n\n2. **Documents Subcollection (`/users/{userId}/documents/{documentId}`):** Each user's uploaded documents are stored as a subcollection under their respective user profile. This hierarchical structure inherently links a document to its owner. Critical for **Authorization Independence**, each `Document` document will explicitly contain a `userId` field (denormalized from the parent user). This allows security rules to verify ownership directly within the document (`resource.data.userId`) without requiring a `get()` call to the parent user document. This is crucial for enabling atomic operations and simplifying rule logic. This structure supports QAPs by allowing clients to query for documents belonging to `request.auth.uid` within the specific user's path, and rules can directly validate `request.auth.uid == userId` (the path wildcard).\n\n3. **Summaries Subcollection (`/users/{userId}/documents/{documentId}/summaries/{summaryId}`):** AI-generated summaries are stored as a further nested subcollection, under the specific document they relate to. This continues the strong hierarchical ownership model. For **Authorization Independence**, each `Summary` document will explicitly contain both `userId` and `documentId` fields. This denormalization allows security rules to verify both the user's ownership and the summary's linkage to the correct document without any `get()` operations on parent documents. This enables `allow read, write: if request.auth.uid == userId;` to be applied efficiently and securely. QAPs are supported by the nested path structure, allowing specific user and document-scoped queries where rules can directly check `request.auth.uid == userId` (the path wildcard).\n\n**Authorization Independence via Denormalization:** This design achieves Authorization Independence by explicitly embedding `userId` in every `Document` document and both `userId` and `documentId` in every `Summary` document. This means that any security rule for a `Document` or `Summary` can evaluate ownership (`request.auth.uid == resource.data.userId`) directly on the document being accessed, without needing to perform `get()` operations on parent collections to determine the owner. This is fundamental for robust and efficient security rules, particularly in transactions and batched writes.\n\n**Support for QAPs (Query-Authentic Paths):** The entire structure is designed around path-based ownership (`/users/{userId}/...`). This inherently makes `list` operations secure and efficient. When a user queries for their documents or summaries, they will naturally be querying within their specific `/users/{request.auth.uid}/` path. The security rules can then simply verify that `request.auth.uid` matches the `{userId}` wildcard in the path, ensuring that users can only query their own data. The explicit `userId` and `documentId` fields in the documents further reinforce this, allowing for rules like `allow read: if request.auth.uid == userId;` which are naturally query-authentic."
}
}