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:
2025-10-15 21:34:08 -04:00
commit 8dd4f0ca63
56 changed files with 3979 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
name: Backend CI
on:
push:
branches: [main, master, develop]
paths:
- 'backend/**'
- 'scripts/ci/backend-test.sh'
- '.gitea/workflows/backend-ci.yml'
pull_request:
branches: [main, master, develop]
paths:
- 'backend/**'
- 'scripts/ci/backend-test.sh'
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install uv
run: pip install uv
- name: Run backend tests
run: bash scripts/ci/backend-test.sh
- name: Upload coverage reports
uses: codecov/codecov-action@v3
with:
files: ./backend/coverage.xml
flags: backend

View File

@@ -0,0 +1,38 @@
name: Frontend CI
on:
push:
branches: [main, master, develop]
paths:
- 'frontend/**'
- 'scripts/ci/frontend-test.sh'
- '.gitea/workflows/frontend-ci.yml'
pull_request:
branches: [main, master, develop]
paths:
- 'frontend/**'
- 'scripts/ci/frontend-test.sh'
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: frontend/package-lock.json
- name: Run frontend tests
run: bash scripts/ci/frontend-test.sh
- name: Upload coverage reports
uses: codecov/codecov-action@v3
with:
files: ./frontend/coverage/coverage-final.json
flags: frontend

72
templates/.gitignore vendored Normal file
View File

@@ -0,0 +1,72 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
.pytest_cache/
.coverage
htmlcov/
.mypy_cache/
.ruff_cache/
# Virtual environments
venv/
env/
ENV/
.venv
# Node
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.npm
.eslintcache
# Frontend build
frontend/build/
frontend/dist/
frontend/.next/
frontend/out/
# Environment files
.env
.env.local
.env.*.local
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store
# Docker
*.log
# Testing
coverage/
.nyc_output/
# Misc
*.bak
*.tmp
.cache/

21
templates/LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) [year] [fullname]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

104
templates/README.md Normal file
View File

@@ -0,0 +1,104 @@
# Project Name
A modern monorepo project with FastAPI backend and React frontend.
## Project Structure
This project follows a modular monorepo layout based on best practices:
- **backend/** - FastAPI server (Python 3.11+)
- **frontend/** - React application (TypeScript)
- **deploy/** - Docker and deployment configurations
- **scripts/** - Shared scripts for CI and development
- **docs/** - Project documentation
## Prerequisites
- Python 3.11+
- Node.js 20 LTS
- Docker & Docker Compose
- uv (Python package manager)
## Quick Start
### Using Docker Compose (Recommended)
```bash
# Start all services
docker compose -f deploy/compose.yml up
# Backend will be available at http://localhost:8000
# Frontend will be available at http://localhost:3000
# API docs at http://localhost:8000/docs
```
### Local Development
#### Backend
```bash
cd backend
cp .env.example .env
uv sync
uv run uvicorn app.main:app --reload
```
#### Frontend
```bash
cd frontend
cp .env.example .env
npm install
npm start
```
## Development Scripts
Located in `scripts/` directory:
- **scripts/dev/** - Developer convenience scripts
- `start-backend.sh` - Start backend server
- `start-frontend.sh` - Start frontend dev server
- `start-database.sh` - Start database container
- `reset-database.sh` - Reset database
- **scripts/utils/** - Utility scripts
- `lint-backend.sh` - Lint backend code
- `lint-frontend.sh` - Lint frontend code
- `format-all.sh` - Format all code
## Testing
### Backend
```bash
cd backend
uv run pytest --cov=app --cov-report=term-missing
```
### Frontend
```bash
cd frontend
npm test
npm run test:coverage
```
## Code Quality
- **Backend**: ruff (format + lint), mypy (type checking), 100% test coverage required
- **Frontend**: ESLint, Prettier, Jest, 90%+ test coverage
## CI/CD
CI workflows are defined in `.gitea/workflows/` and use scripts from `scripts/ci/`.
## Documentation
- API documentation: `/docs/api/`
- Architecture diagrams: `/docs/architecture/`
- User guide: `/docs/user-guide/`
## License
[Specify your license here]

View File

@@ -0,0 +1,21 @@
# Application
APP_NAME=backend
APP_VERSION=0.1.0
DEBUG=true
LOG_LEVEL=INFO
# API
API_HOST=0.0.0.0
API_PORT=8000
API_PREFIX=/api/v1
# CORS
CORS_ORIGINS=http://localhost:3000,http://localhost:8080
# Database (if needed)
# DATABASE_URL=postgresql+asyncpg://user:password@localhost:5432/dbname
# Security
# SECRET_KEY=your-secret-key-here
# ALGORITHM=HS256
# ACCESS_TOKEN_EXPIRE_MINUTES=30

View 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()

View 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"},
)

View 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"}

View File

@@ -0,0 +1,82 @@
[project]
name = "backend"
version = "0.1.0"
description = "FastAPI backend service"
readme = "README.md"
requires-python = ">=3.11"
dependencies = [
"fastapi>=0.104.0",
"uvicorn[standard]>=0.24.0",
"pydantic>=2.5.0",
"pydantic-settings>=2.1.0",
"httpx>=0.25.0",
"python-multipart>=0.0.6",
]
[project.optional-dependencies]
dev = [
"pytest>=7.4.0",
"pytest-cov>=4.1.0",
"pytest-asyncio>=0.21.0",
"ruff>=0.1.0",
"mypy>=1.7.0",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.ruff]
line-length = 100
target-version = "py311"
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # pyupgrade
]
ignore = []
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
[tool.mypy]
python_version = "3.11"
strict = true
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = [
"--strict-markers",
"--cov=app",
"--cov-report=term-missing",
"--cov-report=html",
"--cov-fail-under=100",
]
asyncio_mode = "auto"
[tool.coverage.run]
source = ["app"]
omit = ["tests/*", "**/__init__.py"]
[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"raise AssertionError",
"raise NotImplementedError",
"if __name__ == .__main__.:",
"if TYPE_CHECKING:",
]

View File

@@ -0,0 +1,12 @@
"""Test configuration and fixtures."""
import pytest
from fastapi.testclient import TestClient
from app.main import app
@pytest.fixture
def client() -> TestClient:
"""Create test client."""
return TestClient(app)

View File

@@ -0,0 +1,22 @@
"""Integration tests for health endpoints."""
from fastapi.testclient import TestClient
def test_health_endpoint(client: TestClient) -> None:
"""Test health check endpoint."""
response = client.get("/health")
assert response.status_code == 200
assert response.json() == {"status": "healthy"}
def test_root_endpoint(client: TestClient) -> None:
"""Test root endpoint."""
response = client.get("/")
assert response.status_code == 200
data = response.json()
assert "message" in data
assert "version" in data
assert data["version"] == "0.1.0"

View File

@@ -0,0 +1,24 @@
"""Tests for core configuration."""
from app.core.config import Settings, get_settings
def test_settings_default_values() -> None:
"""Test that settings have correct default values."""
settings = Settings()
assert settings.app_name == "backend"
assert settings.app_version == "0.1.0"
assert settings.debug is False
assert settings.log_level == "INFO"
assert settings.api_host == "0.0.0.0"
assert settings.api_port == 8000
assert settings.api_prefix == "/api/v1"
def test_get_settings_returns_cached_instance() -> None:
"""Test that get_settings returns the same instance."""
settings1 = get_settings()
settings2 = get_settings()
assert settings1 is settings2

View File

@@ -0,0 +1,16 @@
# Docker Compose Environment Variables
# Backend
BACKEND_PORT=8000
DEBUG=true
LOG_LEVEL=INFO
# Frontend
FRONTEND_PORT=3000
REACT_APP_API_URL=http://localhost:8000
# Database
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DB=appdb
POSTGRES_PORT=5432

View File

@@ -0,0 +1,71 @@
# Deployment Configuration
This directory contains deployment artifacts for the project.
## Structure
- **compose.yml** - Docker Compose configuration for local development and deployment
- **.env.example** - Example environment variables
- **docker/** - Dockerfiles and container documentation
## Quick Start
### Local Development
1. Copy environment file:
```bash
cp .env.example .env
```
2. Start all services:
```bash
docker compose -f deploy/compose.yml up
```
3. Access services:
- Backend: http://localhost:8000
- Frontend: http://localhost:3000
- API Docs: http://localhost:8000/docs
- Database: localhost:5432
### Stop Services
```bash
docker compose -f deploy/compose.yml down
```
### Rebuild Services
```bash
docker compose -f deploy/compose.yml up --build
```
### View Logs
```bash
# All services
docker compose -f deploy/compose.yml logs -f
# Specific service
docker compose -f deploy/compose.yml logs -f backend
```
## Production Deployment
For production deployments, consider:
1. Using separate compose files for different environments
2. Implementing proper secret management
3. Setting up reverse proxy (nginx/traefik)
4. Configuring SSL/TLS certificates
5. Setting up monitoring and logging
6. Implementing backup strategies
## Kubernetes (Optional)
If deploying to Kubernetes, create a `k8s/` directory with:
- Deployment manifests
- Service definitions
- ConfigMaps and Secrets
- Ingress configuration

View File

@@ -0,0 +1,63 @@
version: '3.8'
services:
backend:
build:
context: ../backend
dockerfile: ../deploy/docker/backend.Dockerfile
container_name: backend
ports:
- "8000:8000"
environment:
- DEBUG=true
- LOG_LEVEL=INFO
- API_HOST=0.0.0.0
- API_PORT=8000
- CORS_ORIGINS=http://localhost:3000
volumes:
- ../backend:/app
command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
networks:
- app-network
depends_on:
- database
frontend:
build:
context: ../frontend
dockerfile: ../deploy/docker/frontend.Dockerfile
container_name: frontend
ports:
- "3000:3000"
environment:
- REACT_APP_API_URL=http://localhost:8000
- REACT_APP_API_PREFIX=/api/v1
volumes:
- ../frontend:/app
- /app/node_modules
command: npm start
networks:
- app-network
depends_on:
- backend
database:
image: postgres:16-alpine
container_name: database
ports:
- "5432:5432"
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=appdb
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- app-network
networks:
app-network:
driver: bridge
volumes:
postgres-data:

View File

@@ -0,0 +1,40 @@
# Docker Configuration
This directory contains Dockerfiles for building container images.
## Files
- **backend.Dockerfile** - Backend service (FastAPI)
- **frontend.Dockerfile** - Frontend service (React)
## Building Images
### Backend
```bash
docker build -f deploy/docker/backend.Dockerfile -t backend:latest ./backend
```
### Frontend
```bash
docker build -f deploy/docker/frontend.Dockerfile -t frontend:latest ./frontend
```
## Running with Docker Compose
From the project root:
```bash
docker compose -f deploy/compose.yml up
```
## Production Builds
For production, consider:
1. Multi-stage builds to reduce image size
2. Non-root user for security
3. Health checks
4. Proper secret management
5. Optimized layer caching

View File

@@ -0,0 +1,23 @@
# Backend Dockerfile
FROM python:3.11-slim
WORKDIR /app
# Install uv
RUN pip install --no-cache-dir uv
# Copy dependency files
COPY pyproject.toml ./
# Install dependencies
RUN uv pip install --system -e .
RUN uv pip install --system -e ".[dev]"
# Copy application code
COPY . .
# Expose port
EXPOSE 8000
# Run the application
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

View File

@@ -0,0 +1,19 @@
# Frontend Dockerfile
FROM node:20-alpine
WORKDIR /app
# Copy dependency files
COPY package*.json ./
# Install dependencies
RUN npm ci
# Copy application code
COPY . .
# Expose port
EXPOSE 3000
# Run the application
CMD ["npm", "start"]

View File

@@ -0,0 +1,35 @@
# API Changelog
All notable changes to the API will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
- Initial API setup with FastAPI
- Health check endpoint
- Root endpoint
### Changed
- N/A
### Deprecated
- N/A
### Removed
- N/A
### Fixed
- N/A
### Security
- N/A
## [0.1.0] - YYYY-MM-DD
### Added
- Initial release
- Basic project structure
- FastAPI application setup

View File

@@ -0,0 +1,79 @@
# API Documentation
## Overview
The API is built with FastAPI and follows REST principles.
## Base URL
- **Development**: `http://localhost:8000`
- **API Prefix**: `/api/v1`
## Interactive Documentation
FastAPI provides automatic interactive API documentation:
- **Swagger UI**: http://localhost:8000/docs
- **ReDoc**: http://localhost:8000/redoc
## Authentication
(Add authentication details here when implemented)
## Endpoints
### Health Check
```
GET /health
```
Returns the health status of the API.
**Response:**
```json
{
"status": "healthy"
}
```
### Root
```
GET /
```
Returns basic API information.
**Response:**
```json
{
"message": "Welcome to the API",
"version": "0.1.0"
}
```
## Error Responses
All error responses follow this format:
```json
{
"detail": "Error message here"
}
```
### Common Status Codes
- **200 OK** - Request succeeded
- **201 Created** - Resource created successfully
- **400 Bad Request** - Invalid request data
- **401 Unauthorized** - Authentication required
- **403 Forbidden** - Insufficient permissions
- **404 Not Found** - Resource not found
- **422 Unprocessable Entity** - Validation error
- **500 Internal Server Error** - Server error
## Changelog
See [CHANGELOG.md](./CHANGELOG.md) for API changes and migration notes.

View File

@@ -0,0 +1,131 @@
# Architecture Documentation
## Overview
This project follows a monorepo architecture with separate backend and frontend applications.
## System Architecture
```
┌─────────────┐
│ Client │
│ (Browser) │
└──────┬──────┘
│ HTTP/HTTPS
┌──────▼──────┐
│ Frontend │
│ (React) │
└──────┬──────┘
│ REST API
┌──────▼──────┐
│ Backend │
│ (FastAPI) │
└──────┬──────┘
│ SQL
┌──────▼──────┐
│ Database │
│ (PostgreSQL)│
└─────────────┘
```
## Backend Architecture
### Layers
1. **API Layer** (`app/api/`)
- HTTP endpoints
- Request/response handling
- Route definitions
2. **Service Layer** (`app/services/`)
- Business logic
- Data processing
- External integrations
3. **Data Layer** (`app/db/`)
- Database models
- Database connections
- Query operations
4. **Core Layer** (`app/core/`)
- Configuration
- Security
- Error handling
### Request Flow
```
Request → API Endpoint → Service → Database → Service → API Response
```
## Frontend Architecture
### Structure
- **Components** - Reusable UI components
- **Pages** - Route-level components
- **Services** - API communication
- **Store** - State management
- **Utils** - Helper functions
### Data Flow
```
User Action → Component → Service → API → Backend
State Update
UI Re-render
```
## Deployment Architecture
### Development
All services run in Docker containers orchestrated by Docker Compose:
- Backend container (FastAPI)
- Frontend container (React dev server)
- Database container (PostgreSQL)
### Production
(Add production deployment architecture here)
## Security Considerations
- CORS configuration
- Environment variable management
- API authentication/authorization
- Input validation
- SQL injection prevention
## Scalability
- Horizontal scaling via container orchestration
- Database connection pooling
- Caching strategies
- Load balancing
## Technology Stack
### Backend
- Python 3.11+
- FastAPI
- Pydantic v2
- PostgreSQL
### Frontend
- React 18
- TypeScript
- Axios
### DevOps
- Docker & Docker Compose
- Gitea Actions (CI/CD)

View File

@@ -0,0 +1,186 @@
# User Guide
## Getting Started
This guide will help you get started with the application.
## Installation
### Prerequisites
Before you begin, ensure you have the following installed:
- Docker and Docker Compose
- Python 3.11+ (for local backend development)
- Node.js 20 LTS (for local frontend development)
- uv (Python package manager)
### Quick Start with Docker
1. Clone the repository:
```bash
git clone <repository-url>
cd <project-name>
```
2. Start all services:
```bash
docker compose -f deploy/compose.yml up
```
3. Access the application:
- Frontend: http://localhost:3000
- Backend API: http://localhost:8000
- API Documentation: http://localhost:8000/docs
## Local Development
### Backend Development
1. Navigate to backend directory:
```bash
cd backend
```
2. Copy environment file:
```bash
cp .env.example .env
```
3. Install dependencies:
```bash
uv sync
```
4. Start the development server:
```bash
uv run uvicorn app.main:app --reload
```
Or use the convenience script:
```bash
bash scripts/dev/start-backend.sh
```
### Frontend Development
1. Navigate to frontend directory:
```bash
cd frontend
```
2. Copy environment file:
```bash
cp .env.example .env
```
3. Install dependencies:
```bash
npm install
```
4. Start the development server:
```bash
npm start
```
Or use the convenience script:
```bash
bash scripts/dev/start-frontend.sh
```
## Testing
### Backend Tests
```bash
cd backend
uv run pytest --cov=app
```
### Frontend Tests
```bash
cd frontend
npm test
```
## Code Quality
### Linting
```bash
# Backend
bash scripts/utils/lint-backend.sh
# Frontend
bash scripts/utils/lint-frontend.sh
```
### Formatting
```bash
bash scripts/utils/format-all.sh
```
## Common Tasks
### Adding a New API Endpoint
1. Create endpoint in `backend/app/api/`
2. Add business logic in `backend/app/services/`
3. Define schemas in `backend/app/schemas/`
4. Write tests in `backend/tests/`
### Adding a New Frontend Component
1. Create component in `frontend/src/components/`
2. Add styles in `frontend/src/styles/`
3. Write tests in `frontend/tests/components/`
### Database Migrations
(Add database migration instructions when implemented)
## Troubleshooting
### Port Already in Use
If you get a "port already in use" error:
```bash
# Find process using the port
lsof -i :8000 # or :3000 for frontend
# Kill the process
kill -9 <PID>
```
### Docker Issues
```bash
# Clean up Docker resources
docker compose -f deploy/compose.yml down
docker system prune -a
```
### Dependency Issues
```bash
# Backend
cd backend
rm -rf .venv
uv sync
# Frontend
cd frontend
rm -rf node_modules package-lock.json
npm install
```
## Support
For issues and questions:
- Check the documentation in `/docs`
- Review the API documentation at http://localhost:8000/docs
- Open an issue in the repository

View File

@@ -0,0 +1,7 @@
# API Configuration
REACT_APP_API_URL=http://localhost:8000
REACT_APP_API_PREFIX=/api/v1
# Application
REACT_APP_NAME=Frontend
REACT_APP_VERSION=0.1.0

View File

@@ -0,0 +1,34 @@
{
"env": {
"browser": true,
"es2021": true,
"jest": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": ["react", "@typescript-eslint"],
"rules": {
"react/react-in-jsx-scope": "off",
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-module-boundary-types": "off"
},
"settings": {
"react": {
"version": "detect"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"semi": true,
"trailingComma": "es5",
"singleQuote": true,
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"arrowParens": "always",
"endOfLine": "lf"
}

View File

@@ -0,0 +1,73 @@
{
"name": "frontend",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.20.0",
"axios": "^1.6.0"
},
"devDependencies": {
"@testing-library/jest-dom": "^6.1.5",
"@testing-library/react": "^14.1.2",
"@testing-library/user-event": "^14.5.1",
"@types/jest": "^29.5.10",
"@types/node": "^20.10.0",
"@types/react": "^18.2.42",
"@types/react-dom": "^18.2.17",
"@typescript-eslint/eslint-plugin": "^6.13.0",
"@typescript-eslint/parser": "^6.13.0",
"eslint": "^8.54.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"prettier": "^3.1.0",
"react-scripts": "5.0.1",
"typescript": "^5.3.2"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"test:coverage": "react-scripts test --coverage --watchAll=false",
"eject": "react-scripts eject",
"lint": "eslint src --ext .ts,.tsx",
"lint:fix": "eslint src --ext .ts,.tsx --fix",
"format": "prettier --write \"src/**/*.{ts,tsx,json,css,md}\""
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"jest": {
"collectCoverageFrom": [
"src/**/*.{ts,tsx}",
"!src/**/*.d.ts",
"!src/index.tsx",
"!src/reportWebVitals.ts"
],
"coverageThreshold": {
"global": {
"branches": 90,
"functions": 90,
"lines": 90,
"statements": 90
}
}
}
}

View File

@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="Modern monorepo application" />
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>

View File

@@ -0,0 +1,15 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders welcome message', () => {
render(<App />);
const headingElement = screen.getByText(/Welcome to Your Monorepo Project/i);
expect(headingElement).toBeInTheDocument();
});
test('renders edit instruction', () => {
render(<App />);
const instructionElement = screen.getByText(/Edit src\/App.tsx and save to reload/i);
expect(instructionElement).toBeInTheDocument();
});

View File

@@ -0,0 +1,15 @@
import React from 'react';
import './styles/App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<h1>Welcome to Your Monorepo Project</h1>
<p>Edit src/App.tsx and save to reload.</p>
</header>
</div>
);
}
export default App;

View File

@@ -0,0 +1,11 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './styles/index.css';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);

View File

@@ -0,0 +1,41 @@
import axios, { AxiosInstance } from 'axios';
const API_URL = process.env.REACT_APP_API_URL || 'http://localhost:8000';
const API_PREFIX = process.env.REACT_APP_API_PREFIX || '/api/v1';
const apiClient: AxiosInstance = axios.create({
baseURL: `${API_URL}${API_PREFIX}`,
headers: {
'Content-Type': 'application/json',
},
});
// Request interceptor
apiClient.interceptors.request.use(
(config) => {
// Add auth token if available
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
// Response interceptor
apiClient.interceptors.response.use(
(response) => response,
(error) => {
// Handle errors globally
if (error.response?.status === 401) {
// Handle unauthorized
localStorage.removeItem('token');
}
return Promise.reject(error);
}
);
export default apiClient;

View File

@@ -0,0 +1,5 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';

View File

@@ -0,0 +1,23 @@
.App {
text-align: center;
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-header h1 {
margin-bottom: 1rem;
}
.App-header p {
font-size: 1rem;
color: #61dafb;
}

View File

@@ -0,0 +1,11 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',
'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
}

View File

@@ -0,0 +1,32 @@
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"jsx": "react-jsx",
"module": "ESNext",
"moduleResolution": "node",
"resolveJsonModule": true,
"allowJs": true,
"checkJs": false,
"outDir": "./build",
"rootDir": "./src",
"removeComments": true,
"noEmit": true,
"isolatedModules": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
"allowSyntheticDefaultImports": true,
"baseUrl": "src",
"paths": {
"@/*": ["./*"]
}
},
"include": ["src"],
"exclude": ["node_modules", "build", "dist"]
}

View File

@@ -0,0 +1,22 @@
#!/bin/bash
# Backend CI test script
set -e
cd "$(dirname "$0")/../../backend"
echo "Installing dependencies..."
uv sync
uv pip install --system -e ".[dev]"
echo "Running linter..."
uv run ruff check app tests
echo "Running type checker..."
uv run mypy app
echo "Running tests with coverage..."
uv run pytest --cov=app --cov-report=term-missing --cov-report=xml --cov-fail-under=100
echo "Backend tests passed!"

View File

@@ -0,0 +1,18 @@
#!/bin/bash
# Frontend CI test script
set -e
cd "$(dirname "$0")/../../frontend"
echo "Installing dependencies..."
npm ci
echo "Running linter..."
npm run lint
echo "Running tests with coverage..."
npm run test:coverage
echo "Frontend tests passed!"

View File

@@ -0,0 +1,26 @@
#!/bin/bash
# Reset database (WARNING: This will delete all data)
set -e
cd "$(dirname "$0")/../../deploy"
echo "WARNING: This will delete all database data!"
read -p "Are you sure you want to continue? (yes/no): " confirm
if [ "$confirm" != "yes" ]; then
echo "Aborted."
exit 0
fi
echo "Stopping database container..."
docker compose down database
echo "Removing database volume..."
docker volume rm $(basename $(pwd))_postgres-data 2>/dev/null || true
echo "Starting fresh database..."
docker compose up -d database
echo "Database reset complete"

View File

@@ -0,0 +1,31 @@
#!/bin/bash
# Start backend development server
set -e
cd "$(dirname "$0")/../../backend"
echo "Starting backend server..."
if [ ! -f ".env" ]; then
echo "Creating .env from .env.example..."
cp .env.example .env
fi
# Check if uv is installed
if ! command -v uv &> /dev/null; then
echo "Error: uv is not installed. Please install it first."
echo "Visit: https://github.com/astral-sh/uv"
exit 1
fi
# Install dependencies if needed
if [ ! -d ".venv" ]; then
echo "Installing dependencies..."
uv sync
fi
# Start the server
echo "Starting uvicorn..."
uv run uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

View File

@@ -0,0 +1,14 @@
#!/bin/bash
# Start database container
set -e
cd "$(dirname "$0")/../../deploy"
echo "Starting database container..."
docker compose up -d database
echo "Database started successfully"
echo "Connection string: postgresql://postgres:postgres@localhost:5432/appdb"

View File

@@ -0,0 +1,24 @@
#!/bin/bash
# Start frontend development server
set -e
cd "$(dirname "$0")/../../frontend"
echo "Starting frontend server..."
if [ ! -f ".env" ]; then
echo "Creating .env from .env.example..."
cp .env.example .env
fi
# Install dependencies if needed
if [ ! -d "node_modules" ]; then
echo "Installing dependencies..."
npm install
fi
# Start the server
echo "Starting React development server..."
npm start

View File

@@ -0,0 +1,17 @@
#!/bin/bash
# Format all code
set -e
PROJECT_ROOT="$(dirname "$0")/../.."
echo "Formatting backend code..."
cd "$PROJECT_ROOT/backend"
uv run ruff format app tests
echo "Formatting frontend code..."
cd "$PROJECT_ROOT/frontend"
npm run format
echo "All code formatted!"

View File

@@ -0,0 +1,15 @@
#!/bin/bash
# Lint backend code
set -e
cd "$(dirname "$0")/../../backend"
echo "Running ruff linter..."
uv run ruff check app tests
echo "Running mypy type checker..."
uv run mypy app
echo "Backend linting complete!"

View File

@@ -0,0 +1,12 @@
#!/bin/bash
# Lint frontend code
set -e
cd "$(dirname "$0")/../../frontend"
echo "Running ESLint..."
npm run lint
echo "Frontend linting complete!"