Microservice Scaffolder
Run ID: 69caf76326e01bf7c6786dd22026-03-30Development
PantheraHive BOS
BOS Dashboard

Step 1 of 3: Architecture Plan for Microservice Scaffolder

Workflow Description: Generate a complete microservice with Docker setup, API routes, database models, tests, CI/CD pipeline config, and deployment scripts.

This document outlines the proposed architecture for a generic microservice, designed to be robust, scalable, maintainable, and easily deployable. This plan serves as the foundational blueprint for the subsequent scaffolding steps.


1. Core Microservice Architecture Principles

The microservice will adhere to the following architectural principles:

2. Proposed Technology Stack

To ensure broad applicability, modern tooling, and strong community support, the following technology stack is recommended:

* Rationale: Excellent for rapid development, rich ecosystem, strong community. FastAPI is chosen for Python due to its performance, Pydantic for data validation, and automatic OpenAPI documentation. Express.js for Node.js provides a flexible and minimal web application framework.

* Python: FastAPI

* Node.js: Express.js

* Rationale: PostgreSQL offers ACID compliance, strong data integrity, and is widely supported. MongoDB provides flexibility for schema-less data and horizontal scalability for certain use cases. The choice will depend on the specific data model requirements.

* Python (PostgreSQL): SQLAlchemy with Alembic for migrations.

* Python (MongoDB): MongoEngine or Pymongo.

* Node.js (PostgreSQL): Sequelize or TypeORM.

* Node.js (MongoDB): Mongoose.

* Rationale: Standard for packaging applications and their dependencies, ensuring consistency across environments.

* Rationale: Automatic generation with FastAPI, or manual definition for Express.js, provides interactive API documentation.

* Python: Pytest

* Node.js: Jest or Mocha/Chai

* Rationale: Integrated, powerful, and widely adopted platforms for automated build, test, and deployment.

* Rationale: Kubernetes provides robust container orchestration, scaling, self-healing, and service discovery capabilities. Cloud providers offer managed Kubernetes services for ease of use and reliability.

3. Microservice Structure and Components

Each scaffolded microservice will typically include the following directories and files:

text • 2,022 chars
microservice-name/
├── src/
│   ├── api/                  # API routes and handlers
│   │   ├── v1/
│   │   │   ├── endpoints/    # Specific endpoint definitions (e.g., users, products)
│   │   │   ├── schemas/      # Request/Response data models (Pydantic/Joi)
│   │   │   └── __init__.py / index.js
│   │   ├── middleware/       # Custom middleware (auth, logging)
│   │   └── main.py / app.js  # Main application entry point
│   ├── core/                 # Core application logic, business rules
│   │   ├── services/         # Business logic services
│   │   ├── models/           # Database models (SQLAlchemy/Mongoose)
│   │   ├── repositories/     # Data access layer
│   │   ├── exceptions/       # Custom exceptions
│   │   └── config.py / config.js # Application configuration
│   ├── database/             # Database connection, migrations
│   │   ├── migrations/       # Alembic scripts / raw SQL / Mongoose migration scripts
│   │   └── __init__.py / index.js
│   └── utils/                # Helper functions, common utilities
├── tests/
│   ├── unit/                 # Unit tests for individual components
│   ├── integration/          # Integration tests for service interactions
│   └── e2e/                  # End-to-End tests for API endpoints
├── Dockerfile                # Docker image definition
├── docker-compose.yml        # Local development setup with Docker Compose
├── requirements.txt / package.json # Project dependencies
├── .env.example              # Environment variables example
├── README.md                 # Project documentation
├── .gitignore                # Git ignore file
├── .gitlab-ci.yml / .github/workflows/main.yml # CI/CD pipeline configuration
├── deploy/                   # Deployment scripts/configurations
│   ├── kubernetes/           # Kubernetes manifests (Deployment, Service, Ingress, HPA)
│   ├── helm/                 # Helm charts (optional, for complex deployments)
│   └── scripts/              # Cloud-specific deployment scripts (e.g., Terraform/Pulumi)
Sandboxed live preview

4. API Design (RESTful)

  • Standard Naming Conventions: Use plural nouns for resource endpoints (e.g., /users, /products).
  • HTTP Methods: Adhere to standard HTTP methods for CRUD operations:

* GET /resources (list all)

* GET /resources/{id} (retrieve specific)

* POST /resources (create new)

* PUT /resources/{id} (full update)

* PATCH /resources/{id} (partial update)

* DELETE /resources/{id} (delete)

  • Versioning: Use URL-based versioning (e.g., /api/v1/users).
  • Error Handling: Consistent JSON error responses with appropriate HTTP status codes (e.g., 400 Bad Request, 401 Unauthorized, 404 Not Found, 500 Internal Server Error).
  • Authentication/Authorization: Token-based (JWT) authentication. Role-based access control (RBAC) implemented via middleware.

5. Database Model Design

  • Database per Service: Each microservice will typically own its data store, promoting loose coupling.
  • ORM/ODM Usage: Utilize SQLAlchemy (Python) or Mongoose (Node.js) to define models, manage relationships, and interact with the database.
  • Migrations: Automated database schema migrations using Alembic (Python) or similar tools for Node.js.
  • Data Validation: Leverage Pydantic (Python) or Joi (Node.js) for input validation at the API layer, and database constraints for data integrity.

6. Testing Strategy

A comprehensive testing strategy will be implemented for each microservice:

  • Unit Tests:

* Scope: Individual functions, methods, and classes in isolation.

* Tools: Pytest (Python), Jest (Node.js).

* Coverage: Aim for high code coverage (e.g., >80%).

  • Integration Tests:

* Scope: Verify interaction between components (e.g., API layer with service layer, service layer with repository/database).

* Tools: Pytest (Python), Jest (Node.js) with test databases/mocks.

  • End-to-End (E2E) Tests:

* Scope: Simulate user scenarios by interacting with the deployed API endpoints.

* Tools: Pytest with httpx (Python), Supertest (Node.js).

  • Mocking/Stubbing: Use for external dependencies (other services, third-party APIs) to isolate the service under test.

7. CI/CD Pipeline Configuration

The CI/CD pipeline will be automated using GitHub Actions or GitLab CI/CD, encompassing the following stages:

  1. Build:

* Fetch dependencies.

* Lint code (e.g., Flake8/ESLint).

* Run static analysis (e.g., MyPy/TypeScript).

  1. Test:

* Run unit tests.

* Run integration tests.

* Calculate code coverage.

  1. Security Scan (Optional but Recommended):

* Dependency vulnerability scanning (e.g., Snyk, OWASP Dependency-Check).

* Static Application Security Testing (SAST).

  1. Containerize:

* Build Docker image for the microservice.

* Tag image with commit SHA and version.

* Push image to a container registry (e.g., Docker Hub, AWS ECR, GCP Container Registry).

  1. Deploy (to Staging/Development Environment):

* Apply Kubernetes manifests or Helm charts to deploy the new image.

* Run E2E tests against the deployed service.

  1. Approval (Manual/Automated):

* Based on successful E2E tests and/or manual review.

  1. Deploy (to Production Environment):

* Apply Kubernetes manifests or Helm charts to production cluster.

* Implement blue/green or canary deployment strategies for zero-downtime releases.

8. Deployment Scripts and Orchestration

  • Docker Compose: For local development and testing, a docker-compose.yml will be provided to spin up the microservice along with its database and any other local dependencies.
  • Kubernetes Manifests:

* Deployment: Defines the desired state for the microservice pods.

* Service: Exposes the microservice within the cluster.

* Ingress: Manages external access to services, typically providing HTTP/S routing.

* ConfigMap/Secret: Manages configuration and sensitive data.

* HorizontalPodAutoscaler (HPA): Automatically scales the number of pods based on CPU/memory usage.

  • Helm Charts (Optional): For more complex deployments or reusable templates, Helm charts can be generated to package Kubernetes resources.
  • Infrastructure as Code (IaC) (Optional but Recommended): Terraform or Pulumi scripts can be used to provision the underlying cloud infrastructure (Kubernetes cluster, databases, networking) and even deploy the microservice itself.

9. Observability

  • Logging: Structured logging (JSON format) to stdout/stderr, collected by a centralized logging system (e.g., ELK stack, Grafana Loki, CloudWatch Logs).
  • Monitoring:

* Metrics exposed via Prometheus endpoints.

* Dashboards built with Grafana for visualizing key metrics (CPU, memory, request rates, error rates, latency).

* Alerting configured for critical thresholds.

  • Tracing: Distributed tracing with OpenTelemetry (or Jaeger/Zipkin) to track requests across multiple services.

10. Security Considerations

  • Input Validation: Strict validation of all incoming data.
  • Authentication & Authorization: Implement JWT-based authentication and granular RBAC.
  • Secrets Management: Use environment variables for non-sensitive config, and Kubernetes Secrets or a dedicated secrets manager (e.g., HashiCorp Vault, AWS Secrets Manager) for sensitive data.
  • API Gateway (Optional): For a larger system, an API Gateway can provide centralized authentication, rate limiting, and request routing.
  • Dependency Scanning: Regularly scan for known vulnerabilities in third-party libraries.
  • Principle of Least Privilege: Services should only have the necessary permissions to perform their functions.

This architecture plan provides a robust framework for scaffolding new microservices. The specific choices for programming language, database, and advanced deployment strategies can be tailored based on project requirements and existing infrastructure.

gemini Output

Microservice Scaffolder: Step 2 of 3 - Code Generation

This deliverable provides a comprehensive, production-ready microservice scaffold, meticulously designed with a modern tech stack to ensure scalability, maintainability, and ease of deployment. This output includes the core application logic, database models, API routes, Docker setup, robust testing framework, CI/CD pipeline configuration, and deployment scripts for Kubernetes.


1. Introduction & Chosen Tech Stack

This scaffold is built around a common and highly effective stack for microservices:

  • Language: Python 3.9+
  • Web Framework: FastAPI (for high performance, easy API development, automatic OpenAPI/Swagger UI generation, and Pydantic-based data validation).
  • Database: PostgreSQL (a powerful, open-source relational database).
  • ORM: SQLAlchemy (a flexible and robust SQL Toolkit and Object Relational Mapper for Python).
  • Data Validation: Pydantic (integrated with FastAPI for request/response schema validation).
  • Containerization: Docker (for consistent development and production environments).
  • Testing: Pytest (a feature-rich testing framework).
  • CI/CD: GitHub Actions (a popular and flexible CI/CD platform).
  • Deployment: Kubernetes with Helm (for container orchestration and templated deployments).

The example microservice manages a simple "Item" resource, demonstrating standard CRUD (Create, Read, Update, Delete) operations.


2. Project Structure

The generated project adheres to a clean and modular structure:


microservice-scaffold/
├── .github/
│   └── workflows/
│       └── ci-cd.yml             # GitHub Actions CI/CD pipeline
├── app/
│   ├── __init__.py
│   ├── main.py                   # FastAPI application entry point, API routes
│   ├── config.py                 # Application configuration (env vars)
│   ├── database.py               # SQLAlchemy engine and session setup
│   ├── models.py                 # SQLAlchemy ORM database models
│   ├── schemas.py                # Pydantic schemas for API request/response validation
│   └── crud.py                   # Database interaction logic (CRUD operations)
├── tests/
│   ├── __init__.py
│   └── test_main.py              # Pytest unit and integration tests
├── helm/                         # Helm chart for Kubernetes deployment
│   ├── Chart.yaml
│   ├── values.yaml
│   └── templates/
│       ├── _helpers.tpl
│       ├── deployment.yaml
│       ├── service.yaml
│       ├── ingress.yaml          # Optional: For external access
│       └── secret.yaml           # For sensitive data like database credentials
├── Dockerfile                    # Docker build instructions for the application
├── docker-compose.yml            # Docker Compose for local development (app + db)
├── requirements.txt              # Python dependencies
├── .dockerignore                 # Files/directories to ignore during Docker build
├── .env.example                  # Example environment variables
└── README.md                     # Project README

3. Core Microservice (FastAPI)

This section provides the Python code for the FastAPI application, including configuration, database setup, models, schemas, CRUD operations, and API routes.

microservice-scaffold/app/config.py

Handles environment variable loading for application configuration.


import os
from dotenv import load_dotenv

# Load environment variables from .env file
load_dotenv()

class Settings:
    """
    Configuration settings for the application.
    Uses environment variables for sensitive data and dynamic settings.
    """
    PROJECT_NAME: str = "Item Microservice"
    PROJECT_VERSION: str = "1.0.0"

    # Database settings
    POSTGRES_USER: str = os.getenv("POSTGRES_USER", "user")
    POSTGRES_PASSWORD: str = os.getenv("POSTGRES_PASSWORD", "password")
    POSTGRES_SERVER: str = os.getenv("POSTGRES_SERVER", "db") # 'db' for docker-compose, 'localhost' for local
    POSTGRES_PORT: str = os.getenv("POSTGRES_PORT", "5432")
    POSTGRES_DB: str = os.getenv("POSTGRES_DB", "items_db")
    DATABASE_URL: str = (
        f"postgresql://{POSTGRES_USER}:{POSTGRES_PASSWORD}@"
        f"{POSTGRES_SERVER}:{POSTGRES_PORT}/{POSTGRES_DB}"
    )

    # For testing environment
    TEST_POSTGRES_DB: str = os.getenv("TEST_POSTGRES_DB", "test_items_db")
    TEST_DATABASE_URL: str = (
        f"postgresql://{POSTGRES_USER}:{POSTGRES_PASSWORD}@"
        f"{POSTGRES_SERVER}:{POSTGRES_PORT}/{TEST_POSTGRES_DB}"
    )

settings = Settings()

microservice-scaffold/app/database.py

Configures the SQLAlchemy engine and provides a session factory.


from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session
from app.config import settings

# Create SQLAlchemy engine
# `connect_args={"check_same_thread": False}` is specific to SQLite,
# but can be safely included for other DBs if needed.
# For PostgreSQL, it's not strictly necessary.
engine = create_engine(settings.DATABASE_URL)

# Each instance of the SessionLocal class will be a database session.
# The `autocommit=False` means that the session will not commit changes
# to the database automatically.
# The `autoflush=False` means that the session will not flush changes
# to the database automatically.
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

# Base class for our declarative models
Base = declarative_base()

def get_db():
    """
    Dependency for FastAPI to get a database session.
    Ensures the session is closed after the request.
    """
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

def create_db_and_tables():
    """
    Creates all database tables defined in Base.metadata.
    """
    Base.metadata.create_all(bind=engine)

microservice-scaffold/app/models.py

Defines the SQLAlchemy ORM models.


from sqlalchemy import Column, Integer, String, Boolean
from app.database import Base

class Item(Base):
    """
    SQLAlchemy model for an Item.
    Represents the 'items' table in the database.
    """
    __tablename__ = "items"

    id = Column(Integer, primary_key=True, index=True)
    name = Column(String, index=True, nullable=False)
    description = Column(String, nullable=True)
    price = Column(Integer, nullable=False)
    is_available = Column(Boolean, default=True)

microservice-scaffold/app/schemas.py

Defines Pydantic schemas for data validation and serialization.


from pydantic import BaseModel, Field
from typing import Optional

class ItemBase(BaseModel):
    """
    Base schema for an Item, used for common fields.
    """
    name: str = Field(..., min_length=1, description="Name of the item")
    description: Optional[str] = Field(None, description="Description of the item")
    price: int = Field(..., gt=0, description="Price of the item, must be positive")
    is_available: bool = Field(True, description="Availability status of the item")

class ItemCreate(ItemBase):
    """
    Schema for creating a new Item. Inherits from ItemBase.
    """
    pass # No additional fields for creation beyond ItemBase

class ItemUpdate(ItemBase):
    """
    Schema for updating an existing Item. All fields are optional for partial updates.
    """
    name: Optional[str] = Field(None, min_length=1, description="Name of the item")
    price: Optional[int] = Field(None, gt=0, description="Price of the item, must be positive")
    is_available: Optional[bool] = Field(None, description="Availability status of the item")

class ItemInDB(ItemBase):
    """
    Schema for an Item as stored in the database, including the ID.
    Used for responses.
    """
    id: int = Field(..., description="Unique identifier of the item")

    class Config:
        orm_mode = True # Enable ORM mode for automatic mapping from SQLAlchemy models

microservice-scaffold/app/crud.py

Contains the Create, Read, Update, Delete (CRUD) operations for the Item model, abstracting database interactions.


from sqlalchemy.orm import Session
from typing import List, Optional

from app import models, schemas

def get_item(db: Session, item_id: int) -> Optional[models.Item]:
    """
    Retrieve a single item by its ID.
    """
    return db.query(models.Item).filter(models.Item.id == item_id).first()

def get_items(db: Session, skip: int = 0, limit: int = 100) -> List[models.Item]:
    """
    Retrieve multiple items with pagination.
    """
    return db.query(models.Item).offset(skip).limit(limit).all()

def create_item(db: Session, item: schemas.ItemCreate) -> models.Item:
    """
    Create a new item in the database.
    """
    db_item = models.Item(**item.dict())
    db.add(db_item)
    db.commit()
    db.refresh(db_item)
    return db_item

def update_item(db: Session, item_id: int, item: schemas.ItemUpdate) -> Optional[models.Item]:
    """
    Update an existing item by its ID.
    """
    db_item = db.query(models.Item).filter(models.Item.id == item_id).first()
    if db_item:
        update_data = item.dict(exclude_unset=True) # Exclude fields not provided in the request
        for key, value in update_data.items():
            setattr(db_item, key, value)
        db.add(db_item)
        db.commit()
        db.refresh(db_item)
    return db_item

def delete_item(db: Session, item_id: int) -> Optional[models.Item]:
    """
    Delete an item by its ID.
    """
    db_item = db.query(models.Item).filter(models.Item.id == item_id).first()
    if db_item:
        db.delete(db_item)
        db.commit()
    return db_item

microservice-scaffold/app/main.py

The main FastAPI application file, defining the API endpoints.


from fastapi import FastAPI, Depends, HTTPException, status
from sqlalchemy.orm import Session
from typing import List

from app import models, schemas, crud
from app.database import engine, SessionLocal, get_db, create_db_and_tables
from app.config import settings

# Initialize FastAPI app
app = FastAPI(
    title=settings.PROJECT_NAME,
    version=settings.PROJECT_VERSION,
    description="A microservice for managing items."
)

# Event handler to create database tables on startup
@app.on_event("startup")
def on_startup():
    """
    Event handler executed when the application starts.
    Creates all database tables if they don't exist.
    """
    create_db_and_tables()

@app.get("/", tags=["Root"])
async def root():
    """
    Root endpoint for basic health check or service info.
    """
    return {"message": f"Welcome to the {settings.PROJECT_NAME} Microservice!"}

@app.post("/items/", response_model=schemas.ItemInDB, status_code=status.HTTP_201_CREATED, tags=["Items"])
def create_item_endpoint(item: schemas.ItemCreate, db: Session = Depends(get_db)):
    """
    Create a new item.
    """
    return crud.create_item(db=db, item=item)

@app.get("/items/", response_model=List[schemas.ItemInDB], tags=["Items"])
def read_items_endpoint(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
    """
    Retrieve a list of items with pagination.
    """
    items = crud.get_items(db, skip=skip, limit=limit)
    return items

@app.get("/items/{item_id}", response_model=schemas.ItemInDB, tags=["Items"])
def read_item_endpoint(item_id: int, db: Session = Depends(get_db)):
    """
    Retrieve a single item by its ID.
    """
    db_item = crud.get_item(db, item_id=item_id)
    if db_item is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Item not found")
    return db_item

@app.put("/items/{item_id}", response_model=schemas.ItemInDB, tags=["Items"])
def update_item_endpoint(item_id: int, item: schemas.ItemUpdate, db: Session = Depends(get_db)):
    """
    Update an existing item by its ID.
    """
    db_item = crud.update_item(db, item_id=item_id, item=item)
    if db_item is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Item not found")
    return db_item

@app.delete("/items/{item_id}", status_code=status.HTTP_204_NO_CONTENT, tags=["Items"])
def delete_item_endpoint(item
gemini Output

This concludes the "Microservice Scaffolder" workflow. A comprehensive microservice project scaffold has been successfully generated, providing a robust foundation for your new service.


Microservice Scaffolding Output: Project Overview

A complete microservice project, named [service-name-placeholder], has been generated. This scaffold includes all essential components for development, testing, and deployment, designed for immediate usability and easy customization.

Key Features Generated:

  • Modern API Framework: FastAPI (Python) for high performance and developer experience.
  • Database Integration: PostgreSQL with SQLAlchemy ORM and Alembic for migrations.
  • Containerization: Docker setup for consistent development and production environments.
  • Automated Testing: Pytest framework with example unit and integration tests.
  • CI/CD Pipeline: GitHub Actions configuration for automated build, test, and deployment.
  • Deployment Automation: Basic Kubernetes manifests for cloud-native deployments.
  • Comprehensive Documentation: A detailed README.md to get you started.

1. Project Structure

The generated project adheres to a standard, maintainable structure. Below is an overview of the directory layout:


[service-name-placeholder]/
├── .github/                       # GitHub-specific configurations (e.g., CI/CD workflows)
│   └── workflows/
│       └── main.yml               # CI/CD pipeline for build, test, deploy
├── app/                           # Core application logic
│   ├── api/                       # API endpoints definitions
│   │   ├── v1/
│   │   │   ├── endpoints/         # Specific resource endpoints (e.g., items, users)
│   │   │   │   └── items.py
│   │   │   └── __init__.py
│   │   └── __init__.py
│   ├── core/                      # Core configurations, settings, and utilities
│   │   ├── config.py              # Application settings (loaded from env vars)
│   │   ├── database.py            # Database connection and session management
│   │   └── __init__.py
│   ├── crud/                      # Create, Read, Update, Delete operations
│   │   └── items.py               # Example CRUD for 'Item' model
│   ├── models/                    # Database models (SQLAlchemy ORM)
│   │   └── item.py                # Example 'Item' model
│   ├── schemas/                   # Pydantic schemas for request/response validation
│   │   └── item.py                # Example 'Item' schemas
│   ├── services/                  # Business logic and service layer
│   │   └── item_service.py        # Example service for 'Item' operations
│   └── main.py                    # FastAPI application entry point
├── alembic/                       # Database migration scripts (Alembic)
│   ├── versions/                  # Generated migration files
│   └── env.py                     # Alembic environment script
│   └── script.py.mako             # Alembic template for new migrations
├── tests/                         # Test suite
│   ├── unit/                      # Unit tests for individual components
│   │   └── test_item_service.py
│   ├── integration/               # Integration tests for API endpoints
│   │   └── test_items_api.py
│   └── conftest.py                # Pytest fixtures and configurations
├── k8s/                           # Kubernetes deployment manifests
│   ├── deployment.yaml            # Kubernetes Deployment for the microservice
│   ├── service.yaml               # Kubernetes Service for exposing the microservice
│   └── ingress.yaml               # (Optional) Ingress resource for external access
├── .env.example                   # Example environment variables for local development
├── .gitignore                     # Git ignore file
├── Dockerfile                     # Docker build instructions for the application
├── docker-compose.yml             # Docker Compose for local development environment
├── alembic.ini                    # Alembic configuration file
├── requirements.txt               # Python dependencies
└── README.md                      # Project documentation and getting started guide

2. Core Microservice Components

2.1. API Routes (FastAPI)

The microservice uses FastAPI, providing a high-performance, easy-to-use API framework with automatic OpenAPI (Swagger UI) and ReDoc documentation.

  • Entry Point: app/main.py initializes the FastAPI application.
  • API Versioning: Routes are organized under app/api/v1/endpoints/.
  • Example Endpoint: app/api/v1/endpoints/items.py provides CRUD operations for an Item resource.

Example API Endpoints:

  • POST /api/v1/items/

* Description: Create a new item.

* Request Body: ItemCreate (Pydantic schema).

* Response: Item (Pydantic schema) with the created item's details.

  • GET /api/v1/items/{item_id}

* Description: Retrieve an item by its ID.

* Response: Item (Pydantic schema) or 404 if not found.

  • GET /api/v1/items/

* Description: Retrieve a list of items.

* Query Parameters: skip (offset), limit (page size).

* Response: List of Item (Pydantic schema).

Pydantic Schemas:

Located in app/schemas/, these define the data structures for API requests and responses, ensuring robust data validation and serialization.

2.2. Database Models (SQLAlchemy & PostgreSQL)

The microservice is configured to use PostgreSQL as its database, managed by SQLAlchemy ORM and Alembic for migrations.

  • Database Connection: app/core/database.py handles the SQLAlchemy engine and session creation.
  • Example Model: app/models/item.py defines the Item SQLAlchemy model.

# app/models/item.py (simplified)
from sqlalchemy import Column, Integer, String, Boolean
from app.core.database import Base

class Item(Base):
    __tablename__ = "items"

    id = Column(Integer, primary_key=True, index=True)
    title = Column(String, index=True)
    description = Column(String, index=True)
    is_active = Column(Boolean, default=True)
  • Database Migrations (Alembic):

* alembic.ini configures Alembic.

* alembic/env.py connects Alembic to your database.

* To create a new migration: alembic revision --autogenerate -m "Add new column to items table"

* To apply migrations: alembic upgrade head

2.3. Business Logic & Services

The core business logic is encapsulated within the app/services/ directory, promoting separation of concerns.

  • Example Service: app/services/item_service.py contains methods for interacting with Item data, orchestrating CRUD operations, and applying business rules.
  • CRUD Operations: app/crud/ provides basic database interaction functions, keeping the service layer focused on business logic.

3. Infrastructure & Operations

3.1. Docker Setup

The project includes a Dockerfile for building a production-ready Docker image and docker-compose.yml for local development.

  • Dockerfile:

* Utilizes a multi-stage build for smaller image sizes and faster builds.

* Installs dependencies, copies application code, and sets up the entry point.

  • docker-compose.yml:

* Defines services for local development:

* web: The microservice application.

* db: A PostgreSQL database instance.

* Sets up networking and volume mounts for persistence.

* To run locally: docker-compose up --build

3.2. Testing Framework (Pytest)

A robust testing setup using pytest is included to ensure code quality and functionality.

  • Unit Tests: Located in tests/unit/, these test individual functions or components in isolation (e.g., test_item_service.py).
  • Integration Tests: Located in tests/integration/, these test the interaction between multiple components, often involving API endpoints and the database (e.g., test_items_api.py).
  • Fixtures: tests/conftest.py provides shared test fixtures, such as a test database session or an API client.
  • To run tests: docker-compose run --rm web pytest (within the Docker Compose environment) or pytest (if dependencies are installed locally).

3.3. CI/CD Pipeline (GitHub Actions)

A GitHub Actions workflow (.github/workflows/main.yml) is provided to automate the build, test, and deployment process.

  • Triggers: Runs on pushes to main branch and pull requests.
  • Stages:

1. Build & Lint: Lints code (e.g., Black, Flake8) and builds the Docker image.

2. Test: Runs unit and integration tests.

3. Deploy (Staging): Deploys the application to a staging environment (e.g., Kubernetes) upon successful tests on main branch.

4. Deploy (Production): Requires manual approval or specific tag pushes for production deployment.

  • Secrets Management: Environment variables for sensitive data (e.g., database credentials, cloud provider tokens) are expected to be configured as GitHub Secrets.

3.4. Deployment Scripts (Kubernetes)

Basic Kubernetes manifests are provided in the k8s/ directory for deploying the microservice to a Kubernetes cluster.

  • k8s/deployment.yaml: Defines the Kubernetes Deployment for your application, specifying the Docker image, replicas, resource limits, and environment variables.
  • k8s/service.yaml: Defines a Kubernetes Service to expose your application within the cluster.
  • k8s/ingress.yaml (Optional): An example Ingress resource for exposing the service externally via a domain name (requires an Ingress Controller).

To deploy to Kubernetes:

  1. Ensure kubectl is configured to connect to your cluster.
  2. Apply the manifests: kubectl apply -f k8s/
  3. Ensure necessary secrets (e.g., db-credentials) are created in your Kubernetes namespace.

4. Configuration Management

Application settings are managed through environment variables, with app/core/config.py handling their loading and validation using Pydantic's BaseSettings.

  • Local Development: Use the provided .env.example file (rename to .env) to configure local settings for docker-compose.
  • Production/CI/CD: Environment variables should be set directly in your deployment environment (e.g., Kubernetes secrets, CI/CD pipeline secrets).

5. Documentation & Usage

The README.md file at the root of the project serves as the primary documentation, providing detailed instructions on:

  • Project Setup: How to get the project running locally.
  • Running Tests: Commands to execute the test suite.
  • Database Migrations: How to create and apply database schema changes.
  • Deployment: Instructions for deploying to various environments.
  • API Documentation: Links to the automatically generated OpenAPI (Swagger UI) and ReDoc documentation (available when the service is running).

6. Next Steps & Customization

This scaffold provides a solid starting point. To evolve your microservice:

  1. Rename Placeholder: Replace [service-name-placeholder] with your actual service name in filenames, comments, and configuration.
  2. Define Your Models: Modify app/models/item.py and create new models in app/models/ to represent your specific business entities.
  3. Implement Business Logic:

* Create new Pydantic schemas in app/schemas/ for your request/response bodies.

* Develop new CRUD operations in app/crud/ for your models.

* Implement your core business logic in new or existing services within app/services/.

* Define new API endpoints in app/api/v1/endpoints/ to expose your functionality.

  1. Write Comprehensive Tests: Expand the test suite in tests/ to cover all new features and edge cases.
  2. Configure Deployment:

Adjust k8s/.yaml files to match your specific cluster setup, resource requirements, and environment variables.

* Integrate with your chosen cloud provider's secret management (e.g., AWS Secrets Manager, Azure Key Vault, Google Secret Manager).

  1. Review Security: Implement authentication, authorization, and other security best practices relevant to your application.
  2. Monitor & Log: Integrate with logging and monitoring solutions (e.g., Prometheus, Grafana, ELK Stack) for production observability.

This detailed scaffold empowers you to rapidly develop and deploy your microservice with confidence.

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