Imported from yoosungung/timefact (
AGENTS.md). Install upstream withnpx skills add yoosungung/timefact. Copyright stays with the author.
AGENTS.md
This file contains guidelines and commands for agentic coding assistants working on the TimeFact codebase.
Project Overview
TimeFact is a full-stack R&D task tracking and time logging system built with:
- Backend: FastAPI + SQLAlchemy 2.0 + Alembic (Python 3.11+)
- Frontend: React 19 + Vite + TanStack Query + Tailwind CSS
- Deployment: GitLab CI/CD with Kubernetes on NCP
Essential Commands
Backend Development
# Setup
cd backend
uv sync --frozen # Install dependencies
source .venv/bin/activate # Activate virtual env
# Development
uvicorn app.main:app --reload # Start dev server (localhost:8000)
alembic upgrade head # Apply database migrations
alembic revision --autogenerate -m "description" # Create new migration
python initial_data.py # Seed initial data
# Testing
pytest # Run all tests
pytest tests/test_specific.py # Run single test file
pytest -k "test_name" # Run specific test
pytest -v -s # Verbose with print output
Frontend Development
# Setup
cd frontend
npm install # Install dependencies
# Development
npm run dev # Start dev server (localhost:5173)
npm run build # Production build
npm run preview # Preview production build
# Linting
npm run lint # Run ESLint
Database Operations
# Migration workflow
alembic revision --autogenerate -m "Add user table"
alembic upgrade head
alembic downgrade -1 # Rollback one migration
alembic current # Show current revision
alembic history # Show migration history
Code Style Guidelines
Python Backend
General Style
- Use uv package manager for dependency management
- Follow async/await patterns throughout (SQLAlchemy 2.0 style)
- Use type hints with modern Python syntax (
from typing import List, Optional) - Import organization: standard library → third-party → local imports
- Maximum line length: 88 characters (Ruff default)
Naming Conventions
- Variables/Functions:
snake_case - Classes:
PascalCase - Constants:
UPPER_SNAKE_CASE - Private members: Prefix with underscore
_private_method
Database Models
# Use modern SQLAlchemy 2.0 syntax
from sqlalchemy import String, Integer
from sqlalchemy.orm import Mapped, mapped_column
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
email: Mapped[str] = mapped_column(String(255), unique=True, index=True)
is_active: Mapped[bool] = mapped_column(default=True)
API Endpoints
# Use dependency injection for DB and auth
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
@router.post("/users/", response_model=UserResponse)
async def create_user(
user: UserCreate,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user)
) -> UserResponse:
# Implementation
Error Handling
- Use
HTTPExceptionwith proper status codes - Provide meaningful error messages
- Log errors appropriately
- Validate input with Pydantic models
CRUD Operations
- Separate CRUD logic from API endpoints
- Use async patterns consistently
- Return appropriate response models
React Frontend
Component Structure
- Use function components exclusively (no class components)
- Follow hooks pattern (useState, useEffect, useContext)
- Component files:
PascalCase.jsx - Component props: TypeScript-like PropTypes or just document in comments
// Good component structure
import { useState, useEffect } from 'react';
import { useQuery } from '@tanstack/react-query';
const TaskList = () => {
const [selectedTask, setSelectedTask] = useState(null);
const { data: tasks, isLoading, error } = useQuery({
queryKey: ['tasks'],
queryFn: fetchTasks
});
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error loading tasks</div>;
return (
<div className="space-y-4">
{/* Component JSX */}
</div>
);
};
export default TaskList;
State Management
- Server state: TanStack Query for API calls and caching
- Client state: React Context for global state (AuthContext)
- Local state: useState for component-specific state
Styling
- Tailwind CSS for all styling
- Use clsx for conditional classes
- Follow responsive design patterns
- Component composition over CSS overrides
import clsx from 'clsx';
const Button = ({ variant = 'primary', children, className, ...props }) => {
return (
<button
className={clsx(
'px-4 py-2 rounded-md font-medium transition-colors',
{
'bg-blue-600 text-white hover:bg-blue-700': variant === 'primary',
'bg-gray-200 text-gray-900 hover:bg-gray-300': variant === 'secondary',
},
className
)}
{...props}
>
{children}
</button>
);
};
API Integration
- Use Axios with interceptors for JWT handling
- Implement automatic token refresh
- Handle errors with user feedback
- Use TanStack Query for caching and synchronization
// API client setup in lib/api.js
import axios from 'axios';
const api = axios.create({
baseURL: import.meta.env.VITE_API_URL,
});
// Request interceptor to add auth token
api.interceptors.request.use((config) => {
const token = localStorage.getItem('access_token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
Forms
- Use React Hook Form for form handling
- Implement proper validation
- Handle loading and error states
File Organization
Backend Structure
backend/
├── app/
│ ├── api/v1/ # API endpoints by version
│ ├── core/ # Config, security, utilities
│ ├── crud/ # Database operations
│ ├── models/ # SQLAlchemy models
│ ├── schemas/ # Pydantic models
│ ├── db/ # Database session setup
│ └── main.py # FastAPI app entry
├── alembic/ # Database migrations
├── tests/ # Test files
└── initial_data.py # Seed data script
Frontend Structure
frontend/
├── src/
│ ├── components/ # Reusable components
│ ├── pages/ # Page components
│ ├── context/ # React Context providers
│ ├── lib/ # Utilities, API client
│ ├── App.jsx # Main app with routing
│ └── main.jsx # React entry point
├── public/ # Static assets
└── dist/ # Build output
Testing
Backend Testing
- Use pytest framework
- Test files:
test_*.pyintests/directory - Test async functions with
pytest-asyncio - Mock external dependencies
- Test database operations with test database
# Example test structure
import pytest
from httpx import AsyncClient
from sqlalchemy.ext.asyncio import AsyncSession
@pytest.mark.asyncio
async def test_create_user(async_client: AsyncClient, db_session: AsyncSession):
user_data = {"email": "test@example.com", "password": "password123"}
response = await async_client.post("/api/v1/users/", json=user_data)
assert response.status_code == 201
assert response.json()["email"] == user_data["email"]
Frontend Testing
- Currently no testing framework set up
- Consider adding Vitest or Jest for unit testing
- Use React Testing Library for component testing
Development Workflow
-
Feature Development:
- Create feature branch from main/master
- Backend: Create model → CRUD → API endpoint → tests
- Frontend: Create component → integrate with API → add to routing
-
Database Changes:
- Create migration:
alembic revision --autogenerate -m "description" - Apply locally:
alembic upgrade head - Test with sample data if needed
- Create migration:
-
Code Quality:
- Backend: Run
pytestandruff check - Frontend: Run
npm run lint - Ensure all tests pass before committing
- Backend: Run
-
Deployment:
- GitLab CI/CD handles deployment automatically
- Changes pushed to main/master trigger deployment
- SSL certificates managed by cert-manager
Security Considerations
- JWT tokens for authentication
- Password hashing with bcrypt
- CORS properly configured
- Environment variables for sensitive data
- SQL injection prevention through ORM
- Input validation with Pydantic
Performance Guidelines
- Backend: Use async/await for I/O operations
- Database queries: Use indexes, N+1 query prevention
- Frontend: Implement proper caching with TanStack Query
- Bundle optimization with Vite
- Image optimization and lazy loading
Common Issues & Solutions
- Database Connection: Ensure async driver is used (asyncpg for PostgreSQL)
- CORS Issues: Check
BACKEND_CORS_ORIGINSconfiguration - JWT Expiration: Implement automatic token refresh in frontend
- Migration Conflicts: Resolve manually by editing migration files
- Build Errors: Clear node_modules and reinstall dependencies