# ZynkTime A time reporting application for the Kleer API with both FastAPI web interface and CLI. ## Features - ๐ŸŽจ **Modern Web UI**: Responsive glassy interface with drag/drop upload and live status - ๐Ÿ“‘ **CSV + XLSX**: Parse CSV or XLSX (reads `AGRESSO` sheet) for time extraction - โœ… **Approvals**: View and approve events over a date range from the UI or API - ๐ŸŒ **REST API**: FastAPI endpoints for projects, reporting, events, and approvals - ๐Ÿ’ป **CLI**: Interactive command-line mode for CSV/XLSX files - ๐Ÿงช **Tested**: Unit tests with pytest and mocked API calls ## Quick Start ### ๐Ÿณ Docker (Recommended) The easiest way to run ZynkTime is with Docker: ```bash # 1. Clone the repository cd zynktime # 2. Copy environment file cp .env.example .env # 3. Edit .env and add your API key nano .env # or use your favorite editor # 4. Start with Docker Compose docker-compose up -d # 5. Open your browser # Navigate to: http://localhost:8000 ``` **Docker Commands:** ```bash # Start the application docker-compose up -d # View logs docker-compose logs -f # Stop the application docker-compose down # Rebuild after code changes docker-compose up -d --build # Access container shell docker-compose exec zynktime bash ``` ### ๐Ÿ Manual Installation If you prefer to run without Docker: ```bash # Clone the repository cd zynktime # Create virtual environment python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate # Install dependencies pip install -r requirements.txt ``` ### Configuration **Option 1: Environment File (Recommended)** ```bash # Copy example file cp .env.example .env # Edit with your values nano .env ``` **Option 2: Export Variables** ```bash export KLEER_API_KEY="your_api_key_here" export KLEER_USERNAME="Your Name" # Optional, defaults to "Christopher Juhlin" export KLEER_COMPANY_ID="1336" # Optional, defaults to "1336" ``` ### Running the Application **Web UI Mode (Recommended):** ```bash python main.py # Open your browser and navigate to: http://localhost:8000 ``` **CLI Mode:** ```bash python main.py cli # Interactive CLI for processing CSV files ``` ### Using the Web UI 1. **Open your browser** to `http://localhost:8000` 2. **Upload your CSV or XLSX** (XLSX uses the `AGRESSO` sheet) via drag/drop or browse 3. **Select a project** from the dropdown 4. **Click "Report Time"** to submit 5. Optionally **load and approve events** by selecting a date range in the Approve Events panel 6. View the **results summary** with total hours and days reported The web interface features: - ๐ŸŽฏ Drag-and-drop file upload - ๐Ÿ“‹ Real-time project list - ๐Ÿ’ซ Smooth animations and transitions - ๐Ÿ“ฑ Fully responsive design - ๐Ÿ”” Toast notifications for feedback - โœ… Connection status indicator ## API Endpoints ### GET / Serves the modern web UI interface. ### GET /api Returns API information and available endpoints. ### GET /health Health check endpoint - verifies API key configuration. **Response:** ```json { "status": "healthy", "api_key_configured": true } ``` ### GET /projects Lists all active projects for the configured user. **Response:** ```json { "Project Name": { "id": 123, "activity": {"id": 456} } } ``` ### POST /report-time Upload a CSV or XLSX file and report time to a specific project. **Parameters:** - `project_name` (query): Name of the project - `file` (form): CSV or XLSX file with time entries (XLSX sheet: `AGRESSO`) **Response:** ```json { "message": "Time reported successfully.", "reported_days": 5, "total_hours": 40.0, "project_name": "Project Name", "user_name": "Your Name" } ``` ### GET /docs Interactive API documentation (Swagger UI). ### GET /events List events for the configured user within a date range. **Query parameters:** - `start_date` (YYYY-MM-DD) - `end_date` (YYYY-MM-DD) ### POST /approve-events Approve events for the configured user within a date range. **Query parameters:** - `start_date` (YYYY-MM-DD) - `end_date` (YYYY-MM-DD) ## CSV/XLSX Format The application **automatically detects** the CSV delimiter (comma or semicolon) and column structure. XLSX parsing reads rows from the `AGRESSO` worksheet. ### Supported Formats **Format 1: Comma-separated with headers** ```csv reg_period,xreg_period,T,Time code,Time code (T),Vouch.date,Project Activity,Project Activity (T),Work package,Work package (T),Hours,Workflow status,Text 202544,,A,0,Standard Time,10/27/2025,,,,,2.00,N, 202544,,A,0,Standard Time,10/28/2025,,,,,4.00,N, ``` **Format 2: Semicolon-separated** ```csv ...;...;...;...;...;01/15/2024;...;...;...;...;8.5;... ...;...;...;...;...;01/16/2024;...;...;...;...;7,5;... ``` ### Column Detection - **Date column**: Automatically detected by searching for columns containing "date" or "vouch" in the header - **Hours column**: Automatically detected by searching for columns containing "hour" in the header - **Date formats**: Supports both `MM/DD/YYYY` and `YYYY-MM-DD` - **Hours format**: Supports decimal hours with comma (`,`) or dot (`.`) as separator - **Whitespace**: Automatically trimmed from values - **XLSX**: Only the `AGRESSO` worksheet is read; empty rows are skipped and date cells are normalized ## Development ### Project Structure ``` zynktime/ โ”œโ”€โ”€ static/ โ”‚ โ”œโ”€โ”€ index.html # Modern web UI โ”‚ โ”œโ”€โ”€ css/ โ”‚ โ”‚ โ””โ”€โ”€ style.css # Responsive styling โ”‚ โ””โ”€โ”€ js/ โ”‚ โ””โ”€โ”€ app.js # Frontend logic โ”œโ”€โ”€ main.py # FastAPI application entry point โ”œโ”€โ”€ cli.py # CLI interface โ”œโ”€โ”€ config.py # Configuration management โ”œโ”€โ”€ models.py # Pydantic models โ”œโ”€โ”€ api_client.py # Kleer API client โ”œโ”€โ”€ services.py # Business logic โ”œโ”€โ”€ test_main.py # Unit tests โ”œโ”€โ”€ requirements.txt # Python dependencies โ”œโ”€โ”€ AGENTS.md # Guidelines for AI agents โ””โ”€โ”€ README.md # This file ``` ### Running Tests ```bash # Run all tests pytest # Run with verbose output pytest -v # Run specific test pytest test_main.py::TestServices::test_validate_date_valid -v # Run with coverage pytest --cov=. --cov-report=html ``` ### Code Quality The codebase follows: - **Type hints**: Full typing support - **Error handling**: Specific exceptions with proper logging - **Separation of concerns**: Modular architecture - **Documentation**: Comprehensive docstrings - **Testing**: Unit tests for core functionality ## Environment Variables | Variable | Required | Default | Description | |----------|----------|---------|-------------| | `KLEER_API_KEY` | Yes | - | API key for Kleer API | | `KLEER_USERNAME` | No | Christopher Juhlin | Username for API requests | | `KLEER_COMPANY_ID` | No | 1336 | Company ID for API requests | ## Docker Deployment ### Production Deployment For production, you can customize the docker-compose.yml: ```yaml version: '3.8' services: zynktime: image: zynktime:latest restart: always ports: - "80:8000" # Expose on port 80 environment: - KLEER_API_KEY=${KLEER_API_KEY} - KLEER_USERNAME=${KLEER_USERNAME} - KLEER_COMPANY_ID=${KLEER_COMPANY_ID} env_file: - .env ``` ### Behind a Reverse Proxy If deploying behind nginx or traefik: ```yaml # docker-compose.yml services: zynktime: image: zynktime:latest networks: - proxy labels: - "traefik.enable=true" - "traefik.http.routers.zynktime.rule=Host(`time.example.com`)" ``` ### Health Checks The Docker container includes health checks: - **Endpoint**: `/health` - **Interval**: 30 seconds - **Timeout**: 10 seconds - **Retries**: 3 Monitor with: ```bash docker-compose ps docker inspect zynktime | grep Health ``` ## License This project is for internal use with the Kleer API.