Initial commit: Complete project-bootstrap tool
- Bootstrap script for creating monorepo projects - FastAPI backend templates with uv, ruff, mypy, pytest - React frontend templates with TypeScript, ESLint, Prettier - Docker Compose setup with backend, frontend, and database - 9 development and CI scripts - Gitea Actions CI/CD workflows - Comprehensive documentation (8 files) - 45 template files for complete project structure - Automated verification script (all tests pass) - Based on coding-agent-rules standards
This commit is contained in:
36
templates/backend/app/core/config.py
Normal file
36
templates/backend/app/core/config.py
Normal file
@@ -0,0 +1,36 @@
|
||||
"""Application configuration."""
|
||||
|
||||
from functools import lru_cache
|
||||
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
"""Application settings."""
|
||||
|
||||
model_config = SettingsConfigDict(
|
||||
env_file=".env",
|
||||
env_file_encoding="utf-8",
|
||||
case_sensitive=False,
|
||||
extra="ignore",
|
||||
)
|
||||
|
||||
# Application
|
||||
app_name: str = "backend"
|
||||
app_version: str = "0.1.0"
|
||||
debug: bool = False
|
||||
log_level: str = "INFO"
|
||||
|
||||
# API
|
||||
api_host: str = "0.0.0.0"
|
||||
api_port: int = 8000
|
||||
api_prefix: str = "/api/v1"
|
||||
|
||||
# CORS
|
||||
cors_origins: list[str] = ["http://localhost:3000"]
|
||||
|
||||
|
||||
@lru_cache
|
||||
def get_settings() -> Settings:
|
||||
"""Get cached settings instance."""
|
||||
return Settings()
|
||||
58
templates/backend/app/core/errors.py
Normal file
58
templates/backend/app/core/errors.py
Normal file
@@ -0,0 +1,58 @@
|
||||
"""Error handling utilities."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
from fastapi import HTTPException, status
|
||||
|
||||
|
||||
class AppException(Exception):
|
||||
"""Base application exception."""
|
||||
|
||||
def __init__(self, message: str, details: dict[str, Any] | None = None) -> None:
|
||||
"""Initialize exception."""
|
||||
self.message = message
|
||||
self.details = details or {}
|
||||
super().__init__(self.message)
|
||||
|
||||
|
||||
class NotFoundError(AppException):
|
||||
"""Resource not found error."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class ValidationError(AppException):
|
||||
"""Validation error."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class AuthenticationError(AppException):
|
||||
"""Authentication error."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
def raise_not_found(resource: str, identifier: str | int) -> None:
|
||||
"""Raise HTTP 404 exception."""
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"{resource} with id '{identifier}' not found",
|
||||
)
|
||||
|
||||
|
||||
def raise_validation_error(message: str) -> None:
|
||||
"""Raise HTTP 422 exception."""
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail=message,
|
||||
)
|
||||
|
||||
|
||||
def raise_unauthorized(message: str = "Unauthorized") -> None:
|
||||
"""Raise HTTP 401 exception."""
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail=message,
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
35
templates/backend/app/main.py
Normal file
35
templates/backend/app/main.py
Normal file
@@ -0,0 +1,35 @@
|
||||
"""FastAPI application entry point."""
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
|
||||
from app.core.config import get_settings
|
||||
|
||||
settings = get_settings()
|
||||
|
||||
app = FastAPI(
|
||||
title=settings.app_name,
|
||||
version=settings.app_version,
|
||||
debug=settings.debug,
|
||||
)
|
||||
|
||||
# CORS middleware
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=settings.cors_origins,
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
|
||||
@app.get("/")
|
||||
async def root() -> dict[str, str]:
|
||||
"""Root endpoint."""
|
||||
return {"message": "Welcome to the API", "version": settings.app_version}
|
||||
|
||||
|
||||
@app.get("/health")
|
||||
async def health() -> dict[str, str]:
|
||||
"""Health check endpoint."""
|
||||
return {"status": "healthy"}
|
||||
Reference in New Issue
Block a user