GraphQL Schema Designer
Run ID: 69cb5a3d61b1021a29a883ff2026-03-31Development
PantheraHive BOS
BOS Dashboard

GraphQL Schema Architecture Plan: E-Commerce Platform

This document outlines a comprehensive architectural plan for a GraphQL schema, focusing on an illustrative e-commerce platform use case. This plan encompasses the design of types, queries, mutations, subscriptions, resolver strategies, and integration considerations, providing a robust foundation for a scalable and maintainable GraphQL API.


1. Core Domain & Entities: E-Commerce Platform

The chosen domain is a typical e-commerce platform, enabling us to demonstrate a wide range of GraphQL features. Key entities and their relationships are:

Relationships:


2. GraphQL Schema Definition: Structure & Core Types

The schema will be defined using the GraphQL Schema Definition Language (SDL).

2.1. Root Types

2.2. Scalar Types

In addition to standard GraphQL scalars (String, Int, Float, Boolean, ID), we will define custom scalars for common patterns:

2.3. Object Types

Each major entity will have a corresponding object type.

text • 102 chars
#### 2.5. Enums & Sorting/Filtering

Enums for fixed values. Input enums for sorting and filtering.

Sandboxed live preview

graphql

type Mutation {

# --- User & Auth Mutations ---

registerUser(input: CreateUserInput!): User!

login(email: String!, password: String!): AuthPayload! # AuthPayload includes token, user

updateUser(id: ID!, input: UpdateUserInput!): User!

deleteUser(id: ID!): Boolean!

# --- Product Mutations (Admin only) ---

createProduct(input: CreateProductInput!): Product!

updateProduct(input: UpdateProductInput!

gemini Output

GraphQL Schema Designer: Comprehensive E-commerce Platform Schema

This document provides a detailed and production-ready GraphQL schema design for an e-commerce platform. It includes type definitions, queries, mutations, subscriptions, conceptual resolver structures, and integration examples for both server-side (Node.js with Apollo Server) and client-side (React with Apollo Client).


1. Introduction & Schema Overview

This GraphQL schema is designed for a robust e-commerce application, enabling clients to interact with various entities such as users, products, categories, reviews, shopping carts, and orders. The design prioritizes clarity, maintainability, and extensibility, leveraging GraphQL's strong typing system.

Key Features:

  • Type Definitions: Clearly defined object types, input types, and enums.
  • Queries: For fetching data (e.g., products, users, orders).
  • Mutations: For modifying data (e.g., adding products, placing orders, updating user profiles).
  • Subscriptions: For real-time updates (e.g., order status changes, product stock alerts).
  • Relational Data: Demonstrates how to link related data efficiently.
  • Input Types: Utilizes distinct input types for mutations for better organization and validation.

2. GraphQL Schema Definition Language (SDL)

The following is the complete GraphQL Schema Definition Language (SDL) for our e-commerce platform.


# --- ENUMS ---
enum OrderStatus {
  PENDING
  PROCESSING
  SHIPPED
  DELIVERED
  CANCELLED
}

enum UserRole {
  CUSTOMER
  ADMIN
}

# --- TYPES ---

type User {
  id: ID!
  email: String!
  username: String!
  firstName: String
  lastName: String
  roles: [UserRole!]!
  address: Address
  orders: [Order!]!
  cart: Cart
  reviews: [Review!]!
  createdAt: String!
  updatedAt: String!
}

type Address {
  street: String!
  city: String!
  state: String!
  zipCode: String!
  country: String!
}

type Product {
  id: ID!
  name: String!
  description: String
  price: Float!
  stock: Int!
  category: Category!
  imageUrls: [String!]!
  reviews: [Review!]!
  createdAt: String!
  updatedAt: String!
}

type Category {
  id: ID!
  name: String!
  products: [Product!]!
  createdAt: String!
  updatedAt: String!
}

type Review {
  id: ID!
  product: Product!
  user: User!
  rating: Int! # 1-5 stars
  comment: String
  createdAt: String!
  updatedAt: String!
}

type Cart {
  id: ID!
  user: User!
  items: [CartItem!]!
  totalItems: Int!
  totalAmount: Float!
}

type CartItem {
  id: ID!
  product: Product!
  quantity: Int!
}

type Order {
  id: ID!
  user: User!
  items: [OrderItem!]!
  totalAmount: Float!
  status: OrderStatus!
  shippingAddress: Address!
  paymentInfo: PaymentInfo!
  createdAt: String!
  updatedAt: String!
}

type OrderItem {
  id: ID!
  product: Product!
  quantity: Int!
  priceAtPurchase: Float! # Price at the time of order
}

type PaymentInfo {
  cardType: String! # e.g., "Visa", "MasterCard"
  last4: String! # Last 4 digits of the card
  expiryMonth: Int!
  expiryYear: Int!
}

# --- INPUT TYPES (for Mutations) ---

input AddressInput {
  street: String!
  city: String!
  state: String!
  zipCode: String!
  country: String!
}

input CreateUserInput {
  email: String!
  username: String!
  password: String! # In a real app, this would be hashed server-side
  firstName: String
  lastName: String
  address: AddressInput
  roles: [UserRole!] = [CUSTOMER] # Default role
}

input UpdateUserInput {
  firstName: String
  lastName: String
  address: AddressInput
  roles: [UserRole!]
}

input CreateProductInput {
  name: String!
  description: String
  price: Float!
  stock: Int!
  categoryId: ID!
  imageUrls: [String!]
}

input UpdateProductInput {
  name: String
  description: String
  price: Float
  stock: Int
  categoryId: ID
  imageUrls: [String!]
}

input CreateCategoryInput {
  name: String!
}

input UpdateCategoryInput {
  name: String
}

input CreateReviewInput {
  productId: ID!
  rating: Int!
  comment: String
}

input AddToCartInput {
  productId: ID!
  quantity: Int!
}

input UpdateCartItemInput {
  cartItemId: ID!
  quantity: Int!
}

input PlaceOrderInput {
  shippingAddress: AddressInput!
  paymentInfo: PaymentInfoInput!
  # In a real app, this might include a payment token from a payment gateway
}

input PaymentInfoInput {
  cardType: String!
  last4: String!
  expiryMonth: Int!
  expiryYear: Int!
  # In a real app, sensitive payment details would be handled via a secure tokenization process
}

# --- QUERIES ---

type Query {
  # User Queries
  users(limit: Int = 10, offset: Int = 0): [User!]!
  user(id: ID!): User
  me: User # Get current authenticated user

  # Product Queries
  products(
    categoryId: ID
    minPrice: Float
    maxPrice: Float
    search: String
    limit: Int = 10
    offset: Int = 0
  ): [Product!]!
  product(id: ID!): Product

  # Category Queries
  categories(limit: Int = 10, offset: Int = 0): [Category!]!
  category(id: ID!): Category

  # Review Queries
  reviewsByProduct(productId: ID!, limit: Int = 10, offset: Int = 0): [Review!]!
  review(id: ID!): Review

  # Cart Queries
  cart(userId: ID!): Cart # Or `myCart` if authentication is handled
  myCart: Cart # Get current authenticated user's cart

  # Order Queries
  orders(userId: ID, status: OrderStatus, limit: Int = 10, offset: Int = 0): [Order!]!
  order(id: ID!): Order
  myOrders: [Order!]! # Get current authenticated user's orders
}

# --- MUTATIONS ---

type Mutation {
  # User Mutations
  createUser(input: CreateUserInput!): User!
  updateUser(id: ID!, input: UpdateUserInput!): User!
  deleteUser(id: ID!): Boolean!

  # Product Mutations (Admin only typically)
  createProduct(input: CreateProductInput!): Product!
  updateProduct(id: ID!, input: UpdateProductInput!): Product!
  deleteProduct(id: ID!): Boolean!
  updateProductStock(productId: ID!, newStock: Int!): Product! # Specific mutation for stock

  # Category Mutations (Admin only typically)
  createCategory(input: CreateCategoryInput!): Category!
  updateCategory(id: ID!, input: UpdateCategoryInput!): Category!
  deleteCategory(id: ID!): Boolean!

  # Review Mutations
  createReview(input: CreateReviewInput!): Review!
  updateReview(id: ID!, rating: Int, comment: String): Review!
  deleteReview(id: ID!): Boolean!

  # Cart Mutations
  addToCart(input: AddToCartInput!): Cart!
  updateCartItem(input: UpdateCartItemInput!): Cart!
  removeCartItem(cartItemId: ID!): Cart!
  clearCart: Cart!

  # Order Mutations
  placeOrder(input: PlaceOrderInput!): Order!
  updateOrderStatus(orderId: ID!, status: OrderStatus!): Order! # Admin only
  cancelOrder(orderId: ID!): Order! # User or Admin
}

# --- SUBSCRIPTIONS ---

type Subscription {
  orderUpdated(orderId: ID!): Order!
  productStockUpdated(productId: ID!): Product!
  newReviewAdded(productId: ID!): Review!
}

3. Resolver Structure (Conceptual)

Resolvers are functions that tell the GraphQL server how to fetch the data for a particular field. Each field in your schema needs a resolver. If a field's parent object has a resolver, the child field's resolver will receive the parent's resolved value.

Here's a conceptual structure for how resolvers would be organized, often within a resolvers.js or index.js file:


// resolvers.js
import {
  users,
  user,
  me
} from './resolvers/userResolver';
import {
  products,
  product
} from './resolvers/productResolver';
// ... other query imports

import {
  createUser,
  updateUser,
  deleteUser
} from './resolvers/userResolver';
import {
  createProduct,
  updateProduct,
  deleteProduct,
  updateProductStock
} from './resolvers/productResolver';
// ... other mutation imports

import {
  orderUpdated,
  productStockUpdated,
  newReviewAdded
} from './resolvers/subscriptionResolver';
// ... other subscription imports

const resolvers = {
  // Enum Resolvers (if needed for custom value mapping, rare)
  OrderStatus: {
    PENDING: 'PENDING',
    PROCESSING: 'PROCESSING',
    SHIPPED: 'SHIPPED',
    DELIVERED: 'DELIVERED',
    CANCELLED: 'CANCELLED',
  },
  UserRole: {
    CUSTOMER: 'CUSTOMER',
    ADMIN: 'ADMIN',
  },

  // Type Resolvers (for nested fields or computed fields)
  User: {
    // Example: Resolve 'orders' field of a User type
    // This resolver will be called if a query specifically asks for `user.orders`
    orders: async (parent, args, context, info) => {
      // 'parent' here is the resolved User object
      return context.dataSources.orderAPI.getOrdersByUserId(parent.id);
    },
    cart: async (parent, args, context, info) => {
      return context.dataSources.cartAPI.getCartByUserId(parent.id);
    },
    reviews: async (parent, args, context, info) => {
      return context.dataSources.reviewAPI.getReviewsByUserId(parent.id);
    },
  },
  Product: {
    category: async (parent, args, context, info) => {
      // 'parent' is the resolved Product object
      return context.dataSources.categoryAPI.getCategoryById(parent.categoryId);
    },
    reviews: async (parent, args, context, info) => {
      return context.dataSources.reviewAPI.getReviewsByProductId(parent.id);
    },
  },
  Category: {
    products: async (parent, args, context, info) => {
      return context.dataSources.productAPI.getProductsByCategoryId(parent.id);
    },
  },
  Cart: {
    items: async (parent, args, context, info) => {
      // Assuming cart items are stored separately and linked by cart ID
      return context.dataSources.cartAPI.getCartItems(parent.id);
    },
    totalItems: (parent) => parent.items.reduce((acc, item) => acc + item.quantity, 0),
    totalAmount: (parent) => parent.items.reduce((acc, item) => acc + (item.product.price * item.quantity), 0),
  },
  CartItem: {
    product: async (parent, args, context, info) => {
      // 'parent' is the resolved CartItem object
      return context.dataSources.productAPI.getProductById(parent.productId);
    },
  },
  Order: {
    items: async (parent, args, context, info) => {
      return context.dataSources.orderAPI.getOrderItems(parent.id);
    },
    user: async (parent, args, context, info) => {
      return context.dataSources.userAPI.getUserById(parent.userId);
    },
  },
  OrderItem: {
    product: async (parent, args, context, info) => {
      return context.dataSources.productAPI.getProductById(parent.productId);
    },
  },
  Review: {
    product: async (parent, args, context, info) => {
      return context.dataSources.productAPI.getProductById(parent.productId);
    },
    user: async (parent, args, context, info) => {
      return context.dataSources.userAPI.getUserById(parent.userId);
    },
  },


  // Root Query Resolvers
  Query: {
    // User Queries
    users, // Function imported from userResolver.js
    user,
    me,
gemini Output

GraphQL Schema Design: Comprehensive E-commerce API

This document presents a comprehensive GraphQL schema design for an E-commerce application. It includes detailed type definitions, queries for data retrieval, mutations for data manipulation, and subscriptions for real-time updates. Furthermore, it outlines the structure for resolvers and provides practical integration examples for client-side consumption.


1. Introduction and Overview

GraphQL is a powerful query language for APIs and a runtime for fulfilling those queries with your existing data. It provides a complete and understandable description of the data in your API, giving clients the power to ask for exactly what they need and nothing more, making it easier to evolve APIs over time.

This schema design focuses on a typical E-commerce domain, covering core entities such as Users, Products, Categories, and Orders. The goal is to provide a flexible and efficient API for managing these resources, supporting both standard CRUD (Create, Read, Update, Delete) operations and real-time functionalities.


2. Core Schema Definition (Schema Definition Language - SDL)

The following is the complete GraphQL Schema Definition Language (SDL) for our E-commerce API.


# --- Scalar Types ---
# Custom scalar for representing a date-time string (e.g., ISO 8601)
scalar DateTime

# --- Enums ---
enum UserRole {
  CUSTOMER
  ADMIN
  SELLER
}

enum OrderStatus {
  PENDING
  PROCESSING
  SHIPPED
  DELIVERED
  CANCELLED
  RETURNED
}

# --- Object Types ---
type User {
  id: ID!
  username: String!
  email: String!
  role: UserRole!
  createdAt: DateTime!
  updatedAt: DateTime!
  orders(
    # Pagination arguments for orders
    first: Int = 10
    after: String
  ): [Order!]!
}

type Product {
  id: ID!
  name: String!
  description: String
  price: Float!
  imageUrl: String
  category: Category!
  stock: Int!
  createdAt: DateTime!
  updatedAt: DateTime!
}

type Category {
  id: ID!
  name: String!
  description: String
  products(
    # Pagination arguments for products within a category
    first: Int = 10
    after: String
  ): [Product!]!
}

type OrderItem {
  product: Product!
  quantity: Int!
  priceAtPurchase: Float! # Price at the time of order
}

type Order {
  id: ID!
  user: User!
  items: [OrderItem!]!
  totalAmount: Float!
  status: OrderStatus!
  createdAt: DateTime!
  updatedAt: DateTime!
}

# --- Input Types for Mutations ---
input CreateUserInput {
  username: String!
  email: String!
  password: String! # Passwords should be hashed before storage
  role: UserRole = CUSTOMER # Default to customer
}

input UpdateUserInput {
  username: String
  email: String
  password: String
  role: UserRole
}

input CreateProductInput {
  name: String!
  description: String
  price: Float!
  imageUrl: String
  categoryId: ID! # Link to an existing category
  stock: Int!
}

input UpdateProductInput {
  name: String
  description: String
  price: Float
  imageUrl: String
  categoryId: ID
  stock: Int
}

input CreateCategoryInput {
  name: String!
  description: String
}

input UpdateCategoryInput {
  name: String
  description: String
}

input OrderItemInput {
  productId: ID!
  quantity: Int!
}

input CreateOrderInput {
  userId: ID! # The user placing the order
  items: [OrderItemInput!]!
}

input UpdateOrderInput {
  status: OrderStatus
}

# --- Query Type ---
type Query {
  # User Queries
  user(id: ID!): User
  users(
    first: Int = 10
    after: String
  ): [User!]!

  # Product Queries
  product(id: ID!): Product
  products(
    categoryId: ID
    search: String
    minPrice: Float
    maxPrice: Float
    first: Int = 10
    after: String
  ): [Product!]!

  # Category Queries
  category(id: ID!): Category
  categories(
    first: Int = 10
    after: String
  ): [Category!]!

  # Order Queries
  order(id: ID!): Order
  orders(
    userId: ID
    status: OrderStatus
    first: Int = 10
    after: String
  ): [Order!]!
}

# --- Mutation Type ---
type Mutation {
  # User Mutations
  createUser(input: CreateUserInput!): User!
  updateUser(id: ID!, input: UpdateUserInput!): User
  deleteUser(id: ID!): Boolean! # Returns true if deletion was successful

  # Product Mutations
  createProduct(input: CreateProductInput!): Product!
  updateProduct(id: ID!, input: UpdateProductInput!): Product
  deleteProduct(id: ID!): Boolean!
  updateProductStock(id: ID!, newStock: Int!): Product

  # Category Mutations
  createCategory(input: CreateCategoryInput!): Category!
  updateCategory(id: ID!, input: UpdateCategoryInput!): Category
  deleteCategory(id: ID!): Boolean!

  # Order Mutations
  createOrder(input: CreateOrderInput!): Order!
  updateOrderStatus(id: ID!, input: UpdateOrderInput!): Order
  cancelOrder(id: ID!): Order # Sets order status to CANCELLED
}

# --- Subscription Type ---
type Subscription {
  # Real-time updates for new orders
  newOrder(userId: ID): Order! # Optionally filter by user

  # Real-time updates when a product's stock changes significantly
  productStockUpdated(productId: ID): Product!

  # Real-time updates when an order's status changes
  orderStatusUpdated(orderId: ID, userId: ID): Order!
}

3. Detailed Schema Components

3.1. Scalar Types

Beyond the built-in String, Int, Float, Boolean, and ID scalars, we introduce a custom scalar:

  • DateTime: Represents a date and time value, typically stored as an ISO 8601 string. This requires a custom serialization/deserialization logic in the resolvers.

3.2. Enums

Enums provide a way to define a set of allowed values for a field.

  • UserRole: Defines the roles a user can have (e.g., CUSTOMER, ADMIN, SELLER).
  • OrderStatus: Defines the various states an order can be in (e.g., PENDING, PROCESSING, SHIPPED, DELIVERED, CANCELLED, RETURNED).

3.3. Object Types

These are the fundamental data structures of our API.

  • User: Represents a user account with basic details and a list of associated orders (with pagination).
  • Product: Details about a specific product, including its category and stock level.
  • Category: Groups products, with a list of products belonging to it (with pagination).
  • OrderItem: Represents a single item within an order, capturing the product, quantity, and the price at the time of purchase (important for historical accuracy).
  • Order: Represents a customer order, linking to the user, listing order items, total amount, and its current status.

3.4. Input Types

Input types are special object types used as arguments for mutations. They prevent repetitive argument definitions and allow for cleaner, more organized mutation signatures.

  • CreateUserInput, UpdateUserInput: For creating and updating user profiles.
  • CreateProductInput, UpdateProductInput: For creating and updating product details.
  • CreateCategoryInput, UpdateCategoryInput: For creating and updating categories.
  • OrderItemInput: Used within CreateOrderInput to specify products and quantities for a new order.
  • CreateOrderInput, UpdateOrderInput: For creating and updating orders.

3.5. Queries

Queries define the read operations clients can perform.

  • User Queries: user(id: ID!) to fetch a single user, users to fetch a list of users with pagination.
  • Product Queries: product(id: ID!) for a single product, products for a list with filtering capabilities (by category, search term, price range) and pagination.
  • Category Queries: category(id: ID!) for a single category, categories for a list with pagination.
  • Order Queries: order(id: ID!) for a single order, orders for a list with filtering by user or status and pagination.

3.6. Mutations

Mutations define the write operations (create, update, delete) clients can perform.

  • User Mutations: createUser, updateUser, deleteUser.
  • Product Mutations: createProduct, updateProduct, deleteProduct, updateProductStock (a specific mutation for a common update).
  • Category Mutations: createCategory, updateCategory, deleteCategory.
  • Order Mutations: createOrder, updateOrderStatus, cancelOrder.

3.7. Subscriptions

Subscriptions enable real-time, push-based communication from the server to the client.

  • newOrder(userId: ID): Notifies clients when a new order is placed, with an optional filter to receive updates only for orders belonging to a specific user.
  • productStockUpdated(productId: ID): Notifies clients when a specific product's stock changes (e.g., after an order or a restock).
  • orderStatusUpdated(orderId: ID, userId: ID): Notifies clients about changes in an order's status, with optional filters.

4. Resolvers: Connecting Schema to Data

Resolvers are functions that tell GraphQL how to fetch the data for a particular field. Every field in the schema (e.g., User.username, Query.product, Mutation.createUser, Subscription.newOrder) has a corresponding resolver function.

Resolver Structure Example (Conceptual - Node.js/JavaScript):


// Example data sources (e.g., database models, external APIs)
const UserModel = require('./models/User');
const ProductModel = require('./models/Product');
const CategoryModel = require('./models/Category');
const OrderModel = require('./models/Order');
const { PubSub } = require('graphql-subscriptions'); // For subscriptions
const pubsub = new PubSub();

// Define PubSub topic constants
const NEW_ORDER = 'NEW_ORDER';
const PRODUCT_STOCK_UPDATED = 'PRODUCT_STOCK_UPDATED';
const ORDER_STATUS_UPDATED = 'ORDER_STATUS_UPDATED';

const resolvers = {
  // Custom Scalar Resolver
  DateTime: {
    serialize(value) {
      return value.toISOString(); // Convert Date object to ISO string
    },
    parseValue(value) {
      return new Date(value); // Convert client string to Date object
    },
    parseLiteral(ast) {
      if (ast.kind === Kind.STRING) {
        return new Date(ast.value);
      }
      return null;
    },
  },

  // Field Resolvers for Object Types (e.g., User.orders)
  User: {
    orders: async (parent, { first, after }) => {
      // 'parent' here is the User object resolved by a Query.user or Query.users
      // Implement pagination logic here (e.g., using cursor-based pagination)
      return OrderModel.find({ userId: parent.id }).limit(first).skip(after ? parseInt(after) : 0);
    },
  },
  Product: {
    category: async (parent) => {
      // 'parent' is the Product object
      return CategoryModel.findById(parent.categoryId);
    },
  },
  OrderItem: {
    product: async (parent) => {
      // 'parent' is the OrderItem object
      return ProductModel.findById(parent.productId);
    },
  },

  // Query Resolvers
  Query: {
    user: async (parent, { id }) => UserModel.findById(id),
    users: async (parent, { first, after }) => UserModel.find().limit(first).skip(after ? parseInt(after) : 0),
    product: async (parent, { id }) => ProductModel.findById(id),
    products: async (parent, args) => {
      // Build query based on args (categoryId, search, minPrice, maxPrice, pagination)
      let query = {};
      if (args.categoryId) query.categoryId = args.categoryId;
      if (args.search) query.name = { $regex: args.search, $options: 'i' }; // Case-insensitive search
      if (args.minPrice) query.price = { ...query.price, $gte: args.minPrice };
      if (args.maxPrice) query.price = { ...query.price, $lte: args.maxPrice };
      return ProductModel.find(query).limit(args.first).skip(args.after ? parseInt(args.after) : 0);
    },
    category: async (parent, { id }) => CategoryModel.findById(id),
    categories: async (parent, { first, after }) => CategoryModel.find().limit(first).skip(after ? parseInt(after) : 0),
    order: async (parent, { id }) => OrderModel.findById(id),
    orders: async (parent, args) => {
      let query = {};
      if (args.userId) query.userId = args.userId;
      if (args.status) query.status = args.status;
      return OrderModel.find(query).limit(args.first).skip(args.after ? parseInt(args.after) : 0);
    },
  },

  // Mutation Resolvers
  Mutation: {
    createUser: async (parent, { input }) => {
      // Hash password before saving
      const hashedPassword = await hashPassword(input.password);
      const newUser = await UserModel.create({ ...input, password: hashedPassword });
      return newUser;
    },
    updateUser: async (parent, { id, input }) => {
      if (input.password) input.password = await hashPassword(input.password);
      return UserModel.findByIdAndUpdate(id, input, { new: true });
    },
    deleteUser: async (parent, { id }) => {
      const result = await UserModel.findByIdAndDelete(id);
      return !!result; // Return true if a document was deleted
    },
    createProduct: async (parent, { input }) => ProductModel.create(input),
    updateProduct: async
graphql_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);}});}