GraphQL Schema Designer
Run ID: 69caf7dc26e01bf7c6786e2c2026-03-30Development
PantheraHive BOS
BOS Dashboard

This document provides a comprehensive and detailed GraphQL schema design for a Project Management System. It includes the full Schema Definition Language (SDL) for types, queries, mutations, and subscriptions, along with conceptual explanations for resolvers and client-side integration examples. This design emphasizes clarity, scalability, and adherence to GraphQL best practices.


GraphQL Schema Design: Project Management System

This GraphQL schema is designed to power a robust Project Management System, enabling clients to fetch, create, update, and subscribe to data related to users, projects, tasks, and comments.

1. Introduction

The goal of this schema is to provide a single, unified API endpoint for managing all aspects of a project lifecycle. It defines a structured way for clients to interact with the system's data, ensuring efficient data fetching and real-time updates.

2. Schema Definition Language (SDL)

The following sections define the GraphQL schema using the Schema Definition Language (SDL).

2.1. Enumerations (Enums)

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

text • 165 chars
#### 2.2. Object Types

Object types are the fundamental building blocks of a GraphQL schema. They represent the kinds of objects you can fetch from your service.

Sandboxed live preview

As "Step 1 of 3: gemini → plan_architecture" for the "GraphQL Schema Designer" workflow, this output addresses the architectural planning considerations for designing a robust GraphQL schema, followed by a comprehensive study plan for individuals aiming to master GraphQL schema design.


Architectural Planning for a GraphQL Schema Design Project

This section outlines the strategic architectural considerations and planning steps for designing a complete and efficient GraphQL schema. This foundational work ensures the resulting schema is robust, scalable, and maintainable.

1. Project Scope and Requirements Gathering

Before designing any part of the schema, a clear understanding of the project's needs is paramount.

  • Business Domain Analysis:

* Identify core business entities (e.g., User, Product, Order, Post).

* Map relationships between entities (e.g., User has many Posts, Order contains Products).

* Define the key attributes for each entity.

  • Data Access Patterns:

* Determine typical read operations (queries) and their complexity (e.g., fetching a single item, lists with filters, nested data).

* Identify write operations (mutations) and the data required for creation, updates, and deletions.

* Ascertain needs for real-time updates (subscriptions) for critical data.

  • Integration Points:

* List all existing data sources (e.g., SQL databases, NoSQL databases, REST APIs, microservices, third-party services).

* Understand the capabilities and limitations of each data source.

  • Performance & Scalability Requirements:

* Anticipate expected data volumes and query loads.

* Identify potential bottlenecks (e.g., N+1 problems, large list fetches).

* Consider caching strategies.

  • Security & Authorization:

* Define authentication mechanisms (e.g., JWT, OAuth).

* Establish granular authorization rules (who can access/modify what data).

* Identify sensitive data fields requiring special protection.

  • Client Needs:

* Understand the types of clients that will consume the API (web, mobile, internal tools).

* Gather specific data requirements from frontend teams to ensure the schema provides the necessary fields efficiently.

2. Core Schema Design Principles

Adhering to best practices ensures a high-quality, maintainable, and extensible schema.

  • Domain-Driven Design:

* Organize the schema around business domains rather than underlying data sources.

* Use clear, descriptive names for types, fields, and arguments that reflect the business language.

  • Graph-First Approach:

* Design the schema as a coherent graph of data, not just a thin layer over existing APIs.

* Focus on what data clients need and how they relate, rather than how data is stored.

  • Consistency & Predictability:

* Maintain consistent naming conventions (e.g., camelCase for fields, PascalCase for types).

* Use standard patterns for common operations like pagination, filtering, and sorting.

  • Extensibility & Versioning:

* Design for future growth; prefer adding new fields to existing types over creating new versions of types.

* Consider a deprecation strategy for old fields/types rather than immediate removal.

* Avoid major version bumps if possible; aim for additive changes.

  • Error Handling:

* Define a consistent error payload structure for mutations.

* Utilize GraphQL's built-in error handling for syntax/validation issues.

3. High-Level Architecture Components

This outlines the structural elements of the GraphQL service and its schema.

  • GraphQL Schema Definition Language (SDL):

* Types: Object types (entities), Scalar types (primitive data), Enum types (fixed values), Interface types (shared fields), Union types (one of several types), Input types (for mutation arguments).

* Root Types: Query (read operations), Mutation (write operations), Subscription (real-time operations).

  • Resolvers:

* Functions that define how to fetch the data for a specific field in the schema.

* Responsible for connecting the GraphQL schema to various data sources.

* Consider using data loaders to solve the N+1 problem for batching data source calls.

  • Data Sources:

* Integration with various backend systems:

* Databases: SQL (PostgreSQL, MySQL), NoSQL (MongoDB, Cassandra), Graph Databases (Neo4j).

* REST APIs: Wrapping existing REST endpoints.

* Microservices: Direct communication or message queues.

  • Security Layer:

* Authentication: Middleware to verify user identity (e.g., checking JWT tokens).

* Authorization: Logic within resolvers or using directives to check user permissions for specific data or operations.

* Input Validation: Ensure incoming arguments are valid and prevent malicious input.

  • GraphQL Server Framework:

* Choice of framework (e.g., Apollo Server, GraphQL Yoga, Express-GraphQL in Node.js; HotChocolate in .NET; Graphene in Python) based on language, ecosystem, and features.

  • Deployment Strategy:

* Serverless: (AWS Lambda, Google Cloud Functions) for cost-efficiency and scalability.

* Containerized: (Docker, Kubernetes) for microservices architecture.

* Managed Services: (AWS AppSync, Hasura) for rapid development and reduced operational overhead.

  • Monitoring & Logging:

* Tools to track query performance, error rates, and server health.

* Structured logging for easy debugging and analysis.

4. Technology Stack Considerations

The choice of technology stack impacts development velocity, performance, and maintainability.

  • Backend Language: Node.js, Python, Java, .NET, Go, Ruby – dictated by existing infrastructure, team expertise, and performance needs.
  • GraphQL Server Library/Framework: Apollo Server, GraphQL Yoga, Express-GraphQL (Node.js); Graphene (Python); HotChocolate (C#); graphql-java (Java).
  • Database: PostgreSQL (relational), MongoDB (document), Neo4j (graph) – chosen based on data structure and access patterns.
  • Caching: Redis, Memcached – for frequently accessed data to reduce database load.
  • Client Libraries: Apollo Client, Relay, URQL – for efficient consumption of the GraphQL API on the frontend.
  • API Gateway: For managing multiple GraphQL services (schema stitching, federation).

5. Design Process and Iteration

GraphQL schema design is an iterative process requiring collaboration.

  • Initial Schema Draft: Based on initial requirements, create a basic schema using SDL.
  • Client Feedback Loop: Share the draft schema with frontend developers. Use tools like GraphiQL/Playground for exploration.
  • Resolver Implementation (Stubs): Implement mock or basic resolvers to demonstrate functionality before connecting to real data sources.
  • Testing: Write unit and integration tests for resolvers and schema validation.
  • Refinement & Evolution: Continuously update and extend the schema based on new requirements and feedback. Implement deprecation gracefully.
  • Documentation: Maintain clear and up-to-date documentation for the schema, including field descriptions and usage examples.

Detailed Study Plan for Becoming a GraphQL Schema Designer

This study plan is designed for developers who wish to gain a deep understanding of GraphQL schema design, from foundational concepts to advanced patterns and best practices.

Overall Goal:

Master the principles, best practices, and practical implementation of GraphQL schema design to build robust, scalable, and maintainable APIs.

Target Audience:

Developers with a foundational understanding of web development and programming concepts (e.g., JavaScript, Python, Java).

Recommended Study Time:

Approximately 10-15 hours per week, spread over 8 weeks.

graphql

--- Enums ---

enum UserRole {

ADMIN

PROJECT_MANAGER

DEVELOPER

VIEWER

}

enum ProjectStatus {

NOT_STARTED

IN_PROGRESS

COMPLETED

ON_HOLD

CANCELLED

}

enum TaskStatus {

OPEN

IN_PROGRESS

REVIEW

DONE

BLOCKED

}

enum TaskPriority {

LOW

MEDIUM

HIGH

URGENT

}

--- Object Types ---

type User {

id: ID!

name: String!

email: String!

role: UserRole!

createdAt: String!

updatedAt: String!

projects: [Project!]!

tasks: [Task!]!

comments: [Comment!]!

}

type Project {

id: ID!

name: String!

description: String

status: ProjectStatus!

startDate: String

endDate: String

createdAt: String!

updatedAt: String!

manager: User!

members: [User!]!

tasks: [Task!]!

}

type Task {

id: ID!

name: String!

description: String

status: TaskStatus!

priority: TaskPriority!

dueDate: String

createdAt: String!

updatedAt: String!

assignedTo: User!

project: Project!

comments: [Comment!]!

}

type Comment {

id: ID!

content: String!

createdAt: String!

updatedAt: String!

author: User!

task: Task!

}

--- Input Types ---

input CreateUserInput {

name: String!

email: String!

role: UserRole!

}

input UpdateUserInput {

name: String

email: String

role: UserRole

}

input CreateProjectInput {

name: String!

description: String

status: ProjectStatus!

startDate: String

endDate: String

managerId: ID!

memberIds: [ID!]

}

input UpdateProjectInput {

name: String

description: String

status: ProjectStatus

startDate: String

endDate: String

managerId: ID

memberIds: [ID!]

}

input CreateTaskInput {

name: String!

description: String

status: TaskStatus!

priority: TaskPriority!

dueDate: String

assignedToId: ID!

projectId: ID!

}

input UpdateTaskInput {

name: String

description: String

status: TaskStatus

priority: TaskPriority

dueDate: String

assignedToId: ID

projectId: ID

}

input CreateCommentInput {

content: String!

taskId: ID!

authorId: ID!

}

--- Root Types ---

type Query {

me: User

users(limit: Int = 10, offset: Int = 0, role: UserRole, search: String): [User!]!

user(id: ID!): User

projects(limit: Int = 10, offset: Int = 0, status: ProjectStatus, managerId: ID, search: String): [Project!]!

project(id: ID!): Project

tasks(limit: Int = 10, offset: Int = 0, status: TaskStatus, priority: TaskPriority, assignedToId: ID, projectId: ID, search: String): [Task!]!

task(id: ID!): Task

comments(limit: Int = 10, offset: Int = 0, taskId: ID, authorId: ID): [Comment!]!

comment(id: ID!): Comment

}

type Mutation {

createUser(input: CreateUserInput!): User!

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

deleteUser(id: ID!): Boolean!

createProject(input: CreateProjectInput!): Project!

updateProject(id: ID!, input: UpdateProjectInput!): Project

deleteProject(id: ID!): Boolean!

addProjectMembers(projectId: ID!, memberIds: [ID!]!): Project

removeProjectMembers(projectId: ID!, memberIds: [ID!]!):

gemini Output

GraphQL Schema Design: Project Management System

This document outlines a comprehensive GraphQL schema design for a Project Management System. It includes detailed definitions for types, queries, mutations, subscriptions, conceptual resolver implementations, and integration examples. This design aims to be flexible, scalable, and easy to consume for both front-end and back-end developers.


1. Introduction

This deliverable provides a complete blueprint for a GraphQL API for a Project Management System. The schema is designed to manage users, projects, tasks, and comments. It leverages best practices such as custom scalars, enums, input types for mutations, and a clear structure for queries, mutations, and subscriptions. Conceptual resolver implementations illustrate how the schema interacts with underlying data sources, and integration examples demonstrate client and server usage.


2. GraphQL Schema Definition Language (SDL)

The following sections define the schema using GraphQL's Schema Definition Language (SDL).

2.1. Custom Scalars

Custom scalars are used for types not natively supported by GraphQL (e.g., dates).


scalar DateTime
# Represents a date and time in ISO 8601 format.

2.2. Enums

Enums define a set of allowed values for a field.


enum UserRole {
  ADMIN
  MANAGER
  DEVELOPER
  VIEWER
}

enum TaskStatus {
  OPEN
  IN_PROGRESS
  REVIEW
  DONE
  BLOCKED
}

enum Priority {
  LOW
  MEDIUM
  HIGH
  CRITICAL
}

2.3. Interfaces

Interfaces define a set of fields that implementing types must include. Useful for polymorphism and global object identification.


interface Node {
  id: ID!
  # The ID of the object.
}

2.4. Object Types

Object types represent the data structures in our system.


type User implements Node {
  id: ID!
  username: String!
  email: String!
  firstName: String
  lastName: String
  role: UserRole!
  createdAt: DateTime!
  updatedAt: DateTime!
  assignedTasks: [Task!]!
  managedProjects: [Project!]!
}

type Project implements Node {
  id: ID!
  name: String!
  description: String
  status: String! # e.g., "Active", "Archived", "On Hold"
  startDate: DateTime
  endDate: DateTime
  manager: User!
  members: [User!]!
  tasks: [Task!]!
  createdAt: DateTime!
  updatedAt: DateTime!
}

type Task implements Node {
  id: ID!
  title: String!
  description: String
  status: TaskStatus!
  priority: Priority!
  dueDate: DateTime
  assignedTo: User
  project: Project!
  comments: [Comment!]!
  createdAt: DateTime!
  updatedAt: DateTime!
}

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

2.5. Input Types

Input types are special object types used as arguments for mutations.


input CreateUserInput {
  username: String!
  email: String!
  firstName: String
  lastName: String
  role: UserRole!
  password: String! # Passwords should be hashed server-side
}

input UpdateUserInput {
  username: String
  email: String
  firstName: String
  lastName: String
  role: UserRole
  password: String # For password change
}

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

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

input CreateTaskInput {
  title: String!
  description: String
  status: TaskStatus
  priority: Priority
  dueDate: DateTime
  assignedToId: ID
  projectId: ID!
}

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

input CreateCommentInput {
  content: String!
  taskId: ID!
}

input ProjectFilterInput {
  nameContains: String
  status: String
  managerId: ID
  memberId: ID
}

input TaskFilterInput {
  projectId: ID
  status: TaskStatus
  priority: Priority
  assignedToId: ID
  dueDateBefore: DateTime
  dueDateAfter: DateTime
}

2.6. Query Type

The Query type defines all possible read operations.


type Query {
  # User Queries
  getUser(id: ID!): User
  getUsers(
    limit: Int = 20
    offset: Int = 0
    role: UserRole
    search: String
  ): [User!]!

  # Project Queries
  getProject(id: ID!): Project
  getProjects(
    limit: Int = 20
    offset: Int = 0
    filter: ProjectFilterInput
  ): [Project!]!

  # Task Queries
  getTask(id: ID!): Task
  getTasks(
    limit: Int = 20
    offset: Int = 0
    filter: TaskFilterInput
  ): [Task!]!

  # Comment Queries
  getComment(id: ID!): Comment
  getCommentsByTask(
    taskId: ID!
    limit: Int = 20
    offset: Int = 0
  ): [Comment!]!
}

2.7. Mutation Type

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


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

  # 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!, userId: ID!): Task!
  unassignTask(taskId: ID!): Task!

  # Comment Mutations
  createComment(input: CreateCommentInput!): Comment!
  updateComment(id: ID!, content: String!): Comment!
  deleteComment(id: ID!): Boolean!
}

2.8. Subscription Type

The Subscription type defines real-time event streams.


type Subscription {
  taskUpdated(projectId: ID!): Task!
  # Notifies when a task within a specific project is updated.

  commentAdded(taskId: ID!): Comment!
  # Notifies when a new comment is added to a specific task.
}

3. Conceptual Resolver Implementations

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

3.1. Resolver Structure

A resolver function typically takes four arguments: (parent, args, context, info).

  • parent: The result of the parent resolver.
  • args: An object containing all arguments passed to the field.
  • context: An object shared across all resolvers in a particular execution. Useful for passing database connections, authentication info, etc.
  • info: Contains information about the execution state of the query (AST, field names, etc.).

3.2. Example: Query Resolvers


// In a Node.js environment using Apollo Server
// Assuming 'dataSources' in context includes services for users, projects, tasks, etc.

const resolvers = {
  Query: {
    async getUser(parent, { id }, { dataSources }) {
      // Example: Fetch from a database via a service layer
      return dataSources.userService.findById(id);
    },
    async getUsers(parent, { limit, offset, role, search }, { dataSources }) {
      // Example: Apply filters and pagination
      return dataSources.userService.find({ limit, offset, role, search });
    },
    async getProject(parent, { id }, { dataSources }) {
      return dataSources.projectService.findById(id);
    },
    async getProjects(parent, { limit, offset, filter }, { dataSources }) {
      return dataSources.projectService.find({ limit, offset, filter });
    },
    // ... other Query resolvers
  },

  // Field-level resolvers for nested data
  Project: {
    async manager(parent, args, { dataSources }) {
      // 'parent' here is the Project object returned by getProject/getProjects
      return dataSources.userService.findById(parent.managerId);
    },
    async members(parent, args, { dataSources }) {
      return dataSources.userService.findByIds(parent.memberIds);
    },
    async tasks(parent, args, { dataSources }) {
      return dataSources.taskService.findByProjectId(parent.id);
    },
  },
  Task: {
    async assignedTo(parent, args, { dataSources }) {
      if (!parent.assignedToId) return null;
      return dataSources.userService.findById(parent.assignedToId);
    },
    async project(parent, args, { dataSources }) {
      return dataSources.projectService.findById(parent.projectId);
    },
    async comments(parent, args, { dataSources }) {
      return dataSources.commentService.findByTaskId(parent.id);
    },
  },
  Comment: {
    async author(parent, args, { dataSources }) {
      return dataSources.userService.findById(parent.authorId);
    },
    async task(parent, args, { dataSources }) {
      return dataSources.taskService.findById(parent.taskId);
    }
  },

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

3.3. Example: Mutation Resolvers


// In a Node.js environment using Apollo Server

const resolvers = {
  Mutation: {
    async createUser(parent, { input }, { dataSources }) {
      // In a real app, hash password before saving
      const newUser = await dataSources.userService.create(input);
      return newUser;
    },
    async updateTask(parent, { id, input }, { dataSources }) {
      const updatedTask = await dataSources.taskService.update(id, input);
      // Publish update for subscriptions (if using PubSub)
      pubsub.publish('TASK_UPDATED', { taskUpdated: updatedTask, projectId: updatedTask.projectId });
      return updatedTask;
    },
    async createComment(parent, { input }, { dataSources, user }) {
      // 'user' might come from authentication context
      const newComment = await dataSources.commentService.create({ ...input, authorId: user.id });
      // Publish new comment for subscriptions
      pubsub.publish('COMMENT_ADDED', { commentAdded: newComment, taskId: newComment.taskId });
      return newComment;
    },
    // ... other Mutation resolvers
  },
};

3.4. Example: Subscription Resolvers

Subscriptions typically require a PubSub (Publish-Subscribe) mechanism.


// In a Node.js environment using Apollo Server with `graphql-subscriptions`

import { PubSub } from 'graphql-subscriptions';
const pubsub = new PubSub();

const resolvers = {
  Subscription: {
    taskUpdated: {
      subscribe: (parent, { projectId }) => {
        // Filter
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);}});}