Authentication System
Run ID: 69a79983ca66473bfe6fb3782026-03-29Development
PantheraHive BOS
BOS Dashboard

This document outlines the technical specifications for an authentication system designed for a professional workflow tool. Leveraging Express.js and MongoDB, it integrates JWT for stateless authentication, OAuth2 for Google and GitHub logins, and optional TOTP-based Multi-Factor Authentication. The specification covers architectural design, API endpoints, data models, robust error handling, comprehensive testing, critical security considerations, and a practical deployment guide.

1. Architecture Diagram Description

The authentication system follows a microservice-oriented architecture, with a clear separation of concerns.

Components:

  • Client Applications: Web (React/Angular/Vue) or Mobile (iOS/Android) applications interact with the backend API.
  • Load Balancer/API Gateway (e.g., Nginx, AWS ALB): Acts as the entry point, distributing requests, handling SSL termination, and potentially providing basic rate limiting.
  • Express.js Backend (Authentication Service): This is the core service responsible for all authentication-related logic. It handles user registration, login, token generation/validation, OAuth callbacks, and MFA management. It communicates with the MongoDB database.
  • MongoDB Database: Stores user profiles, hashed passwords, OAuth provider links, MFA secrets, and refresh tokens. It's a NoSQL document database, providing flexibility and scalability.
  • External OAuth2 Providers (Google, GitHub): Third-party identity providers used for social logins. The Express.js backend redirects users to these providers and handles the callback to exchange authorization codes for user information.
  • JWT Tokens: Access tokens are short-lived, signed JSON Web Tokens issued upon successful authentication. They are used by client applications to access protected resources on the backend. Refresh tokens are longer-lived, stored securely, and used to obtain new access tokens without re-authenticating.
  • MFA Service (TOTP): Integrated within the Authentication Service, it manages the generation and verification of Time-based One-Time Passwords (TOTP) using libraries like speakeasy or otp-generator.

Flows:

  1. Local Login: User sends credentials to Express.js, which verifies against MongoDB, generates JWT (access + refresh tokens).
  2. OAuth2 Login: User initiates login via Google/GitHub. Express.js redirects to provider. Provider authenticates user, redirects back to Express.js callback with authorization code. Express.js exchanges code for user data, creates/updates user in MongoDB, generates JWT.
  3. Protected Resource Access: Client sends access token with each request to protected endpoints. Express.js middleware validates the token.
  4. Token Refresh: When access token expires, client sends refresh token to Express.js to obtain a new access token.
  5. MFA: During login, if MFA is enabled, user provides TOTP code which is verified by Express.js against the stored secret.

2. API Endpoints

All API endpoints will be prefixed with /api/v1/auth and return JSON responses.

2.1. Local Authentication

  • POST /api/v1/auth/register

* Description: Registers a new user with email and password.

* Request Body: { email, password, firstName, lastName }

* Response: { message: 'User registered successfully', userId: '...' }

  • POST /api/v1/auth/login

* Description: Authenticates a user with email and password.

* Request Body: { email, password, mfaCode? }

* Response: { accessToken, refreshToken, user: { id, email, firstName, lastName, mfaEnabled } }

  • POST /api/v1/auth/refresh-token

* Description: Exchanges a valid refresh token for a new access token.

* Request Body: { refreshToken }

* Response: { accessToken }

  • POST /api/v1/auth/logout

* Description: Invalidates the provided refresh token, effectively logging out the user.

* Request Body: { refreshToken }

* Response: { message: 'Logged out successfully' }

  • GET /api/v1/auth/me (Protected)

* Description: Retrieves the profile of the authenticated user.

* Response: { id, email, firstName, lastName, roles, mfaEnabled, ... }

  • POST /api/v1/auth/forgot-password

* Description: Initiates password reset process by sending a reset link to the user's email.

* Request Body: { email }

* Response: { message: 'Password reset link sent to email' }

  • POST /api/v1/auth/reset-password

* Description: Resets the user's password using a valid reset token.

* Request Body: { token, newPassword }

* Response: { message: 'Password reset successfully' }

2.2. OAuth2 Authentication

  • GET /api/v1/auth/google

* Description: Initiates Google OAuth2 flow.

* Response: Redirects to Google authentication page.

  • GET /api/v1/auth/google/callback

* Description: Google OAuth2 callback endpoint. Handles user data retrieval and token generation.

* Response: Redirects to client application with accessToken and refreshToken (e.g., via query params or cookie).

  • GET /api/v1/auth/github

* Description: Initiates GitHub OAuth2 flow.

* Response: Redirects to GitHub authentication page.

  • GET /api/v1/auth/github/callback

* Description: GitHub OAuth2 callback endpoint. Handles user data retrieval and token generation.

* Response: Redirects to client application with accessToken and refreshToken.

2.3. Multi-Factor Authentication (TOTP)

  • POST /api/v1/auth/mfa/setup (Protected)

* Description: Generates a new TOTP secret and returns a QR code URL for user setup.

* Response: { qrCodeUrl, secret }

  • POST /api/v1/auth/mfa/verify (Protected)

* Description: Verifies a TOTP code against the generated secret during setup.

* Request Body: { secret, code }

* Response: { verified: true/false }

  • POST /api/v1/auth/mfa/enable (Protected)

* Description: Enables MFA for the authenticated user after successful verification.

* Request Body: { secret, code }

* Response: { message: 'MFA enabled successfully' }

  • POST /api/v1/auth/mfa/disable (Protected)

* Description: Disables MFA for the authenticated user (requires password or current TOTP code for confirmation).

* Request Body: { password | code }

* Response: { message: 'MFA disabled successfully' }

  • POST /api/v1/auth/mfa/authenticate

* Description: Verifies TOTP code during login for users with MFA enabled.

* Request Body: { userId, code }

* Response: { message: 'MFA code verified' } (This would typically be part of the /login flow, but can be a separate step for re-authentication challenges).

3. Data Models (MongoDB)

The following MongoDB schemas will be implemented using Mongoose.

3.1. User Model


const UserSchema = new mongoose.Schema({
  email: {
    type: String,
    required: true,
    unique: true,
    lowercase: true,
    trim: true
  },
  password: {
    type: String, // Hashed password, optional for OAuth-only users
    minlength: 8
  },
  firstName: {
    type: String,
    required: true,
    trim: true
  },
  lastName: {
    type: String,
    required: true,
    trim: true
  },
  roles: [{
    type: String, // e.g., 'user', 'admin', 'manager'
    enum: ['user', 'admin', 'manager'],
    default: 'user'
  }],
  isVerified: {
    type: Boolean,
    default: false // For email verification
  },
  verificationToken: String,
  verificationTokenExpires: Date,
  passwordResetToken: String,
  passwordResetExpires: Date,
  oauthProviders: [{
    provider: { type: String, enum: ['google', 'github'] },
    providerId: String,
    accessToken: String, // Optional, for accessing provider APIs
    refreshToken: String // Optional
  }],
  mfaEnabled: {
    type: Boolean,
    default: false
  },
  mfaSecret: {
    type: String, // Encrypted TOTP secret
    select: false // Do not return by default
  },
  createdAt: {
    type: Date,
    default: Date.now
  },
  updatedAt: {
    type: Date,
    default: Date.now
  }
});

// Pre-save hook for password hashing and updatedAt
UserSchema.pre('save', async function(next) {
  if (this.isModified('password') && this.password) {
    this.password = await bcrypt.hash(this.password, 10);
  }
  this.updatedAt = Date.now();
  next();
});

// Method to compare passwords
UserSchema.methods.comparePassword = async function(candidatePassword) {
  return bcrypt.compare(candidatePassword, this.password);
};

3.2. RefreshToken Model


const RefreshTokenSchema = new mongoose.Schema({
  userId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User',
    required: true
  },
  token: {
    type: String,
    required: true,
    unique: true
  },
  expiresAt: {
    type: Date,
    required: true
  },
  createdAt: {
    type: Date,
    default: Date.now
  },
  ipAddress: String,
  userAgent: String
});

// Index for efficient lookup and expiry
RefreshTokenSchema.index({ expiresAt: 1 }, { expireAfterSeconds: 0 });

4. Error Handling Strategy

A centralized error handling strategy will be implemented using Express.js middleware to ensure consistent and informative error responses.

4.1. Custom Error Classes:

  • AuthError (401 Unauthorized, 403 Forbidden): For authentication/authorization failures.
  • ValidationError (400 Bad Request, 422 Unprocessable Entity): For invalid input data (e.g., missing fields, incorrect format).
  • NotFoundError (404 Not Found): When a requested resource does not exist.
  • ConflictError (409 Conflict): For resource conflicts (e.g., registering with an existing email).
  • InternalServerError (500 Internal Server Error): For unexpected server-side issues.

4.2. Consistent Error Response Format:

All error responses will adhere to a standard JSON structure:


{
  "status": "error",
  "message": "A human-readable error message.",
  "code": "AUTH_001", // An internal error code for programmatic handling
  "statusCode": 401, // HTTP status code
  "details": [ // Optional: specific validation errors or additional info
    { "field": "email", "message": "Email is required." },
    { "field": "password", "message": "Password must be at least 8 characters." }
  ]
}

4.3. Centralized Error Middleware:

An Express.js error handling middleware will catch all errors thrown by routes and other middleware. It will:

  • Log the error details (stack trace, request info) to a logging service (e.g., Winston, Pino).
  • Determine the appropriate HTTP status code and error message based on the error type.
  • Send the standardized JSON error response to the client.
  • Distinguish between operational errors (e.g., ValidationError) that are safe to expose to the client and programming errors (e.g., TypeError) which should be masked as generic 500 errors in production.

4.4. Input Validation:

  • Utilize a robust validation library (e.g., express-validator, Joi) to validate all incoming request bodies and query parameters against defined schemas.
  • Validation errors will be caught and transformed into ValidationError instances.

5. Testing Plan

A multi-faceted testing strategy will be employed to ensure the reliability, security, and performance of the authentication system.

5.1. Unit Tests (Jest)

  • Scope: Individual functions, utility helpers (e.g., password hashing, JWT generation/validation), middleware components (e.g., authentication middleware, role-based access control).
  • Tools: Jest for testing framework, sinon or Jest's built-in mocks for mocking dependencies.
  • Coverage: Aim for high code coverage (e.g., >90%) for critical logic.

5.2. Integration Tests (Supertest & Jest)

  • Scope: Interactions between different modules, API endpoint functionality, database operations, and full request-response cycles for individual endpoints.
  • Tools: Supertest for making HTTP requests to the Express.js application, Jest for assertions.
  • Examples:

* Verify user registration creates a record in MongoDB.

* Test login with correct/incorrect credentials.

* Ensure protected endpoints return 401 without a valid token.

* Test refresh token rotation.

* Verify OAuth callback processes user data correctly.

5.3. End-to-End (E2E) Tests (Cypress/Playwright)

  • Scope: Simulate real user scenarios across the entire application stack, from client UI interaction to backend processing and database updates.
  • Tools: Cypress or Playwright for browser automation.
  • Examples:

* Full user registration, email verification, and login flow.

* Login via Google/GitHub and subsequent access to a protected resource.

* MFA setup and login with TOTP.

* Password reset flow.

5.4. Security Testing

  • Vulnerability Scanning: Regularly use tools like Snyk, OWASP ZAP, or similar to identify known vulnerabilities in dependencies and the application itself.
  • Penetration Testing: Conduct periodic manual or automated penetration tests to uncover potential exploits (e.g., injection flaws, broken authentication, insecure configurations).
  • Code Review: Peer code reviews with a focus on security best practices.
  • Rate Limiting Tests: Verify that rate limiting mechanisms effectively prevent brute-force attacks.

5.5. Performance Testing (JMeter/K6)

  • Scope: Assess the system's responsiveness and stability under various load conditions.
  • Tools: Apache JMeter or K6 for load generation and performance metrics collection.
  • Metrics: Response times, throughput, error rates, resource utilization (CPU, memory).
  • Scenarios: Simulate concurrent user logins, token refreshes, and protected resource access to identify bottlenecks.

6. Security Considerations

Security is paramount for an authentication system. The following measures will be implemented:

6.1. Password Management:

  • Hashing: All passwords will be securely hashed using bcrypt with a sufficient work factor (e.g., 10-12 rounds).
  • Salting: Unique salts will be automatically generated by bcrypt for each password.
  • Complexity: Enforce strong password policies (minimum length, mix of characters).
  • Rate Limiting: Implement rate limiting on login attempts to prevent brute-force attacks.
  • Password Reset: Secure password reset mechanism using single-use, time-limited tokens sent via email.

6.2. JWT and Token Management:

  • Short-lived Access Tokens: Access tokens will have a short expiry (e.g., 15-60 minutes) to minimize the impact of compromise.
  • Secure Refresh Tokens: Refresh tokens will be long-lived (e.g., 7-30 days), stored in an HTTP-only, secure cookie (or database for revocation), and rotated upon use.
  • Token Revocation: Implement a mechanism to revoke refresh tokens (e.g., by blacklisting or removing from the database) upon logout or security incident.
  • Signing Algorithm: Use a strong signing algorithm (e.g., HS256 or RS256) with a robust, securely stored secret key.
  • Token Invalidation on Password Change: Invalidate all active refresh tokens for a user when their password is changed.

6.3. OAuth2 Security:

  • State Parameter: Use a state parameter during OAuth redirects to prevent Cross-Site Request Forgery (CSRF) attacks.
  • PKCE (Proof Key for Code Exchange): Implement PKCE for public clients (e.g., mobile apps) to mitigate authorization code interception attacks.
  • Secure Client Secrets: OAuth client secrets will be stored securely as environment variables and never exposed client-side.

6.4. Multi-Factor Authentication (TOTP):

  • Secret Storage: TOTP secrets will be encrypted at rest in the database.
  • Rate Limiting: Apply rate limiting to TOTP verification attempts.
  • Backup Codes: Consider implementing backup codes for users to regain access if their TOTP device is lost.

6.5. General Security Practices:

  • HTTPS Everywhere: Enforce HTTPS for all communication between clients and the server to protect data in transit.
  • CORS Configuration: Properly configure Cross-Origin Resource Sharing (CORS) to allow only trusted origins.
  • Input Validation & Sanitization: Rigorous validation and sanitization of all user inputs to prevent injection attacks (XSS, NoSQL injection).
  • Dependency Security: Regularly audit and update third-party dependencies to patch known vulnerabilities.
  • Environment Variables: Store all sensitive configuration (database credentials, JWT secrets, OAuth client IDs/secrets) as environment variables.
  • Logging & Monitoring: Implement comprehensive logging of authentication events (successful logins, failed attempts, password resets) and monitor for suspicious activity.
  • Principle of Least Privilege: Ensure that services and users only have the minimum necessary permissions.

7. Deployment Guide

This section outlines the steps and considerations for deploying the authentication system.

7.1. Prerequisites:

  • Node.js (LTS version)
  • npm or Yarn
  • MongoDB instance (local, self-hosted, or cloud service like MongoDB Atlas)
  • Git
  • Docker and Docker Compose (recommended for local development and containerization)

7.2. Environment Setup:

  • Configuration: Create a .env file based on a .env.example template. This file will contain:

* PORT: Application port (e.g., 3000)

* MONGODB_URI: Connection string for MongoDB

* JWT_SECRET: Secret key for signing JWTs (strong, random string)

* JWT_ACCESS_TOKEN_EXPIRATION: e.g., 15m

* JWT_REFRESH_TOKEN_EXPIRATION: e.g., 7d

* OAUTH_GOOGLE_CLIENT_ID, OAUTH_GOOGLE_CLIENT_SECRET, OAUTH_GOOGLE_CALLBACK_URL

* OAUTH_GITHUB_CLIENT_ID, OAUTH_GITHUB_CLIENT_SECRET, OAUTH_GITHUB_CALLBACK_URL

* EMAIL_SERVICE_API_KEY, EMAIL_SENDER_ADDRESS (for password resets, email verification)

* MFA_SECRET_ENCRYPTION_KEY: Key for encrypting MFA secrets in DB

  • Installation: Run npm install or yarn install to install dependencies.

7.3. Local Development & Testing (Docker Compose):

  • Provide a docker-compose.yml file to spin up the Express.js application and a local MongoDB instance for development and testing.
  • docker-compose up --build to build and start services.

7.4. Production Deployment Strategy:

  • Containerization (Docker): Create a Dockerfile for the Express.js application to ensure consistent environments across development and production.
  • Cloud Provider: Deploy to a cloud platform (e.g., AWS, GCP, Azure).

* Compute: AWS EC2, AWS Fargate/ECS, Google Cloud Run, Azure App Service, Kubernetes (EKS, GKE, AKS).

* Database: MongoDB Atlas (managed service) is highly recommended for production due to its scalability, reliability, and security features.

  • Reverse Proxy & Load Balancing:

* Use Nginx or a cloud-native load balancer (e.g., AWS ALB, GCP Load Balancer) to distribute traffic, handle SSL termination, and provide basic security features.

* Configure health checks for the Express.js instances.

  • CI/CD Pipeline: Implement a Continuous Integration/Continuous Deployment (CI/CD) pipeline (e.g., GitHub Actions, GitLab CI, Jenkins).

* Build Stage: Lint, run unit/integration tests, build Docker image.

* Deploy Stage: Push Docker image to a container registry (e.g., Docker Hub, AWS ECR), deploy to staging/production environment.

  • Environment Variables Management: Use the cloud provider's secure secrets management service (e.g., AWS Secrets Manager, GCP Secret Manager) to store sensitive environment variables.
  • Scaling: Configure horizontal auto-scaling for the Express.js instances based on CPU utilization or request load.
  • Monitoring & Logging:

* Integrate with a logging service (e.g., AWS CloudWatch, Google Cloud Logging, ELK Stack) for centralized log collection.

* Set up monitoring and alerting for application health, performance metrics (CPU, memory, request latency), and error rates (e.g., Prometheus/Grafana, Datadog).

7.5. Post-Deployment:

  • Security Audit: Conduct a post-deployment security audit.
  • Backup Strategy: Implement regular database backups.
  • Disaster Recovery: Plan for disaster recovery scenarios.
Recommendations
Next Steps
  1. Detailed API Endpoint Specification: Create a comprehensive OpenAPI/Swagger specification for all API endpoints, including request/response schemas, authentication requirements, and example payloads. 1 week
  2. Database Schema Implementation: Translate the defined data models into Mongoose schemas and implement initial database seeding for development and testing environments. 1 week
  3. Proof-of-Concept (PoC) Implementation: Develop a minimal working PoC for the core authentication flows (local registration/login, JWT generation/validation, and one OAuth provider integration). 2 weeks
  4. Security Audit & Threat Modeling: Conduct an initial threat modeling exercise and a preliminary security audit of the PoC to identify potential vulnerabilities early in the development cycle. 1 week
  5. Performance Benchmarking Plan: Define key performance indicators (KPIs) and outline a plan for performance benchmarking, including tools and target metrics for concurrent users and response times. 0.5 week
authentication_system.md
Download as Markdown
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);}});}