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

The following output details a comprehensive GraphQL schema for a "Project Management System," encompassing types, queries, mutations, subscriptions, resolver examples, and integration patterns. This design prioritizes clarity, maintainability, and best practices for modern GraphQL applications.


GraphQL Schema Designer: Project Management System

This document provides a complete GraphQL schema for a Project Management System. It includes the Schema Definition Language (SDL), conceptual resolver implementations, and examples for client-side and server-side integration.

1. Introduction

The goal of this deliverable is to provide a robust and extensible GraphQL schema for managing projects, tasks, users, and comments. This schema serves as a foundational blueprint, demonstrating how to structure a GraphQL API with various features, including:

2. Schema Design Philosophy

Our design adheres to the following principles:

3. GraphQL Schema Definition Language (SDL)

The following SDL defines the complete schema for the Project Management System.

text • 485 chars
### 4. Resolver Implementations (Conceptual Examples)

Resolvers are functions that tell GraphQL how to fetch the data for a particular field. Below are conceptual examples using Node.js with `apollo-server` and `graphql-subscriptions` to illustrate how resolvers would be structured.

We'll use a simple in-memory data store for demonstration purposes. In a real application, this would interact with a database (SQL, NoSQL), REST APIs, or other microservices.

**File Structure:**

Sandboxed live preview

As part of the "GraphQL Schema Designer" workflow, this deliverable outlines a comprehensive and actionable study plan. This plan is designed to equip you with the knowledge and practical skills necessary to design complete, robust, and efficient GraphQL schemas, encompassing types, queries, mutations, subscriptions, resolvers, and real-world integration examples.

This document serves as the architectural blueprint for your learning journey, providing a structured approach to mastering GraphQL schema design.


Comprehensive Study Plan for Mastering GraphQL Schema Design

1. Introduction & Overall Goal

This study plan is meticulously crafted to guide developers and architects through the intricacies of GraphQL schema design. By following this plan, you will gain a deep understanding of GraphQL's core principles, learn to design scalable and maintainable schemas, and implement best practices for various use cases.

Overall Goal: To become highly proficient in designing, implementing, and optimizing GraphQL schemas, capable of building robust and efficient data layers for modern applications. This includes a thorough understanding of schema definition, type systems, operation types (queries, mutations, subscriptions), resolver implementation, and practical integration strategies.

2. Target Audience

This plan is ideal for:

  • Backend developers looking to transition to or specialize in GraphQL.
  • Frontend developers seeking a deeper understanding of API design and data fetching.
  • Solution architects responsible for designing data access layers.
  • Anyone with basic programming experience (preferably JavaScript/TypeScript) and a foundational understanding of web APIs (REST).

3. Recommended Time Commitment

This plan is structured for a 4-week intensive study period, assuming an average commitment of 10-15 hours per week. This includes theory, hands-on coding, and project work. Flexibility is built-in, allowing individuals to adjust the pace based on their prior experience and availability. For a more relaxed pace, consider extending each week's content over two weeks.

4. Weekly Schedule, Learning Objectives, Resources, Milestones & Assessment


Week 1: Fundamentals of GraphQL & Schema Basics

Learning Objectives:

  • Understand the core concepts of GraphQL (vs. REST, benefits, use cases).
  • Grasp the GraphQL Type System (Scalar types, Object types, List, Non-Null).
  • Define basic Queries and Mutations.
  • Learn to use Schema Definition Language (SDL) to define a schema.
  • Set up a basic GraphQL server (e.g., Apollo Server, Express-GraphQL).
  • Understand the role of Resolvers and implement simple ones.

Weekly Schedule Focus:

  • Days 1-2: Introduction to GraphQL, comparison with REST, understanding the problem GraphQL solves.
  • Days 3-4: Deep dive into the GraphQL Type System (Scalars, Objects, Lists, Non-Null). Introduction to SDL.
  • Days 5-7: Defining basic Queries and Mutations in SDL. Setting up a minimal GraphQL server with mock data. Implementing simple resolvers. Hands-on with GraphiQL/GraphQL Playground.

Recommended Resources:

  • Official GraphQL Documentation: graphql.org/learn/ (Concepts, Type System, Query Language)
  • Apollo Server Docs: www.apollographql.com/docs/apollo-server/ (Getting Started)
  • Book: "Learning GraphQL" by Eve Porcello & Alex Banks (Chapters 1-3)
  • Online Course: "GraphQL: The Complete Guide" on Udemy (Sections on basics and schema definition)
  • Tool: GraphQL Playground or GraphiQL (for exploring schemas and executing queries)

Milestones:

  • Successfully set up a basic GraphQL server.
  • Define a schema with at least 3 custom object types, 5 queries, and 3 mutations.
  • Implement resolvers for all defined queries and mutations using in-memory data.
  • Execute queries and mutations successfully using GraphQL Playground.

Assessment Strategies:

  • Self-Assessment: Can you explain GraphQL's core advantages and disadvantages compared to REST?
  • Practical: Build a simple "Blog Post" API with posts and authors types, allPosts, post(id), createPost, updatePost operations.
  • Code Review: Review your SDL and resolver code for clarity and correctness.

Week 2: Advanced Schema Design & Data Management

Learning Objectives:

  • Master advanced GraphQL types: Enums, Interfaces, Unions, Input Types.
  • Understand and implement Custom Scalar Types.
  • Learn about Schema Directives and their use cases.
  • Connect GraphQL resolvers to a persistent data source (e.g., PostgreSQL, MongoDB).
  • Implement relationships between types (one-to-many, many-to-many).
  • Understand data loading patterns (e.g., N+1 problem, DataLoader).

Weekly Schedule Focus:

  • Days 1-2: Advanced Type System: Enums, Interfaces, Unions, Input Types. Designing complex data structures.
  • Days 3-4: Custom Scalars and Schema Directives. Practical application of directives for authorization or formatting.
  • Days 5-7: Integrating with a database (e.g., using Prisma, TypeORM, Mongoose). Implementing resolvers that fetch, create, update, and delete data from a database. Introduction to DataLoader for optimizing data fetching.

Recommended Resources:

  • Official GraphQL Documentation: graphql.org/learn/schema/ (Interfaces, Unions, Input Types)
  • Apollo Server Docs: www.apollographql.com/docs/apollo-server/data/data-sources/ (Data Sources, DataLoader)
  • Book: "GraphQL in Action" by John Aucsmith (Chapters on advanced types and data fetching)
  • Article: "The N+1 Problem in GraphQL" and "Solving the N+1 Problem with DataLoader" (search Apollo blog or similar)
  • Tool: Your preferred ORM/ODM (Prisma, TypeORM, Mongoose, Sequelize).

Milestones:

  • Redesign your Week 1 schema to include Interfaces, Unions, and Input Types.
  • Implement a custom scalar (e.g., Date, JSON).
  • Integrate your GraphQL server with a real database and perform CRUD operations.
  • Apply DataLoader to solve an N+1 problem in your schema.

Assessment Strategies:

  • Self-Assessment: Can you explain why DataLoader is crucial for performance?
  • Practical: Extend your "Blog Post" API to include Comments (one-to-many relationship with Posts), using interfaces for User and input types for createComment. Ensure efficient data loading.
  • Code Challenge: Implement a simple authorization directive that restricts access to certain fields.

Week 3: Real-world Applications & Performance

Learning Objectives:

  • Understand and implement Real-time data with GraphQL Subscriptions.
  • Explore different subscription implementations (WebSockets, PubSub).
  • Learn about GraphQL Federation and Schema Stitching for microservices architectures.
  • Implement error handling strategies in GraphQL.
  • Understand pagination techniques (Offset-based, Cursor-based/Relay).
  • Explore caching strategies for GraphQL APIs.

Weekly Schedule Focus:

  • Days 1-2: GraphQL Subscriptions: concept, PubSub implementations, setting up WebSockets.
  • Days 3-4: Advanced Architectures: Introduction to GraphQL Federation (Apollo Federation) and Schema Stitching.
  • Days 5-7: Error Handling best practices. Implementing pagination (especially Relay-style cursor pagination). Discussion on caching at different layers (client-side, server-side).

Recommended Resources:

  • Apollo Server Docs: www.apollographql.com/docs/apollo-server/data/subscriptions/
  • Apollo Federation Docs: www.apollographql.com/docs/federation/
  • Article: "GraphQL Error Handling Best Practices" (search Apollo blog or similar)
  • Book: "Learning GraphQL" by Eve Porcello & Alex Banks (Chapter on Subscriptions)
  • Specification: Relay Cursor Connections specification (relay.dev/graphql/connections.htm)

Milestones:

  • Add a subscription to your existing API (e.g., newPostAdded, commentAdded).
  • Design a simple federated schema with two subgraphs (e.g., users and products).
  • Implement cursor-based pagination for your posts query.
  • Implement custom error handling for specific resolver errors.

Assessment Strategies:

  • Self-Assessment: Describe the differences between schema stitching and federation.
  • Practical: Build a real-time chat feature using GraphQL subscriptions.
  • Design Review: Present a design for a federated GraphQL API for a hypothetical e-commerce platform.

Week 4: Best Practices, Security & Ecosystem

Learning Objectives:

  • Understand GraphQL security considerations (authentication, authorization, rate limiting, depth/complexity limiting).
  • Learn about GraphQL clients (Apollo Client, Relay, Urql) and their features.
  • Explore GraphQL tooling and ecosystem (code generation, testing).
  • Understand schema evolution and versioning strategies.
  • Review GraphQL best practices for schema design and development.
  • Prepare for deployment and monitoring of GraphQL services.

Weekly Schedule Focus:

  • Days 1-2: GraphQL Security: Authentication (JWT, OAuth), Authorization (Role-based, Attribute-based), Rate Limiting, Query Depth/Complexity Limiting.
  • Days 3-4: GraphQL Clients: Introduction to Apollo Client/Relay (features like caching, state management, optimistic UI). Client-side integration.
  • Days 5-7: Schema Evolution & Versioning. Code Generation (e.g., GraphQL Codegen). Testing GraphQL APIs. Best practices roundup, deployment considerations, and monitoring.

Recommended Resources:

  • Apollo Client Docs: www.apollographql.com/docs/react/
  • GraphQL Codegen: www.graphql-code-generator.com/
  • Article: "Securing Your GraphQL API" (search Apollo blog, Hasura blog)
  • Book: "GraphQL in Action" by John Aucsmith (Chapters on security, clients, and deployment)
  • Community: GraphQL Slack, Stack Overflow.

Milestones:

  • Implement authentication and authorization in your GraphQL API (e.g., requiring a JWT for certain mutations).
  • Set up query depth/complexity limiting.
  • Integrate a GraphQL client

javascript

import { v4 as uuidv4 } from 'uuid';

// In-memory mock data store

const users = [

{ id: 'usr-1', name: 'Alice Smith', email: 'alice@example.com' },

{ id: 'usr-2', name: 'Bob Johnson', email: 'bob@example.com' },

];

const projects = [

{ id: 'proj-1', name: 'Website Redesign', description: 'Redesign the company website.', status: 'IN_PROGRESS', startDate: new Date('2023-01-15'), endDate: null, createdAt: new Date(), updatedAt: new Date(), memberIds: ['usr-1', 'usr-2'] },

{ id: 'proj-2', name: 'Mobile App Development', description: 'Develop a new mobile application.', status: 'NOT_STARTED', startDate: null, endDate: null, createdAt: new Date(), updatedAt: new Date(), memberIds: ['usr-1'] },

];

const tasks = [

{ id: 'tsk-1', projectId: 'proj-1', title: 'Design Homepage', description: 'Create mockups for the new homepage.', status: 'IN_PROGRESS', dueDate: new Date('2023-02-10'), assigneeId: 'usr-1', createdAt: new Date(), updatedAt: new Date() },

{ id: 'tsk-2', projectId: 'proj-1', title: 'Develop Contact Form', description: 'Implement the contact us form with validation.', status: 'OPEN', dueDate: new Date('2023-02-20'), assigneeId: 'usr-2', createdAt: new Date(), updatedAt: new Date() },

{ id: 'tsk-3', projectId: 'proj-2', title: 'Setup Project Infrastructure', description:

gemini Output

This document outlines a comprehensive GraphQL schema design for a Project Management System, encompassing types, queries, mutations, subscriptions, resolver considerations, and integration examples. This design provides a robust foundation for building a modern, data-driven application with real-time capabilities.


GraphQL Schema Design: Project Management System

1. Executive Summary

This deliverable presents a detailed GraphQL schema for a Project Management System. The design prioritizes clarity, flexibility, and performance, enabling efficient data fetching and manipulation for various client applications. It includes core object types, input types, enums, a full suite of queries for data retrieval, mutations for data modification, and subscriptions for real-time updates. Furthermore, it outlines key resolver design principles and provides conceptual integration examples for both frontend and backend development.

2. Core Schema Definition (Type System)

The foundation of our GraphQL API is its type system. We define the various data structures that clients can query and manipulate.

2.1. Custom Scalars

Standard GraphQL scalars (ID, String, Int, Float, Boolean) are sufficient for most cases. However, for specific data types like dates and times, custom scalars provide better type safety and clarity.


scalar DateTime

2.2. Enums

Enums define a set of allowed values for a field, ensuring data consistency.


enum UserRole {
  ADMIN
  MANAGER
  MEMBER
  GUEST
}

enum TaskStatus {
  OPEN
  IN_PROGRESS
  REVIEW
  DONE
  ARCHIVED
}

enum ProjectStatus {
  ACTIVE
  ON_HOLD
  COMPLETED
  CANCELLED
}

enum Priority {
  LOW
  MEDIUM
  HIGH
  CRITICAL
}

2.3. Object Types

These are the fundamental building blocks, representing the data entities in our system.


type User {
  id: ID!
  email: String!
  username: String!
  firstName: String
  lastName: String
  role: UserRole!
  projects: [Project!]!
  tasks: [Task!]!
  createdAt: DateTime!
  updatedAt: DateTime!
}

type Project {
  id: ID!
  name: String!
  description: String
  status: ProjectStatus!
  startDate: DateTime
  endDate: DateTime
  owner: User!
  members: [User!]!
  tasks(status: TaskStatus, priority: Priority): [Task!]! # Filterable tasks
  createdAt: DateTime!
  updatedAt: DateTime!
}

type Task {
  id: ID!
  title: String!
  description: String
  status: TaskStatus!
  priority: Priority!
  dueDate: DateTime
  project: Project!
  assignee: User # Optional assignee
  reporter: User!
  comments: [Comment!]!
  createdAt: DateTime!
  updatedAt: DateTime!
}

type Comment {
  id: ID!
  content: String!
  author: User!
  task: Task!
  createdAt: DateTime!
  updatedAt: DateTime!
}

2.4. Input Types

Input types are used for arguments in mutations, providing a structured way to pass complex data.


input CreateUserInput {
  email: String!
  username: String!
  firstName: String
  lastName: String
  role: UserRole = MEMBER # Default role
}

input UpdateUserInput {
  email: String
  username: String
  firstName: String
  lastName: String
  role: UserRole
}

input CreateProjectInput {
  name: String!
  description: String
  startDate: DateTime
  endDate: DateTime
  ownerId: ID!
  memberIds: [ID!]
}

input UpdateProjectInput {
  name: String
  description: String
  status: ProjectStatus
  startDate: DateTime
  endDate: DateTime
  ownerId: ID
  memberIds: [ID!]
}

input CreateTaskInput {
  projectId: ID!
  title: String!
  description: String
  status: TaskStatus = OPEN # Default status
  priority: Priority = MEDIUM # Default priority
  dueDate: DateTime
  assigneeId: ID
  reporterId: ID!
}

input UpdateTaskInput {
  title: String
  description: String
  status: TaskStatus
  priority: Priority
  dueDate: DateTime
  assigneeId: ID
}

input AddCommentInput {
  content: String!
  authorId: ID!
}

3. Queries (Read Operations)

The Query type defines all possible read operations clients can perform.


type Query {
  # User Queries
  me: User # Get the currently authenticated user
  user(id: ID!): User
  users(role: UserRole, search: String): [User!]! # Filterable list of users

  # Project Queries
  project(id: ID!): Project
  projects(status: ProjectStatus, ownerId: ID, memberId: ID, search: String): [Project!]! # Filterable list of projects

  # Task Queries
  task(id: ID!): Task
  tasks(
    projectId: ID!
    status: TaskStatus
    priority: Priority
    assigneeId: ID
    reporterId: ID
    search: String
  ): [Task!]! # Filterable list of tasks for a project

  # Comment Queries
  comment(id: ID!): Comment
  comments(taskId: ID!): [Comment!]!
}

4. Mutations (Write Operations)

The Mutation type defines all possible write (create, update, delete) operations.


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

  # Project Mutations
  createProject(input: CreateProjectInput!): Project!
  updateProject(id: ID!, input: UpdateProjectInput!): Project!
  deleteProject(id: ID!): Boolean!
  addProjectMember(projectId: ID!, userId: ID!): Project!
  removeProjectMember(projectId: ID!, userId: ID!): Project!

  # Task Mutations
  createTask(input: CreateTaskInput!): Task!
  updateTask(id: ID!, input: UpdateTaskInput!): Task!
  deleteTask(id: ID!): Boolean!
  assignTask(taskId: ID!, assigneeId: ID!): Task!
  unassignTask(taskId: ID!): Task!

  # Comment Mutations
  addCommentToTask(taskId: ID!, input: AddCommentInput!): Comment!
  updateComment(id: ID!, content: String!): Comment!
  deleteComment(id: ID!): Boolean!
}

5. Subscriptions (Real-time Operations)

The Subscription type enables clients to receive real-time updates when specific events occur.


type Subscription {
  taskAdded(projectId: ID!): Task! # Notifies when a new task is added to a project
  taskUpdated(taskId: ID!): Task! # Notifies when a specific task is updated
  commentAdded(taskId: ID!): Comment! # Notifies when a new comment is added to a task
  projectUpdated(projectId: ID!): Project! # Notifies when a specific project is updated
}

6. Resolver Design Principles

Resolvers are functions that tell the GraphQL server how to fetch the data for a particular field. They are the bridge between the GraphQL schema and your backend data sources (databases, REST APIs, microservices, etc.).

6.1. Core Resolver Structure


// Example resolver for a 'Project' type's 'owner' field
const resolvers = {
  Query: {
    project: async (parent, { id }, context, info) => {
      // context typically contains authenticated user, data loaders, etc.
      // info contains the AST of the query
      return context.dataSources.projectAPI.getProjectById(id);
    },
    projects: async (parent, args, context) => {
      return context.dataSources.projectAPI.getProjects(args);
    },
    me: async (parent, args, context) => {
      // Assumes context.user is populated by authentication middleware
      if (!context.user) throw new AuthenticationError('Not authenticated');
      return context.dataSources.userAPI.getUserById(context.user.id);
    },
  },
  Mutation: {
    createTask: async (parent, { input }, context) => {
      if (!context.user) throw new AuthenticationError('Not authenticated');
      // Ensure reporterId is the authenticated user or validate input
      input.reporterId = context.user.id;
      return context.dataSources.taskAPI.createTask(input);
    },
    updateTask: async (parent, { id, input }, context) => {
      if (!context.user) throw new AuthenticationError('Not authenticated');
      // Authorization check: Does context.user have permission to update this task?
      const existingTask = await context.dataSources.taskAPI.getTaskById(id);
      if (!existingTask || !context.authService.canUpdateTask(context.user, existingTask)) {
        throw new ForbiddenError('Not authorized to update this task');
      }
      return context.dataSources.taskAPI.updateTask(id, input);
    },
  },
  Subscription: {
    taskAdded: {
      subscribe: (parent, { projectId }, context) =>
        context.pubsub.asyncIterator(`TASK_ADDED_${projectId}`),
    },
    taskUpdated: {
      subscribe: (parent, { taskId }, context) =>
        context.pubsub.asyncIterator(`TASK_UPDATED_${taskId}`),
    },
  },
  // Field-level resolvers for nested data
  Project: {
    owner: async (parent, args, context) => {
      // 'parent' here is the Project object returned by the 'project' or 'projects' resolver
      return context.dataSources.userAPI.getUserById(parent.ownerId);
    },
    members: async (parent, args, context) => {
      return context.dataSources.userAPI.getUsersByIds(parent.memberIds);
    },
    tasks: async (parent, args, context) => {
      // N+1 problem mitigation: DataLoader should be used for efficient batching if many projects are fetched
      return context.dataSources.taskAPI.getTasksByProjectId(parent.id, args);
    },
  },
  Task: {
    project: async (parent, args, context) => {
      return context.dataSources.projectAPI.getProjectById(parent.projectId);
    },
    assignee: async (parent, args, context) => {
      if (!parent.assigneeId) return null;
      return context.dataSources.userAPI.getUserById(parent.assigneeId);
    },
    reporter: async (parent, args, context) => {
      return context.dataSources.userAPI.getUserById(parent.reporterId);
    },
    comments: async (parent, args, context) => {
      return context.dataSources.commentAPI.getCommentsByTaskId(parent.id);
    },
  },
  Comment: {
    author: async (parent, args, context) => {
      return context.dataSources.userAPI.getUserById(parent.authorId);
    },
    task: async (parent, args, context) => {
      return context.dataSources.taskAPI.getTaskById(parent.taskId);
    },
  },
  // Custom Scalar Resolver
  DateTime: {
    serialize: (value) => value.toISOString(), // Convert outgoing Date to ISOString
    parseValue: (value) => new Date(value), // Convert incoming value to Date
    parseLiteral: (ast) => (ast.kind === Kind.STRING ? new Date(ast.value) : null), // Convert AST to Date
  },
};

6.2. Key Considerations for Resolvers

  • Data Sources: Encapsulate database access, REST API calls, or microservice communication within dedicated data source classes (e.g., UserAPI, ProjectAPI). This promotes modularity and testability.
  • Context Object: Use the context object to pass request-scoped information (e.g., authenticated user, session data, data loaders, pub/sub instance) down to all resolvers.
  • N+1 Problem Mitigation: For fetching related data (e.g., Project.owner, Task.assignee), utilize [DataLoader](https://github.com/graphql/dataloader) to batch requests and prevent the N+1 query problem, significantly improving performance.
  • Authentication & Authorization: Implement middleware to authenticate users and populate context.user. Resolvers should then perform authorization checks based on context.user's roles and permissions.
  • Error Handling: Resolvers should throw specific errors (e.g., AuthenticationError, ForbiddenError, UserInputError) that can be caught and formatted by the GraphQL server.
  • Input Validation: While GraphQL handles type validation, resolvers should perform business logic validation (e.g., project end date cannot be before start date).
  • Pub/Sub for Subscriptions: Use a Publish/Subscribe mechanism (e.g., graphql-subscriptions with Redis, Kafka, or a simple in-memory implementation for development) to trigger subscription events.

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);}});}