Main branch Resync on w/ gitea. v0.1.6 #1

Merged
serversdown merged 20 commits from claude/nested-todo-app-mvp-014vUjLpD8wNjkMhLMXS6Kd5 into main 2026-01-04 04:30:52 -05:00
10 changed files with 100 additions and 22 deletions
Showing only changes of commit 8d5ad6a809 - Show all commits

14
backend/.env.example Normal file
View File

@@ -0,0 +1,14 @@
# Database Configuration
DATABASE_URL=sqlite:///./tesseract.db
# API Configuration
API_TITLE=Tesseract - Nested Todo Tree API
API_DESCRIPTION=API for managing deeply nested todo trees
API_VERSION=1.0.0
# CORS Configuration (comma-separated list of allowed origins)
CORS_ORIGINS=http://localhost:5173,http://localhost:3000
# Server Configuration
HOST=0.0.0.0
PORT=8000

View File

@@ -1,8 +1,9 @@
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from .settings import settings
SQLALCHEMY_DATABASE_URL = "sqlite:///./tesseract.db"
SQLALCHEMY_DATABASE_URL = settings.database_url
engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}

View File

@@ -6,20 +6,21 @@ import json
from . import models, schemas, crud
from .database import engine, get_db
from .settings import settings
# Create database tables
models.Base.metadata.create_all(bind=engine)
app = FastAPI(
title="Tesseract - Nested Todo Tree API",
description="API for managing deeply nested todo trees",
version="1.0.0"
title=settings.api_title,
description=settings.api_description,
version=settings.api_version
)
# CORS middleware for frontend
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:5173", "http://localhost:3000"], # Vite default port
allow_origins=settings.cors_origins_list,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],

37
backend/app/settings.py Normal file
View File

@@ -0,0 +1,37 @@
from pydantic_settings import BaseSettings, SettingsConfigDict
from typing import List
class Settings(BaseSettings):
"""Application settings loaded from environment variables"""
# Database Configuration
database_url: str = "sqlite:///./tesseract.db"
# API Configuration
api_title: str = "Tesseract - Nested Todo Tree API"
api_description: str = "API for managing deeply nested todo trees"
api_version: str = "1.0.0"
# CORS Configuration
cors_origins: str = "http://localhost:5173,http://localhost:3000"
# Server Configuration
host: str = "0.0.0.0"
port: int = 8000
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
case_sensitive=False,
extra="ignore"
)
@property
def cors_origins_list(self) -> List[str]:
"""Parse comma-separated CORS origins into a list"""
return [origin.strip() for origin in self.cors_origins.split(",")]
# Global settings instance
settings = Settings()

View File

@@ -1,5 +1,3 @@
version: '3.8'
services:
backend:
build:
@@ -7,10 +5,12 @@ services:
dockerfile: Dockerfile
container_name: tesseract-backend
ports:
- "8000:8000"
- "8002:8002"
volumes:
- ./backend/app:/app/app
- tesseract-db:/app
env_file:
- ./backend/.env
environment:
- PYTHONUNBUFFERED=1
restart: unless-stopped
@@ -21,7 +21,9 @@ services:
dockerfile: Dockerfile
container_name: tesseract-frontend
ports:
- "3000:80"
- "3002:80"
env_file:
- ./frontend/.env
depends_on:
- backend
restart: unless-stopped

18
frontend/.env.example Normal file
View File

@@ -0,0 +1,18 @@
# API Configuration
# Base URL for API requests (relative path used in production)
VITE_API_BASE_URL=/api
# Backend API URL (used for development proxy)
VITE_API_URL=http://localhost:8000
# Development Configuration
# Port for Vite development server
VITE_DEV_PORT=5173
# Application Configuration
# Application version displayed in UI
VITE_APP_VERSION=0.1.5
# UI/UX Configuration
# Search input debounce delay in milliseconds
VITE_SEARCH_DEBOUNCE_MS=300

View File

@@ -13,7 +13,7 @@ function App() {
<h1 className="text-2xl font-bold text-cyber-orange">
TESSERACT
<span className="ml-3 text-sm text-gray-500">Task Decomposition Engine</span>
<span className="ml-2 text-xs text-gray-600">v0.1.5</span>
<span className="ml-2 text-xs text-gray-600">v{import.meta.env.VITE_APP_VERSION || '0.1.5'}</span>
</h1>
</div>
<SearchBar />

View File

@@ -84,9 +84,10 @@ function SearchBar() {
return
}
const debounceMs = parseInt(import.meta.env.VITE_SEARCH_DEBOUNCE_MS || '300')
const timeoutId = setTimeout(() => {
handleSearch(query)
}, 300)
}, debounceMs)
return () => clearTimeout(timeoutId)
}, [query, selectedProjects])

View File

@@ -1,4 +1,4 @@
const API_BASE = '/api';
const API_BASE = import.meta.env.VITE_API_BASE_URL || '/api';
async function fetchAPI(endpoint, options = {}) {
const response = await fetch(`${API_BASE}${endpoint}`, {

View File

@@ -1,15 +1,19 @@
import { defineConfig } from 'vite'
import { defineConfig, loadEnv } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
server: {
host: '0.0.0.0',
port: 5173,
proxy: {
'/api': {
target: 'http://localhost:8000',
changeOrigin: true,
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), '')
return {
plugins: [react()],
server: {
host: '0.0.0.0',
port: parseInt(env.VITE_DEV_PORT || '5173'),
proxy: {
'/api': {
target: env.VITE_API_URL || 'http://localhost:8000',
changeOrigin: true,
}
}
}
}