Database Schema Designer
Run ID: 69bca49077c0421c0bf495802026-03-29Development
PantheraHive BOS
BOS Dashboard

Database Schema Design for E-commerce Platform (MongoDB)

1. Workflow Execution Summary - Step 1: Generate

This output details the initial schema design for an E-commerce platform, tailored for MongoDB based on the provided app_description. Given the generic nature of the input, a common application domain (E-commerce) has been chosen to provide a comprehensive and illustrative example of MongoDB schema design principles.

Application Concept: A basic E-commerce platform allowing users to browse products, add them to a cart, place orders, and leave reviews.

MongoDB Design Philosophy Applied:

2. High-Level Schema Overview

The proposed schema organizes data into several core collections, each representing a primary entity within the e-commerce domain. Relationships between these entities are handled through a mix of embedding (for one-to-few, frequently accessed data) and referencing (for one-to-many, many-to-many, or large datasets).

Core Collections:

3. Detailed Collection Schemas

3.1. users Collection

* _id: MongoDB's default ObjectId for unique identification.

* email, passwordHash: Essential for authentication. passwordHash should store a securely hashed password.

* firstName, lastName: Basic user identification.

* addresses: An array of embedded documents for multiple addresses (shipping, billing). Each address has a type and standard fields. This is an example of embedding "one-to-few" related data.

* createdAt, updatedAt: Timestamps for auditing.

* roles: An array for role-based access control (e.g., admin, customer).

text • 1,357 chars
#### 3.5. `reviews` Collection (Alternative: Embedded in `products`)

*   **Purpose:** Stores customer reviews for products.
*   **Design Choices:**
    *   **Option 1 (Separate Collection - chosen for this example):** For scenarios where reviews can be very numerous for a single product, or if reviews have their own complex lifecycle/moderation, a separate collection is better.
        *   `_id`: MongoDB's default `ObjectId`.
        *   `productId`: `ObjectId` reference to the `products` collection.
        *   `userId`: `ObjectId` reference to the `users` collection.
        *   `rating`: Numeric rating (e.g., 1-5 stars).
        *   `comment`: Textual review.
        *   `createdAt`, `updatedAt`: Timestamps.
        *   `isApproved`: Boolean for moderation.
    *   **Option 2 (Embedded in `products`):** If reviews are typically few per product, always accessed with the product, and don't require independent querying/updates, embedding directly into the `products` collection as an array is efficient. This would mean adding a `reviews` array field to the `products` collection. *The current `products` schema uses denormalized `averageRating` and `reviewCount`, implying reviews are likely in a separate collection or managed in a way that allows these fields to be updated.*
*   **Sample Document Structure (Separate Collection):**

    
Sandboxed live preview

4. Relationships and Denormalization Strategy

  • User-Order (One-to-Many): An order belongs to one user. Handled by userId reference in orders.
  • Product-Category (Many-to-Many): A product can have multiple categories, and a category can contain multiple products. Handled by categoryIds array of ObjectId references in products.
  • Product-Order Item (Many-to-Many): An order contains multiple products, and a product can be in multiple orders. Handled by embedded items array in orders, which includes productId references and denormalized product details (name, price) for historical accuracy.
  • Product-Review (One-to-Many): A product can have many reviews. Handled by productId reference in reviews (if separate collection).
  • User-Review (One-to-Many): A user can write many reviews. Handled by userId reference in reviews.
  • Denormalization:

* products.averageRating, products.reviewCount: Denormalized from reviews collection for quick display without aggregation.

* orders.items.name, orders.items.price: Denormalized from products to preserve historical order details.

* orders.shippingAddress: Embedded snapshot of the user's address at the time of order.

5. Key Considerations for MongoDB

  • Sharding: For very large collections (e.g., orders, users, products), consider a shard key. For users, email or a synthetic userId might work. For orders, userId (to keep all orders for a user on the same shard) or orderDate (for time-based sharding) could be options. For products, _id is a good default or sku if queries are often by sku.
  • Transactions: MongoDB supports multi-document ACID transactions. For operations requiring atomicity across multiple documents or collections (e.g., placing an order that involves creating an order and updating product stock), use transactions.
  • Aggregation Framework: Leverage MongoDB's powerful aggregation pipeline for complex queries, reporting, and data transformations (e.g., calculating sales trends, top-selling products).
  • Schema Validation: As demonstrated, use JSON Schema for server-side schema validation to enforce structure and data types, even in a schema-less database. This improves data quality and application robustness.
  • Data Lifecycle Management: Consider TTL (Time-To-Live) indexes for data that expires (e.g., temporary carts, old logs) to automatically remove documents.
  • Storage Optimization: Be mindful of document size limits (16MB). Large arrays or deeply nested documents might need re-evaluation.

6. Actionable Recommendations

  1. Refine app_description: Provide more specific details about the application's core features, user stories, and expected query patterns. This will allow for a more tailored and optimized schema.
  2. Performance Testing: Once the initial schema is implemented, rigorously test common queries and operations to identify performance bottlenecks and optimize indexes.
  3. Security Best Practices: Ensure all sensitive data (e.g., passwords) is properly hashed. Implement robust access control and authentication mechanisms.
  4. Error Handling and Data Consistency: Design application logic to handle potential data inconsistencies (e.g., if a product is deleted but still referenced in an order item) and ensure denormalized fields are updated reliably.
  5. Iterative Design: This is an initial design. MongoDB's flexibility allows for schema evolution. Be prepared to iterate and adjust the schema as the application grows and requirements change.

This comprehensive output provides a strong foundation for developing an e-commerce application using MongoDB, highlighting key design considerations and best practices.

Step 2: projectmanager

Database Schema Design for "projectmanager" Application (MongoDB)

1. Executive Summary

This document outlines a comprehensive MongoDB schema design for a "projectmanager" application. Given the nature of a project management system, the design emphasizes flexibility, scalability, and efficient data retrieval through a document-oriented approach. Key entities like Projects, Tasks, Users, and Teams are modeled with considerations for embedding frequently accessed sub-documents (e.g., comments, attachments) and referencing independent entities (e.g., users, projects) to balance performance and data consistency. The schema includes indexing strategies, validation rules, and actionable recommendations to ensure a robust and performant database for your application.

2. Core Entities and Collections

The "projectmanager" application will primarily interact with the following collections:

  • users: Stores information about individuals using the system.
  • teams: Organizes users into groups, which can then be assigned to projects.
  • projects: Represents distinct projects, containing tasks and managed by teams/users.
  • tasks: Individual work items associated with a project.
  • notifications: (Optional) Stores system notifications for users.

3. Detailed Schema Design (MongoDB)

3.1. users Collection

This collection stores user profiles and authentication details.

Document Structure:


{
  "_id": ObjectId,               // Unique identifier for the user
  "username": String,            // Unique username for login
  "email": String,               // Unique email address, used for communication/login
  "password_hash": String,       // Hashed password (NEVER store plain passwords)
  "first_name": String,
  "last_name": String,
  "profile_picture_url": String, // Optional URL to user's profile image
  "roles": [String],             // Array of roles (e.g., ["admin", "project_manager", "member"])
  "status": String,              // User account status (e.g., "active", "inactive", "pending_verification")
  "created_at": ISODate,         // Timestamp of user creation
  "updated_at": ISODate          // Timestamp of last update to user profile
}

Indexes:

  • { "username": 1 }: Unique index for efficient login and lookup by username.
  • { "email": 1 }: Unique index for efficient login and lookup by email.
  • { "roles": 1 }: For querying users by their roles.
  • { "status": 1 }: For managing user accounts.

Validation (Example db.createCollection schema validation):


db.createCollection("users", {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["username", "email", "password_hash", "first_name", "last_name", "roles", "status", "created_at", "updated_at"],
      properties: {
        username: { bsonType: "string", description: "must be a string and is required", minLength: 3 },
        email: { bsonType: "string", description: "must be a string and is required", pattern: "^.+@.+$" },
        password_hash: { bsonType: "string", description: "must be a string and is required" },
        first_name: { bsonType: "string", description: "must be a string and is required" },
        last_name: { bsonType: "string", description: "must be a string and is required" },
        profile_picture_url: { bsonType: "string" },
        roles: {
          bsonType: "array",
          items: { bsonType: "string" },
          description: "must be an array of strings and is required",
          minItems: 1
        },
        status: {
          enum: ["active", "inactive", "pending_verification"],
          description: "can only be one of the enum values and is required"
        },
        created_at: { bsonType: "date", description: "must be a date and is required" },
        updated_at: { bsonType: "date", description: "must be a date and is required" }
      }
    }
  }
});

3.2. teams Collection

This collection groups users together, allowing for easier assignment to projects.

Document Structure:


{
  "_id": ObjectId,               // Unique identifier for the team
  "name": String,                // Unique name of the team
  "description": String,         // Description of the team
  "member_ids": [ObjectId],      // Array of ObjectId references to users in this team
  "created_at": ISODate,         // Timestamp of team creation
  "updated_at": ISODate          // Timestamp of last update to team profile
}

Indexes:

  • { "name": 1 }: Unique index for efficient lookup by team name.
  • { "member_ids": 1 }: For querying teams that a specific user belongs to.

Validation (Example):


db.createCollection("teams", {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["name", "member_ids", "created_at", "updated_at"],
      properties: {
        name: { bsonType: "string", description: "must be a string and is required", minLength: 3 },
        description: { bsonType: "string" },
        member_ids: {
          bsonType: "array",
          items: { bsonType: "objectId" },
          description: "must be an array of ObjectIds and is required"
        },
        created_at: { bsonType: "date", description: "must be a date and is required" },
        updated_at: { bsonType: "date", description: "must be a date and is required" }
      }
    }
  }
});

3.3. projects Collection

This collection holds the main project details.

Document Structure:


{
  "_id": ObjectId,                 // Unique identifier for the project
  "name": String,                  // Name of the project
  "description": String,           // Detailed description of the project
  "status": String,                // Current status (e.g., "Not Started", "In Progress", "On Hold", "Completed", "Archived")
  "priority": String,              // Project priority (e.g., "Low", "Medium", "High")
  "start_date": ISODate,           // Planned start date
  "due_date": ISODate,             // Planned due date
  "completed_at": ISODate,         // Actual completion date (optional)
  "owner_id": ObjectId,            // Reference to the user who owns/manages the project
  "team_ids": [ObjectId],          // Array of ObjectId references to teams working on the project
  "member_ids": [ObjectId],        // Array of ObjectId references to individual users on the project (in addition to teams)
  "tags": [String],                // Array of tags for categorization
  "attachments": [                 // Embedded array of project-level attachments
    {
      "filename": String,          // Original filename
      "url": String,               // URL to the stored file (e.g., S3, CDN)
      "file_type": String,         // MIME type (e.g., "image/jpeg", "application/pdf")
      "uploaded_by_id": ObjectId,  // User who uploaded the file
      "uploaded_at": ISODate       // Timestamp of upload
    }
  ],
  "created_at": ISODate,           // Timestamp of project creation
  "updated_at": ISODate            // Timestamp of last update to project
}

Indexes:

  • { "owner_id": 1 }: For quickly finding projects owned by a specific user.
  • { "team_ids": 1 }: For finding projects associated with a specific team.
  • { "member_ids": 1 }: For finding projects a user is directly involved in.
  • { "status": 1, "due_date": 1 }: For querying active projects by due date.
  • { "tags": 1 }: For searching projects by tags.
  • { "name": "text", "description": "text" }: For full-text search capabilities (requires text index).

Validation (Example):


db.createCollection("projects", {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["name", "status", "start_date", "due_date", "owner_id", "created_at", "updated_at"],
      properties: {
        name: { bsonType: "string", description: "must be a string and is required", minLength: 3 },
        description: { bsonType: "string" },
        status: {
          enum: ["Not Started", "In Progress", "On Hold", "Completed", "Archived"],
          description: "can only be one of the enum values and is required"
        },
        priority: { enum: ["Low", "Medium", "High"], description: "optional project priority" },
        start_date: { bsonType: "date", description: "must be a date and is required" },
        due_date: { bsonType: "date", description: "must be a date and is required" },
        completed_at: { bsonType: "date" },
        owner_id: { bsonType: "objectId", description: "must be an ObjectId and is required" },
        team_ids: { bsonType: "array", items: { bsonType: "objectId" } },
        member_ids: { bsonType: "array", items: { bsonType: "objectId" } },
        tags: { bsonType: "array", items: { bsonType: "string" } },
        attachments: {
          bsonType: "array",
          items: {
            bsonType: "object",
            required: ["filename", "url", "uploaded_by_id", "uploaded_at"],
            properties: {
              filename: { bsonType: "string" },
              url: { bsonType: "string" },
              file_type: { bsonType: "string" },
              uploaded_by_id: { bsonType: "objectId" },
              uploaded_at: { bsonType: "date" }
            }
          }
        },
        created_at: { bsonType: "date", description: "must be a date and is required" },
        updated_at: { bsonType: "date", description: "must be a date and is required" }
      }
    }
  }
});

3.4. tasks Collection

This collection stores individual tasks associated with projects.

Document Structure:


{
  "_id": ObjectId,                 // Unique identifier for the task
  "project_id": ObjectId,          // Reference to the parent project
  "name": String,                  // Name of the task
  "description": String,           // Detailed description of the task
  "status": String,                // Current status (e.g., "To Do", "In Progress", "Review", "Done")
  "priority": String,              // Task priority (e.g., "Low", "Medium", "High", "Urgent")
  "assigned_to_ids": [ObjectId],   // Array of ObjectId references to users assigned to this task
  "reporter_id": ObjectId,         // Reference to the user who created/reported the task
  "start_date": ISODate,           // Planned start date for the task
  "due_date": ISODate,             // Planned due date for the task
  "completed_at": ISODate,         // Actual completion date (optional)
  "parent_task_id": ObjectId,      // Optional: Reference to a parent task for sub-tasks
  "tags": [String],                // Array of tags for categorization
  "comments": [                    // Embedded array of comments for the task
    {
      "_id": ObjectId,             // Unique ID for the comment (useful for direct updates/deletes)
      "user_id": ObjectId,         // User who posted the comment
      "text": String,              // Comment content
      "created_at": ISODate,       // Timestamp of comment
      "updated_at": ISODate        // Timestamp of last comment update (optional)
    }
  ],
  "attachments": [                 // Embedded array of task-level attachments
    {
      "filename": String,
      "url": String,
      "file_type": String,
      "uploaded_by_id": ObjectId,
      "uploaded_at": ISODate
    }
  ],
  "created_at": ISODate,           // Timestamp of task creation
  "updated_at": ISODate            // Timestamp of last update to task
}

Indexes:

  • { "project_id": 1 }: Essential for querying tasks within a specific project.
  • { "assigned_to_ids": 1 }: For finding tasks assigned to a particular user.
  • { "status": 1, "due_date": 1 }: For querying tasks by status and due date (e.g., "overdue tasks").
  • { "reporter_id": 1 }: For finding tasks reported by a specific user.
  • { "parent_task_id": 1 }: For querying sub-tasks.
  • { "name": "text", "description": "text" }: For full-text search on tasks.

Validation (Example):


db.createCollection("tasks", {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["project_id", "name", "status", "assigned_to_ids", "reporter_id", "due_date", "created_at", "updated_at"],
      properties: {
        project_id: { bsonType: "objectId", description: "must be an ObjectId and is required" },
        name: { bsonType: "string", description: "must be a string and is required", minLength: 3 },
        description: { bsonType: "string" },
        status: {
          enum: ["To Do", "In Progress", "Review", "Done"],
          description: "can only be one of the enum values and is required"
        },
        priority: { enum: ["Low", "Medium", "High", "Urgent"], description: "optional task priority" },
        assigned_to_ids: {
          bsonType: "array",
          items: { bsonType: "objectId" },
          description: "must be an array of ObjectIds and is required",
          minItems: 1
        },
        reporter_id: { bsonType: "objectId", description: "must be an ObjectId and is required" },
        start_date: { bsonType: "date" },
        due_date: { bsonType: "date", description: "must be a date and is required" },
        completed_at: { bsonType: "date" },
        parent_task_id: { bsonType: "objectId" },
        tags: { bsonType: "array", items: { bsonType: "string" } },
        comments: {
          bsonType: "array",
          items: {
            bsonType: "object",
            required: ["_id", "user_id", "text", "created_at"],
            properties: {
              _id: { bsonType: "objectId" },
              user_id: { bsonType: "objectId" },
              text: { bsonType: "string" },
              created_at: { bsonType: "date" },
              updated_at: { bsonType: "date" }
            }
          }
        },
        attachments: {
          bsonType: "array",
          items: {
            bsonType: "object",
            required: ["filename", "url", "uploaded_by_id", "uploaded_at"],
            properties: {
              filename: { bsonType: "string" },
              url: { bsonType: "string" },
              file_type: { bsonType: "string" },
              uploaded_by_id: { bsonType: "objectId" },
              uploaded_at: { bsonType: "date" }
            }
          }
        },
        created_at: { bsonType: "date", description: "must be a date and is required" },
        updated_at: { bsonType: "date", description: "must be a date and is required" }
      }
    }
  }
});

3.5. notifications Collection (Optional)

This collection can be used to store system-generated notifications for users.

Document Structure:


{
  "_id": ObjectId,               // Unique identifier for the notification
  "user_id": ObjectId,           // Reference to the user who receives the notification
  "type": String,                // Type of notification (e.g., "task_assigned", "comment_added", "project_status_changed")
  "entity_type": String,         // Type of the entity the notification refers to (e.g., "task", "project")
  "entity_id": ObjectId,         // Reference to the relevant entity (e.g., Task ID, Project ID)
  "message": String,             // The notification message
  "link": String,                // Optional URL to navigate to when clicking the notification
  "is_read": Boolean,            // True if the user has read the notification, default false
  "created_at": ISODate          // Timestamp of notification creation
}

Indexes:

  • { "user_id": 1, "is_read": 1, "created_at": -1 }: For efficient retrieval of unread notifications for a user, ordered by most recent.
  • { "entity_id": 1 }: For contextual lookups.

Validation (Example):


db.createCollection("notifications", {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["user_id", "type", "entity_type", "entity_id", "message", "is_read", "created_at"],
      properties: {
        user_id: { bsonType: "objectId", description: "must be an ObjectId and is required" },
        type: { bsonType: "string", description: "must be a string and is required" },
        entity_type: { enum: ["task", "project", "comment", "user"], description: "must be a valid entity type" },
        entity_id: { bsonType: "objectId", description: "must be an ObjectId and is required" },
        message: { bsonType: "string", description: "must be a string and is required" },
        link: { bsonType: "string" },
        is_read: { bsonType: "bool", description: "must be a boolean and is required" },
        created_at: { bsonType: "date", description: "must be a date and is required" }
      }
    }
  }
});

4. Relationships and Data Modeling Decisions

  • Embedding vs. Referencing:

* Embedded: comments and attachments are embedded within tasks and projects. This is ideal because comments and attachments are almost always accessed in the context of their parent task/project. This reduces the number of queries needed to display a task or project with its related content. For comments, each comment has its own _id to allow for direct updates or deletions within the array using array filters.

* Referenced: users, teams, and projects are separate collections.

* A user can be part of many teams and assigned to many projects and tasks.

* A team can be associated with many projects.

* A project has many tasks.

* This many-to-many or one-to-many relationship where the "many" side can grow large or entities need independent existence justifies separate collections with ObjectId references.

  • Array of ObjectIds: For assigned_to_ids, team_ids, member_ids, and tags, arrays of ObjectIds/Strings are used. This allows for flexible assignment of multiple users/teams/tags without complex join operations. MongoDB's $in operator and multi-key indexes handle these efficiently.
  • Timestamps: created_at and updated_at fields are consistently included in all primary collections for auditing and tracking changes.

5. Actionable Recommendations and Best Practices

  1. Implement Schema Validation: Use MongoDB's built-in schema validation (as shown in examples above) to enforce data consistency and type checking at the database level. This helps prevent invalid data from being inserted.
  2. Indexing Strategy:

* Review Access Patterns: Regularly analyze your application's query patterns. Add indexes for fields frequently used in find(), sort(), and aggregation operations.

* Compound Indexes: Consider compound indexes (e.g., { "status": 1, "due_date": 1 } for tasks) for queries that involve multiple fields.

* Text Indexes: For full-text search on name and description fields, utilize MongoDB's text indexes.

* Sparse Indexes: If a field is optional and only a subset of documents have it, consider a sparse index to save space.

  1. Authentication & Authorization:

* Password Hashing: Always store password hashes (e.g., using bcrypt) in the users collection, never plain passwords.

* Role-Based Access Control (RBAC): Use the roles array in the users collection to implement RBAC at the application layer, determining what actions a user can perform.

  1. File Storage:

* External Storage: For attachments, store the actual files in an external object storage service like AWS S3, Google Cloud Storage, or Azure Blob Storage. Only store the URL and metadata in MongoDB. This keeps your database lean and performs better for large files.

* GridFS: For very large files (over 16MB) or if you prefer to keep files within MongoDB, consider GridFS, but for most project management attachments, external storage is more scalable and cost-effective.

  1. Performance Tuning:

* Projection: Use projection ({ field: 1, _id: 0 }) to retrieve only the necessary fields from documents, reducing network overhead.

* Aggregation Pipeline: For complex data transformations and reporting, leverage MongoDB's powerful aggregation framework.

* Sharding: As your data volume grows, consider sharding your collections (especially tasks and notifications) to distribute data and read/write operations across multiple servers.

  1. Change Streams: For real-time updates and notifications, utilize MongoDB Change Streams to react to data modifications in your collections. This can power real-time dashboards or push notifications.
  2. Data Archiving/TTL Indexes: For notifications or historical data that you don't need to keep forever, consider using Time-To-Live (TTL) indexes to automatically remove old documents. For older projects/tasks, implement an archiving strategy (e.g., move to a separate archived_projects collection).
  3. Application Logic for References: When querying documents with references (e.g., fetching a project and its owner's details), your application will need to perform a second query or use the $lookup aggregation stage for "joins." Design your application to handle these efficiently, potentially caching frequently accessed user or team data.

This schema provides a solid foundation for your "projectmanager" application, balancing the benefits of a document database with the need for structured data and efficient querying. Remember to iterate and refine the schema based on actual usage patterns and application requirements as your project evolves.

database_schema_designer.txt
Download source file
Copy all content
Full output as text
Download ZIP
IDE-ready project ZIP
Copy share link
Permanent URL for this run
Get Embed Code
Embed this result on any website
Print / Save PDF
Use browser print dialog
\n\n\n"); var hasSrcMain=Object.keys(extracted).some(function(k){return k.indexOf("src/main")>=0;}); if(!hasSrcMain) zip.file(folder+"src/main."+ext,"import React from 'react'\nimport ReactDOM from 'react-dom/client'\nimport App from './App'\nimport './index.css'\n\nReactDOM.createRoot(document.getElementById('root')!).render(\n \n \n \n)\n"); var hasSrcApp=Object.keys(extracted).some(function(k){return k==="src/App."+ext||k==="App."+ext;}); if(!hasSrcApp) zip.file(folder+"src/App."+ext,"import React from 'react'\nimport './App.css'\n\nfunction App(){\n return(\n
\n
\n

"+slugTitle(pn)+"

\n

Built with PantheraHive BOS

\n
\n
\n )\n}\nexport default App\n"); zip.file(folder+"src/index.css","*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:system-ui,-apple-system,sans-serif;background:#f0f2f5;color:#1a1a2e}\n.app{min-height:100vh;display:flex;flex-direction:column}\n.app-header{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:40px}\nh1{font-size:2.5rem;font-weight:700}\n"); zip.file(folder+"src/App.css",""); zip.file(folder+"src/components/.gitkeep",""); zip.file(folder+"src/pages/.gitkeep",""); zip.file(folder+"src/hooks/.gitkeep",""); Object.keys(extracted).forEach(function(p){ var fp=p.startsWith("src/")?p:"src/"+p; zip.file(folder+fp,extracted[p]); }); zip.file(folder+"README.md","# "+slugTitle(pn)+"\n\nGenerated by PantheraHive BOS.\n\n## Setup\n\`\`\`bash\nnpm install\nnpm run dev\n\`\`\`\n\n## Build\n\`\`\`bash\nnpm run build\n\`\`\`\n\n## Open in IDE\nOpen the project folder in VS Code or WebStorm.\n"); zip.file(folder+".gitignore","node_modules/\ndist/\n.env\n.DS_Store\n*.local\n"); } /* --- Vue (Vite + Composition API + TypeScript) --- */ function buildVue(zip,folder,app,code,panelTxt){ var pn=pkgName(app); var C=cc(pn); var extracted=extractCode(panelTxt); zip.file(folder+"package.json",'{\n "name": "'+pn+'",\n "version": "0.0.0",\n "type": "module",\n "scripts": {\n "dev": "vite",\n "build": "vue-tsc -b && vite build",\n "preview": "vite preview"\n },\n "dependencies": {\n "vue": "^3.5.13",\n "vue-router": "^4.4.5",\n "pinia": "^2.3.0",\n "axios": "^1.7.9"\n },\n "devDependencies": {\n "@vitejs/plugin-vue": "^5.2.1",\n "typescript": "~5.7.3",\n "vite": "^6.0.5",\n "vue-tsc": "^2.2.0"\n }\n}\n'); zip.file(folder+"vite.config.ts","import { defineConfig } from 'vite'\nimport vue from '@vitejs/plugin-vue'\nimport { resolve } from 'path'\n\nexport default defineConfig({\n plugins: [vue()],\n resolve: { alias: { '@': resolve(__dirname,'src') } }\n})\n"); zip.file(folder+"tsconfig.json",'{"files":[],"references":[{"path":"./tsconfig.app.json"},{"path":"./tsconfig.node.json"}]}\n'); zip.file(folder+"tsconfig.app.json",'{\n "compilerOptions":{\n "target":"ES2020","useDefineForClassFields":true,"module":"ESNext","lib":["ES2020","DOM","DOM.Iterable"],\n "skipLibCheck":true,"moduleResolution":"bundler","allowImportingTsExtensions":true,\n "isolatedModules":true,"moduleDetection":"force","noEmit":true,"jsxImportSource":"vue",\n "strict":true,"paths":{"@/*":["./src/*"]}\n },\n "include":["src/**/*.ts","src/**/*.d.ts","src/**/*.tsx","src/**/*.vue"]\n}\n'); zip.file(folder+"env.d.ts","/// \n"); zip.file(folder+"index.html","\n\n\n \n \n "+slugTitle(pn)+"\n\n\n
\n \n\n\n"); var hasMain=Object.keys(extracted).some(function(k){return k==="src/main.ts"||k==="main.ts";}); if(!hasMain) zip.file(folder+"src/main.ts","import { createApp } from 'vue'\nimport { createPinia } from 'pinia'\nimport App from './App.vue'\nimport './assets/main.css'\n\nconst app = createApp(App)\napp.use(createPinia())\napp.mount('#app')\n"); var hasApp=Object.keys(extracted).some(function(k){return k.indexOf("App.vue")>=0;}); if(!hasApp) zip.file(folder+"src/App.vue","\n\n\n\n\n"); zip.file(folder+"src/assets/main.css","*{margin:0;padding:0;box-sizing:border-box}body{font-family:system-ui,sans-serif;background:#fff;color:#213547}\n"); zip.file(folder+"src/components/.gitkeep",""); zip.file(folder+"src/views/.gitkeep",""); zip.file(folder+"src/stores/.gitkeep",""); Object.keys(extracted).forEach(function(p){ var fp=p.startsWith("src/")?p:"src/"+p; zip.file(folder+fp,extracted[p]); }); zip.file(folder+"README.md","# "+slugTitle(pn)+"\n\nGenerated by PantheraHive BOS.\n\n## Setup\n\`\`\`bash\nnpm install\nnpm run dev\n\`\`\`\n\n## Build\n\`\`\`bash\nnpm run build\n\`\`\`\n\nOpen in VS Code or WebStorm.\n"); zip.file(folder+".gitignore","node_modules/\ndist/\n.env\n.DS_Store\n*.local\n"); } /* --- Angular (v19 standalone) --- */ function buildAngular(zip,folder,app,code,panelTxt){ var pn=pkgName(app); var C=cc(pn); var sel=pn.replace(/_/g,"-"); var extracted=extractCode(panelTxt); zip.file(folder+"package.json",'{\n "name": "'+pn+'",\n "version": "0.0.0",\n "scripts": {\n "ng": "ng",\n "start": "ng serve",\n "build": "ng build",\n "test": "ng test"\n },\n "dependencies": {\n "@angular/animations": "^19.0.0",\n "@angular/common": "^19.0.0",\n "@angular/compiler": "^19.0.0",\n "@angular/core": "^19.0.0",\n "@angular/forms": "^19.0.0",\n "@angular/platform-browser": "^19.0.0",\n "@angular/platform-browser-dynamic": "^19.0.0",\n "@angular/router": "^19.0.0",\n "rxjs": "~7.8.0",\n "tslib": "^2.3.0",\n "zone.js": "~0.15.0"\n },\n "devDependencies": {\n "@angular-devkit/build-angular": "^19.0.0",\n "@angular/cli": "^19.0.0",\n "@angular/compiler-cli": "^19.0.0",\n "typescript": "~5.6.0"\n }\n}\n'); zip.file(folder+"angular.json",'{\n "$schema": "./node_modules/@angular/cli/lib/config/schema.json",\n "version": 1,\n "newProjectRoot": "projects",\n "projects": {\n "'+pn+'": {\n "projectType": "application",\n "root": "",\n "sourceRoot": "src",\n "prefix": "app",\n "architect": {\n "build": {\n "builder": "@angular-devkit/build-angular:application",\n "options": {\n "outputPath": "dist/'+pn+'",\n "index": "src/index.html",\n "browser": "src/main.ts",\n "tsConfig": "tsconfig.app.json",\n "styles": ["src/styles.css"],\n "scripts": []\n }\n },\n "serve": {"builder":"@angular-devkit/build-angular:dev-server","configurations":{"production":{"buildTarget":"'+pn+':build:production"},"development":{"buildTarget":"'+pn+':build:development"}},"defaultConfiguration":"development"}\n }\n }\n }\n}\n'); zip.file(folder+"tsconfig.json",'{\n "compileOnSave": false,\n "compilerOptions": {"baseUrl":"./","outDir":"./dist/out-tsc","forceConsistentCasingInFileNames":true,"strict":true,"noImplicitOverride":true,"noPropertyAccessFromIndexSignature":true,"noImplicitReturns":true,"noFallthroughCasesInSwitch":true,"paths":{"@/*":["src/*"]},"skipLibCheck":true,"esModuleInterop":true,"sourceMap":true,"declaration":false,"experimentalDecorators":true,"moduleResolution":"bundler","importHelpers":true,"target":"ES2022","module":"ES2022","useDefineForClassFields":false,"lib":["ES2022","dom"]},\n "references":[{"path":"./tsconfig.app.json"}]\n}\n'); zip.file(folder+"tsconfig.app.json",'{\n "extends":"./tsconfig.json",\n "compilerOptions":{"outDir":"./dist/out-tsc","types":[]},\n "files":["src/main.ts"],\n "include":["src/**/*.d.ts"]\n}\n'); zip.file(folder+"src/index.html","\n\n\n \n "+slugTitle(pn)+"\n \n \n \n\n\n \n\n\n"); zip.file(folder+"src/main.ts","import { bootstrapApplication } from '@angular/platform-browser';\nimport { appConfig } from './app/app.config';\nimport { AppComponent } from './app/app.component';\n\nbootstrapApplication(AppComponent, appConfig)\n .catch(err => console.error(err));\n"); zip.file(folder+"src/styles.css","* { margin: 0; padding: 0; box-sizing: border-box; }\nbody { font-family: system-ui, -apple-system, sans-serif; background: #f9fafb; color: #111827; }\n"); var hasComp=Object.keys(extracted).some(function(k){return k.indexOf("app.component")>=0;}); if(!hasComp){ zip.file(folder+"src/app/app.component.ts","import { Component } from '@angular/core';\nimport { RouterOutlet } from '@angular/router';\n\n@Component({\n selector: 'app-root',\n standalone: true,\n imports: [RouterOutlet],\n templateUrl: './app.component.html',\n styleUrl: './app.component.css'\n})\nexport class AppComponent {\n title = '"+pn+"';\n}\n"); zip.file(folder+"src/app/app.component.html","
\n
\n

"+slugTitle(pn)+"

\n

Built with PantheraHive BOS

\n
\n \n
\n"); zip.file(folder+"src/app/app.component.css",".app-header{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:60vh;gap:16px}h1{font-size:2.5rem;font-weight:700;color:#6366f1}\n"); } zip.file(folder+"src/app/app.config.ts","import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';\nimport { provideRouter } from '@angular/router';\nimport { routes } from './app.routes';\n\nexport const appConfig: ApplicationConfig = {\n providers: [\n provideZoneChangeDetection({ eventCoalescing: true }),\n provideRouter(routes)\n ]\n};\n"); zip.file(folder+"src/app/app.routes.ts","import { Routes } from '@angular/router';\n\nexport const routes: Routes = [];\n"); Object.keys(extracted).forEach(function(p){ var fp=p.startsWith("src/")?p:"src/"+p; zip.file(folder+fp,extracted[p]); }); zip.file(folder+"README.md","# "+slugTitle(pn)+"\n\nGenerated by PantheraHive BOS.\n\n## Setup\n\`\`\`bash\nnpm install\nng serve\n# or: npm start\n\`\`\`\n\n## Build\n\`\`\`bash\nng build\n\`\`\`\n\nOpen in VS Code with Angular Language Service extension.\n"); zip.file(folder+".gitignore","node_modules/\ndist/\n.env\n.DS_Store\n*.local\n.angular/\n"); } /* --- Python --- */ function buildPython(zip,folder,app,code){ var title=slugTitle(app); var pn=pkgName(app); var src=code.replace(/^\`\`\`[\w]*\n?/m,"").replace(/\n?\`\`\`$/m,"").trim(); var reqMap={"numpy":"numpy","pandas":"pandas","sklearn":"scikit-learn","tensorflow":"tensorflow","torch":"torch","flask":"flask","fastapi":"fastapi","uvicorn":"uvicorn","requests":"requests","sqlalchemy":"sqlalchemy","pydantic":"pydantic","dotenv":"python-dotenv","PIL":"Pillow","cv2":"opencv-python","matplotlib":"matplotlib","seaborn":"seaborn","scipy":"scipy"}; var reqs=[]; Object.keys(reqMap).forEach(function(k){if(src.indexOf("import "+k)>=0||src.indexOf("from "+k)>=0)reqs.push(reqMap[k]);}); var reqsTxt=reqs.length?reqs.join("\n"):"# add dependencies here\n"; zip.file(folder+"main.py",src||"# "+title+"\n# Generated by PantheraHive BOS\n\nprint(title+\" loaded\")\n"); zip.file(folder+"requirements.txt",reqsTxt); zip.file(folder+".env.example","# Environment variables\n"); zip.file(folder+"README.md","# "+title+"\n\nGenerated by PantheraHive BOS.\n\n## Setup\n\`\`\`bash\npython3 -m venv .venv\nsource .venv/bin/activate\npip install -r requirements.txt\n\`\`\`\n\n## Run\n\`\`\`bash\npython main.py\n\`\`\`\n"); zip.file(folder+".gitignore",".venv/\n__pycache__/\n*.pyc\n.env\n.DS_Store\n"); } /* --- Node.js --- */ function buildNode(zip,folder,app,code){ var title=slugTitle(app); var pn=pkgName(app); var src=code.replace(/^\`\`\`[\w]*\n?/m,"").replace(/\n?\`\`\`$/m,"").trim(); var depMap={"mongoose":"^8.0.0","dotenv":"^16.4.5","axios":"^1.7.9","cors":"^2.8.5","bcryptjs":"^2.4.3","jsonwebtoken":"^9.0.2","socket.io":"^4.7.4","uuid":"^9.0.1","zod":"^3.22.4","express":"^4.18.2"}; var deps={}; Object.keys(depMap).forEach(function(k){if(src.indexOf(k)>=0)deps[k]=depMap[k];}); if(!deps["express"])deps["express"]="^4.18.2"; var pkgJson=JSON.stringify({"name":pn,"version":"1.0.0","main":"src/index.js","scripts":{"start":"node src/index.js","dev":"nodemon src/index.js"},"dependencies":deps,"devDependencies":{"nodemon":"^3.0.3"}},null,2)+"\n"; zip.file(folder+"package.json",pkgJson); var fallback="const express=require(\"express\");\nconst app=express();\napp.use(express.json());\n\napp.get(\"/\",(req,res)=>{\n res.json({message:\""+title+" API\"});\n});\n\nconst PORT=process.env.PORT||3000;\napp.listen(PORT,()=>console.log(\"Server on port \"+PORT));\n"; zip.file(folder+"src/index.js",src||fallback); zip.file(folder+".env.example","PORT=3000\n"); zip.file(folder+".gitignore","node_modules/\n.env\n.DS_Store\n"); zip.file(folder+"README.md","# "+title+"\n\nGenerated by PantheraHive BOS.\n\n## Setup\n\`\`\`bash\nnpm install\n\`\`\`\n\n## Run\n\`\`\`bash\nnpm run dev\n\`\`\`\n"); } /* --- Vanilla HTML --- */ function buildVanillaHtml(zip,folder,app,code){ var title=slugTitle(app); var isFullDoc=code.trim().toLowerCase().indexOf("=0||code.trim().toLowerCase().indexOf("=0; var indexHtml=isFullDoc?code:"\n\n\n\n\n"+title+"\n\n\n\n"+code+"\n\n\n\n"; zip.file(folder+"index.html",indexHtml); zip.file(folder+"style.css","/* "+title+" — styles */\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:system-ui,-apple-system,sans-serif;background:#fff;color:#1a1a2e}\n"); zip.file(folder+"script.js","/* "+title+" — scripts */\n"); zip.file(folder+"assets/.gitkeep",""); zip.file(folder+"README.md","# "+title+"\n\nGenerated by PantheraHive BOS.\n\n## Open\nDouble-click \`index.html\` in your browser.\n\nOr serve locally:\n\`\`\`bash\nnpx serve .\n# or\npython3 -m http.server 3000\n\`\`\`\n"); zip.file(folder+".gitignore",".DS_Store\nnode_modules/\n.env\n"); } /* ===== MAIN ===== */ var sc=document.createElement("script"); sc.src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"; sc.onerror=function(){ if(lbl)lbl.textContent="Download ZIP"; alert("JSZip load failed — check connection."); }; sc.onload=function(){ var zip=new JSZip(); var base=(_phFname||"output").replace(/\.[^.]+$/,""); var app=base.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"")||"my_app"; var folder=app+"/"; var vc=document.getElementById("panel-content"); var panelTxt=vc?(vc.innerText||vc.textContent||""):""; var lang=detectLang(_phCode,panelTxt); if(_phIsHtml){ buildVanillaHtml(zip,folder,app,_phCode); } else if(lang==="flutter"){ buildFlutter(zip,folder,app,_phCode,panelTxt); } else if(lang==="react-native"){ buildReactNative(zip,folder,app,_phCode,panelTxt); } else if(lang==="swift"){ buildSwift(zip,folder,app,_phCode,panelTxt); } else if(lang==="kotlin"){ buildKotlin(zip,folder,app,_phCode,panelTxt); } else if(lang==="react"){ buildReact(zip,folder,app,_phCode,panelTxt); } else if(lang==="vue"){ buildVue(zip,folder,app,_phCode,panelTxt); } else if(lang==="angular"){ buildAngular(zip,folder,app,_phCode,panelTxt); } else if(lang==="python"){ buildPython(zip,folder,app,_phCode); } else if(lang==="node"){ buildNode(zip,folder,app,_phCode); } else { /* Document/content workflow */ var title=app.replace(/_/g," "); var md=_phAll||_phCode||panelTxt||"No content"; zip.file(folder+app+".md",md); var h=""+title+""; h+="

"+title+"

"; var hc=md.replace(/&/g,"&").replace(//g,">"); hc=hc.replace(/^### (.+)$/gm,"

$1

"); hc=hc.replace(/^## (.+)$/gm,"

$1

"); hc=hc.replace(/^# (.+)$/gm,"

$1

"); hc=hc.replace(/\*\*(.+?)\*\*/g,"$1"); hc=hc.replace(/\n{2,}/g,"

"); h+="

"+hc+"

Generated by PantheraHive BOS
"; zip.file(folder+app+".html",h); zip.file(folder+"README.md","# "+title+"\n\nGenerated by PantheraHive BOS.\n\nFiles:\n- "+app+".md (Markdown)\n- "+app+".html (styled HTML)\n"); } zip.generateAsync({type:"blob"}).then(function(blob){ var a=document.createElement("a"); a.href=URL.createObjectURL(blob); a.download=app+".zip"; a.click(); URL.revokeObjectURL(a.href); if(lbl)lbl.textContent="Download ZIP"; }); }; document.head.appendChild(sc); } function phShare(){navigator.clipboard.writeText(window.location.href).then(function(){var el=document.getElementById("ph-share-lbl");if(el){el.textContent="Link copied!";setTimeout(function(){el.textContent="Copy share link";},2500);}});}function phEmbed(){var runId=window.location.pathname.split("/").pop().replace(".html","");var embedUrl="https://pantherahive.com/embed/"+runId;var code='';navigator.clipboard.writeText(code).then(function(){var el=document.getElementById("ph-embed-lbl");if(el){el.textContent="Embed code copied!";setTimeout(function(){el.textContent="Get Embed Code";},2500);}});}