docu: Add documentation for security, extensibility, deployment, and general overview

This commit is contained in:
Jean Jacques Avril 2025-03-09 10:42:01 +00:00
parent e31b93df93
commit be6340332e
19 changed files with 1623 additions and 103 deletions

22
docu/README.md Normal file
View File

@ -0,0 +1,22 @@
# Time Tracking and Management System Documentation
# Time Tracking and Management System Documentation
This document provides an overview of the Time Tracking and Management System. For detailed information, please refer to the following documents:
- [General Overview](general_overview.md)
- [Backend Architecture](backend_architecture.md)
- [Frontend Architecture](frontend_architecture.md)
- [Database Schema](database_schema.md)
- [Deployment and DevOps](deployment_devops.md)
- [Security and Privacy](security_privacy.md)
- [Extensibility and Integrations](extensibility_integrations.md)
- [LLM Guidance](llm_guidance.md)
- [Roadmap](Roadmap.md)
## Code Examples
- [GORM Entities](code_examples/gorm_entities.go)
- [FPGO Repository](code_examples/fpgo_repository.go)
- [FPGO Service](code_examples/fpgo_service.go)
- [API Handler](code_examples/api_handler.go)
- [React Component](code_examples/react_component.tsx)

153
docu/Roadmap.md Normal file
View File

@ -0,0 +1,153 @@
# Time Tracking System Roadmap
This document outlines the roadmap for the development of the Time Tracking and Management System.
## Project Phases
### Phase 1: MVP (Minimum Viable Product)
**Goal:** A functional system with core time tracking capabilities, user authentication, and basic project/activity management.
**Sub-phases:**
1. **1.1 Core Backend Setup:**
- Project initialization (Go, Next.js).
- Database setup (PostgreSQL, GORM).
- Basic API structure (Gin).
- Authentication setup (JWT).
2. **1.2 User Management:**
- User registration, login, and password management.
- Implementation of basic user roles (User, Admin).
3. **1.3 Company Management:**
- Company (tenant) creation and basic management (Admin only).
4. **1.4 Project and Activity Management:**
- Project creation/editing/deletion (name, description, company association).
- Activity creation/editing/deletion (name, billing rate, company association).
5. **1.5 Time Entry Core:**
- Time entry creation (start/stop timer functionality).
- Manual time entry input.
6. **1.6 Basic Frontend:**
- Basic UI for time entry.
- Basic UI for project/activity listing.
7. **1.7 Basic Listing and Filtering:**
- Time entry listing.
- Basic filtering (by user, project, date range).
8. **1.8 Simple Dashboard:**
- Display of recent time entries.
### Phase 2: Version 1
**Goal:** Full implementation of the features described in the initial version of the specification.
**Sub-phases:**
1. **2.1 Expanded Roles:**
- Implement Manager, Auditor, and Company roles.
2. **2.2 Client and Employee Management:**
- Client creation/editing/deletion.
- Employee creation/editing/deletion (with hourly rates).
3. **2.3 Detailed Time Entry:**
- Add fields for location, purpose, description, and billable percentage to time entries.
4. **2.4 Reporting Engine:**
- Implement report generation (by project, employee, client, time period).
- PDF export for reports.
5. **2.5 Dashboard Enhancements:**
- Add graphical dashboards with summaries and visualizations.
6. **2.6 Tracker Improvement:**
- Pre-populate tracker with data from the last booking.
7. **2.7 Multi-Tenancy Refinement:**
- Ensure complete data isolation between tenants.
8. **2.8 RBAC Implementation:**
- Implement fine-grained Role-Based Access Control.
9. **2.9 API Documentation:**
- Create comprehensive API documentation using Swagger.
10. **2.10 CI/CD Setup:**
- Implement a basic CI/CD pipeline for automated testing and deployment.
### Phase 3: Version 2
**Goal:** Implement the "Future Enhancements" outlined in the specification.
**Sub-phases:**
1. **3.1 Sprint and Task Management:**
- Add sprint and task entities to the data model.
- Implement sprint and task creation/editing/deletion.
2. **3.2 Kanban Boards:**
- Develop Kanban board UI components.
- Implement drag-and-drop functionality for task management.
3. **3.3 Task-Time Entry Linking:**
- Allow users to select a specific task when creating a time entry.
### Phase 4: Future Considerations
**Goal:** Expand the system with additional features and integrations.
**Sub-phases (Not exhaustive, can be further broken down):**
1. **4.1 Integrations:**
- Billing systems integration.
- Calendar integrations (Google Calendar, Outlook).
- Project management tool integrations (Jira, Trello).
- Webhook implementation.
- SSO implementation.
2. **4.2 Extensibility:**
- Develop a plugin system.
- Implement custom fields.
3. **4.3 Mobile App:**
- Develop responsive web design.
- Explore native mobile app development.
4. **4.4 Internationalization:**
- Implement multilingual support.
- Add localized date/time formats.
- Add currency conversion.
5. **4.5 Billing and Invoicing:**
- Implement invoice generation.
- Add billing data export functionality.
- Implement reminders for unrecorded time.
6. **4.6 Notification System:**
- Implement email and in-app notifications.
- Add reminders and approval requests.
7. **4.7 Analytics:**
- Implement advanced analytics and reporting.
- Add trend analysis and forecasting.
- Implement resource utilization tracking.
- Add export options for BI tools.
8. **4.8 Offline Functionality**
- Implement PWA features.
- Add local storage and synchronization.
9. **4.9 Enhanced Security:**
- Implement more detailed audit trails.
10. **4.10 Error Handling:**
- Implement a unified error handling and validation strategy.
11. **4.11 Performance:**
- Implement Caching (Redis).
- Optimize database with indexing.

View File

@ -0,0 +1,144 @@
# Backend Architecture (Go)
**Note:** This document describes a *conceptual* architecture and is not a final, binding requirement.
The backend is written in Go and follows the principles of **Clean Architecture** and **Domain-Driven Design (DDD)**.
## Project Structure
```
timetracker-backend/
├── cmd/ # Einstiegspunkte
│ ├── api/
│ │ └── main.go
│ └── worker/
│ └── main.go
├── internal/ # Interner Code
│ ├── domain/ # Domain Layer (DDD)
│ │ ├── entities/ # Domain Entitäten
│ │ │ ├── user.go
│ │ │ ├── company.go
│ │ │ ├── project.go
│ │ │ ├── timeentry.go
│ │ │ ├── customer.go
│ │ │ ├── activity.go
│ │ │ ├── sprint.go
│ │ │ ├── task.go
│ │ │ └── kanban.go
│ │ ├── repositories/ # Repository Interfaces
│ │ │ ├── user_repository.go
│ │ │ ├── company_repository.go
│ │ │ ├── project_repository.go
│ │ │ ├── timeentry_repository.go
│ │ │ └── ...
│ │ ├── services/ # Service Interfaces und Implementierungen
│ │ │ ├── auth_service.go
│ │ │ ├── user_service.go
│ │ │ ├── timetracking_service.go
│ │ │ ├── reporting_service.go
│ │ │ └── ...
│ │ └── valueobjects/ # Value Objects
│ │ ├── money.go
│ │ ├── duration.go
│ │ └── ...
│ ├── application/ # Anwendungsfälle
│ │ ├── auth/ # Authentication Use Cases
│ │ │ ├── login.go
│ │ │ ├── register.go
│ │ │ └── ...
│ │ ├── timetracking/ # Zeiterfassung Use Cases
│ │ │ ├── create_time_entry.go
│ │ │ ├── update_time_entry.go
│ │ │ ├── list_time_entries.go
│ │ │ └── ...
│ │ ├── projects/ # Projektverwaltung Use Cases
│ │ │ └── ...
│ │ ├── customers/ # Kundenverwaltung Use Cases
│ │ │ └── ...
│ │ └── reporting/ # Berichtswesen Use Cases
│ │ └── ...
│ ├── infrastructure/ # Infrastruktur
│ │ ├── persistence/ # Datenbankzugriff
│ │ │ ├── postgres/ # PostgreSQL Implementierung
│ │ │ │ ├── connection.go
│ │ │ │ ├── user_repository.go
│ │ │ │ ├── company_repository.go
│ │ │ │ └── ...
│ │ │ └── migrations/
│ │ ├── security/ # Sicherheitsimplementierungen
│ │ │ ├── jwt.go
│ │ │ ├── password.go
│ │ │ └── rbac.go
│ │ ├── messaging/ # Messaging-Implementierungen
│ │ │ ├── email.go
│ │ │ └── notification.go
│ │ └── external/ # Externe Dienste
│ │ ├── calendar/
│ │ ├── pdf/
│ │ └── webhook/
│ └── interfaces/ # Interfaces
│ ├── http/ # HTTP-API
│ │ ├── handlers/ # API Handler
│ │ │ ├── auth_handler.go
│ │ │ ├── user_handler.go
│ │ │ ├── time_entry_handler.go
│ │ │ └── ...
│ │ ├── middleware/ # Middleware
│ │ │ ├── auth_middleware.go
│ │ │ ├── tenant_middleware.go
│ │ │ ├── logging_middleware.go
│ │ │ └── ...
│ │ ├── dto/ # Data Transfer Objects
│ │ │ ├── auth_dto.go
│ │ │ ├── user_dto.go
│ │ │ ├── time_entry_dto.go
│ │ │ └── ...
│ │ └── routes/ # API Routes
│ │ └── router.go
│ └── grpc/ # gRPC-API (Optional für Microservice-Kommunikation)
├── pkg/ # Öffentliche Pakete
│ ├── functional/ # FPGO Utilities
│ │ ├── option.go
│ │ ├── result.go
│ │ └── ...
│ ├── validator/ # Validierung
│ │ └── validator.go
│ ├── logger/ # Logging
│ │ └── logger.go
│ ├── errors/ # Fehlerbehandlung
│ │ └── errors.go
│ └── utils/ # Allgemeine Utilities
│ ├── date.go
│ ├── crypto.go
│ └── ...
├── api/ # API Definitionen
│ └── swagger/ # Swagger Dokumentation
│ └── swagger.yaml
├── deployments/ # Deployment-Konfigurationen
│ ├── docker/
│ │ ├── Dockerfile
│ │ └── docker-compose.yml
│ └── kubernetes/
│ ├── api.yaml
│ └── worker.yaml
├── test/ # Tests
│ ├── unit/
│ ├── integration/
│ └── e2e/
├── scripts/ # Skripte
│ ├── migration.sh
│ ├── seed.sh
│ └── ...
├── docu/ # Projektdokumentation
│ ├── general_overview.md
│ ├── backend_architecture.md
│ ├── frontend_architecture.md
│ ├── database_schema.md
│ ├── security_privacy.md
│ ├── extensibility_integrations.md
│ ├── deployment_devops.md
│ ├── llm_guidance.md
│ └── README.md
├── go.mod
├── go.sum
└── README.md
```

View File

@ -0,0 +1,101 @@
// interfaces/http/handlers/time_entry_handler.go
package main
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/username/timetracker/internal/application/timetracking"
"github.com/username/timetracker/internal/interfaces/http/dto"
"github.com/username/timetracker/internal/interfaces/http/middleware"
)
// TimeEntryHandler behandelt HTTP-Anfragen für Zeitbuchungen
type TimeEntryHandler struct {
createTimeEntryUseCase *timetracking.CreateTimeEntryUseCase
updateTimeEntryUseCase *timetracking.UpdateTimeEntryUseCase
listTimeEntriesUseCase *timetracking.ListTimeEntriesUseCase
deleteTimeEntryUseCase *timetracking.DeleteTimeEntryUseCase
}
// NewTimeEntryHandler erstellt einen neuen TimeEntryHandler
func NewTimeEntryHandler(
createTimeEntryUseCase *timetracking.CreateTimeEntryUseCase,
updateTimeEntryUseCase *timetracking.UpdateTimeEntryUseCase,
listTimeEntriesUseCase *timetracking.ListTimeEntriesUseCase,
deleteTimeEntryUseCase *timetracking.DeleteTimeEntryUseCase,
) *TimeEntryHandler {
return &TimeEntryHandler{
createTimeEntryUseCase: createTimeEntryUseCase,
updateTimeEntryUseCase: updateTimeEntryUseCase,
listTimeEntriesUseCase: listTimeEntriesUseCase,
deleteTimeEntryUseCase: deleteTimeEntryUseCase,
}
}
// RegisterRoutes registriert die Routen am Router
func (h *TimeEntryHandler) RegisterRoutes(router *gin.RouterGroup) {
timeEntries := router.Group("/time-entries")
{
timeEntries.GET("", h.ListTimeEntries)
timeEntries.POST("", h.CreateTimeEntry)
timeEntries.GET("/:id", h.GetTimeEntry)
timeEntries.PUT("/:id", h.UpdateTimeEntry)
timeEntries.DELETE("/:id", h.DeleteTimeEntry)
}
}
// CreateTimeEntry behandelt die Erstellung einer neuen Zeitbuchung
func (h *TimeEntryHandler) CreateTimeEntry(c *gin.Context) {
var req dto.CreateTimeEntryRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// Tenant-ID aus dem Kontext extrahieren
companyID, exists := middleware.GetCompanyID(c)
if !exists {
c.JSON(http.StatusBadRequest, gin.H{"error": "Company ID not found"})
return
}
// Benutzer-ID aus dem Kontext oder Request
var userID uuid.UUID
if req.UserID != nil {
userID = *req.UserID
} else {
currentUserID, exists := middleware.GetUserID(c)
if !exists {
c.JSON(http.StatusBadRequest, gin.H{"error": "User ID not found"})
return
}
userID = currentUserID
}
// Command erstellen
cmd := timetracking.CreateTimeEntryCommand{
UserID: userID,
ProjectID: req.ProjectID,
ActivityID: req.ActivityID,
TaskID: req.TaskID,
StartTime: req.StartTime,
EndTime: req.EndTime,
Description: req.Description,
BillablePercentage: req.BillablePercentage,
}
// UseCase ausführen
result := h.createTimeEntryUseCase.Execute(c.Request.Context(), companyID, cmd)
if result.IsFailure() {
c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error().Error()})
return
}
// TimeEntry in Response-DTO umwandeln
timeEntry := result.Value()
response := dto.MapTimeEntryToDTO(*timeEntry)
c.JSON(http.StatusCreated, response)
}

View File

@ -0,0 +1,52 @@
// domain/repositories/time_entry_repository.go
package repositories
import (
"context"
"time"
"github.com/google/uuid"
"github.com/username/timetracker/internal/domain/entities"
"github.com/username/timetracker/pkg/functional"
)
// TimeEntryFilter enthält Filter für die Suche nach Zeitbuchungen
type TimeEntryFilter struct {
UserID *uuid.UUID
ProjectID *uuid.UUID
CustomerID *uuid.UUID
StartDate *time.Time
EndDate *time.Time
ActivityID *uuid.UUID
TaskID *uuid.UUID
}
// TimeEntryRepository Interface für den Zugriff auf Zeitbuchungen
type TimeEntryRepository interface {
// FindByID sucht eine Zeitbuchung anhand ihrer ID
FindByID(ctx context.Context, companyID, id uuid.UUID) functional.Result[*entities.TimeEntry]
// FindAll sucht alle Zeitbuchungen mit optionalen Filtern
FindAll(ctx context.Context, companyID uuid.UUID, filter TimeEntryFilter) functional.Result[[]entities.TimeEntry]
// Create erstellt eine neue Zeitbuchung
Create(ctx context.Context, entry *entities.TimeEntry) functional.Result[*entities.TimeEntry]
// Update aktualisiert eine bestehende Zeitbuchung
Update(ctx context.Context, entry *entities.TimeEntry) functional.Result[*entities.TimeEntry]
// Delete löscht eine Zeitbuchung
Delete(ctx context.Context, companyID, id uuid.UUID) functional.Result[bool]
// GetSummary berechnet eine Zusammenfassung der Zeitbuchungen
GetSummary(ctx context.Context, companyID uuid.UUID, filter TimeEntryFilter) functional.Result[TimeEntrySummary]
}
// TimeEntrySummary enthält zusammengefasste Informationen über Zeitbuchungen
type TimeEntrySummary struct {
TotalDuration int
TotalBillableDuration int
TotalAmount float64
TotalBillableAmount float64
EntriesCount int
}

View File

@ -0,0 +1,99 @@
// application/timetracking/create_time_entry.go
package main
import (
"context"
"time"
"github.com/google/uuid"
"github.com/username/timetracker/internal/domain/entities"
"github.com/username/timetracker/internal/domain/repositories"
"github.com/username/timetracker/pkg/functional"
"github.com/username/timetracker/pkg/validator"
)
// CreateTimeEntryCommand enthält die Daten zum Erstellen einer Zeitbuchung
type CreateTimeEntryCommand struct {
UserID uuid.UUID
ProjectID uuid.UUID
ActivityID uuid.UUID
TaskID *uuid.UUID
StartTime time.Time
EndTime time.Time
Description string
BillablePercentage int
}
// CreateTimeEntryUseCase repräsentiert den Anwendungsfall zum Erstellen einer Zeitbuchung
type CreateTimeEntryUseCase struct {
timeEntryRepo repositories.TimeEntryRepository
projectRepo repositories.ProjectRepository
activityRepo repositories.ActivityRepository
userRepo repositories.UserRepository
}
// NewCreateTimeEntryUseCase erstellt eine neue Instanz des UseCase
func NewCreateTimeEntryUseCase(
timeEntryRepo repositories.TimeEntryRepository,
projectRepo repositories.ProjectRepository,
activityRepo repositories.ActivityRepository,
userRepo repositories.UserRepository,
) *CreateTimeEntryUseCase {
return &CreateTimeEntryUseCase{
timeEntryRepo: timeEntryRepo,
projectRepo: projectRepo,
activityRepo: activityRepo,
userRepo: userRepo,
}
}
// Execute führt den Anwendungsfall aus
func (uc *CreateTimeEntryUseCase) Execute(ctx context.Context, companyID uuid.UUID, cmd CreateTimeEntryCommand) functional.Result[*entities.TimeEntry] {
// Validierung
if err := validator.ValidateStruct(cmd); err != nil {
return functional.Failure[*entities.TimeEntry](err)
}
// Überprüfen, ob Projekt existiert und zum gleichen Tenant gehört
projectResult := uc.projectRepo.FindByID(ctx, companyID, cmd.ProjectID)
if projectResult.IsFailure() {
return functional.Failure[*entities.TimeEntry](projectResult.Error())
}
// Überprüfen, ob Activity existiert und zum gleichen Tenant gehört
activityResult := uc.activityRepo.FindByID(ctx, companyID, cmd.ActivityID)
if activityResult.IsFailure() {
return functional.Failure[*entities.TimeEntry](activityResult.Error())
}
activity := activityResult.Value()
// Benutzer abrufen für den Stundensatz
userResult := uc.userRepo.FindByID(ctx, companyID, cmd.UserID)
if userResult.IsFailure() {
return functional.Failure[*entities.TimeEntry](userResult.Error())
}
user := userResult.Value()
// Berechnung der Dauer in Minuten
durationMinutes := int(cmd.EndTime.Sub(cmd.StartTime).Minutes())
// TimeEntry erstellen
timeEntry := &entities.TimeEntry{
TenantEntity: entities.TenantEntity{
CompanyID: companyID,
},
UserID: cmd.UserID,
ProjectID: cmd.ProjectID,
ActivityID: cmd.ActivityID,
TaskID: cmd.TaskID,
StartTime: cmd.StartTime,
EndTime: cmd.EndTime,
DurationMinutes: durationMinutes,
Description: cmd.Description,
BillablePercentage: cmd.BillablePercentage,
BillingRate: activity.BillingRate,
}
// Speichern der TimeEntry
return uc.timeEntryRepo.Create(ctx, timeEntry)
}

View File

@ -0,0 +1,104 @@
package entities
import (
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
// BaseEntity enthält gemeinsame Felder für alle Entitäten
type BaseEntity struct {
ID uuid.UUID `gorm:"type:uuid;primary_key"`
CreatedAt time.Time `gorm:"autoCreateTime"`
UpdatedAt time.Time `gorm:"autoUpdateTime"`
DeletedAt gorm.DeletedAt `gorm:"index"`
}
// BeforeCreate setzt eine neue UUID vor dem Erstellen
func (base *BaseEntity) BeforeCreate(tx *gorm.DB) error {
if base.ID == uuid.Nil {
base.ID = uuid.New()
}
return nil
}
// TenantEntity erweitert BaseEntity um Company-ID für Multi-Tenancy
type TenantEntity struct {
BaseEntity
CompanyID uuid.UUID `gorm:"type:uuid;index:idx_tenant"`
}
// Role repräsentiert eine Benutzerrolle
type Role struct {
BaseEntity
Name string `gorm:"unique;not null"`
Description string
Permissions []Permission `gorm:"many2many:role_permissions;"`
}
// Permission repräsentiert eine einzelne Berechtigung
type Permission struct {
BaseEntity
Resource string `gorm:"not null"`
Action string `gorm:"not null"`
UniqueID string `gorm:"uniqueIndex"`
}
// User repräsentiert einen Benutzer im System
type User struct {
TenantEntity
Email string `gorm:"uniqueIndex;not null"`
FirstName string
LastName string
PasswordHash string `gorm:"not null"`
RoleID uuid.UUID `gorm:"type:uuid"`
Role Role `gorm:"foreignKey:RoleID"`
HourlyRate float64
IsActive bool `gorm:"default:true"`
}
// FullName gibt den vollständigen Namen des Benutzers zurück
func (u User) FullName() string {
return u.FirstName + " " + u.LastName
}
// TimeEntry repräsentiert eine Zeitbuchung
type TimeEntry struct {
TenantEntity
UserID uuid.UUID `gorm:"type:uuid;index:idx_user"`
User User `gorm:"foreignKey:UserID"`
ProjectID uuid.UUID `gorm:"type:uuid;index:idx_project"`
Project Project `gorm:"foreignKey:ProjectID"`
ActivityID uuid.UUID `gorm:"type:uuid"`
Activity Activity `gorm:"foreignKey:ActivityID"`
TaskID *uuid.UUID `gorm:"type:uuid;null"`
Task *Task `gorm:"foreignKey:TaskID"`
StartTime time.Time `gorm:"not null;index:idx_time_range"`
EndTime time.Time `gorm:"not null;index:idx_time_range"`
DurationMinutes int `gorm:"not null"`
Description string
BillablePercentage int `gorm:"default:100"`
BillingRate float64
}
type Project struct {
TenantEntity
Name string
}
type Activity struct {
TenantEntity
Name string
}
type Task struct {
TenantEntity
Name string
}
// CalculateBillableAmount berechnet den abrechenbaren Betrag
func (t TimeEntry) CalculateBillableAmount() float64 {
hours := float64(t.DurationMinutes) / 60.0
return hours * t.BillingRate * (float64(t.BillablePercentage) / 100.0)
}

View File

@ -0,0 +1,136 @@
// presentation/components/timeTracker/Timer/Timer.tsx
import React, { useState, useEffect } from 'react';
import { useTimeTracking } from '../../../hooks/useTimeTracking';
import { pipe, Option, fromNullable } from '../../../../utils/fp/option';
import { Button } from '../../common/Button';
import { formatDuration } from '../../../../utils/date/dateUtils';
interface TimerProps {
onComplete?: (duration: number) => void;
}
export const Timer: React.FC<TimerProps> = ({ onComplete }) => {
const [isRunning, setIsRunning] = useState(false);
const [startTime, setStartTime] = useState<Option<Date>>(Option.none());
const [elapsedTime, setElapsedTime] = useState(0);
const [selectedProject, setSelectedProject] = useState<Option<string>>(Option.none());
const [selectedActivity, setSelectedActivity] = useState<Option<string>>(Option.none());
const { lastTimeEntry, projects, activities } = useTimeTracking();
// Beim ersten Rendering die letzte Zeitbuchung laden
useEffect(() => {
pipe(
fromNullable(lastTimeEntry),
Option.map(entry => {
setSelectedProject(Option.some(entry.projectId));
setSelectedActivity(Option.some(entry.activityId));
})
);
}, [lastTimeEntry]);
// Timer-Logik
useEffect(() => {
let interval: NodeJS.Timeout | null = null;
if (isRunning) {
interval = setInterval(() => {
const now = new Date();
pipe(
startTime,
Option.map(start => {
const diff = now.getTime() - start.getTime();
setElapsedTime(Math.floor(diff / 1000));
})
);
}, 1000);
} else if (interval) {
clearInterval(interval);
}
return () => {
if (interval) clearInterval(interval);
};
}, [isRunning, startTime]);
// Timer starten
const handleStart = () => {
setStartTime(Option.some(new Date()));
setIsRunning(true);
};
// Timer stoppen
const handleStop = () => {
setIsRunning(false);
// Prüfen, ob Projekt und Aktivität ausgewählt wurden
const projectId = pipe(
selectedProject,
Option.getOrElse(() => '')
);
const activityId = pipe(
selectedActivity,
Option.getOrElse(() => '')
);
if (projectId && activityId && onComplete) {
onComplete(elapsedTime);
}
// Timer zurücksetzen
setElapsedTime(0);
setStartTime(Option.none());
};
return (
<div className="bg-white rounded-lg shadow-md p-4">
<div className="text-4xl text-center font-mono mb-4">
{formatDuration(elapsedTime)}
</div>
<div className="grid grid-cols-2 gap-4 mb-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Projekt
</label>
<select
className="w-full border border-gray-300 rounded-md px-3 py-2"
value={pipe(selectedProject, Option.getOrElse(() => ''))}
onChange={(e) => setSelectedProject(Option.some(e.target.value))}
disabled={isRunning}
>
<option value="">Projekt auswählen</option>
{projects.map((project) => (
<option key={project.id} value={project.id}>
{project.name}
</option>
))}
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Tätigkeit
</label>
<select
className="w-full border border-gray-300 rounded-md px-3 py-2"
value={pipe(selectedActivity, Option.getOrElse(() => ''))}
onChange={(e) => setSelectedActivity(Option.some(e.target.value))}
disabled={isRunning}
>
<option value="">Tätigkeit auswählen</option>
{activities.map((activity) => (
<option key={activity.id} value={activity.id}>
{activity.name}
</option>
))}
</select>
</div>
</div>
<div className="flex justify-center">
</div>
</div>
);
};

View File

@ -1,103 +0,0 @@
timetracker-frontend/
├── public/ # Statische Dateien
│ ├── assets/
│ │ ├── images/
│ │ ├── icons/
│ │ └── fonts/
│ └── locales/ # Mehrsprachige Inhalte
│ ├── de/
│ └── en/
├── src/
│ ├── app/ # Next.js 13+ App Router
│ │ ├── api/ # API-Routen (falls nötig)
│ │ ├── (auth)/ # Authentifizierungsseiten
│ │ │ ├── login/
│ │ │ └── register/
│ │ ├── dashboard/ # Dashboard-Seiten
│ │ │ ├── page.tsx
│ │ │ └── layout.tsx
│ │ ├── time-tracking/ # Zeiterfassungsseiten
│ │ │ ├── page.tsx
│ │ │ ├── [id]/
│ │ │ └── components/
│ │ ├── projects/ # Projektseiten
│ │ │ ├── page.tsx
│ │ │ └── [id]/
│ │ ├── customers/ # Kundenseiten
│ │ │ ├── page.tsx
│ │ │ └── [id]/
│ │ ├── reports/ # Berichtsseiten
│ │ │ ├── page.tsx
│ │ │ └── [type]/
│ │ ├── admin/ # Administrationsseiten
│ │ │ ├── users/
│ │ │ ├── companies/
│ │ │ └── settings/
│ │ ├── kanban/ # Kanban-Boards (Version 2)
│ │ │ ├── page.tsx
│ │ │ └── [id]/
│ │ ├── layout.tsx
│ │ └── page.tsx
│ ├── components/ # Wiederverwendbare Komponenten
│ │ ├── common/ # Allgemeine Komponenten
│ │ │ ├── Button.tsx
│ │ │ ├── Card.tsx
│ │ │ ├── Input.tsx
│ │ │ └── ...
│ │ ├── layout/ # Layout-Komponenten
│ │ │ ├── Navbar.tsx
│ │ │ ├── Sidebar.tsx
│ │ │ ├── Footer.tsx
│ │ │ └── ...
│ │ ├── dashboard/ # Dashboard-Komponenten
│ │ │ ├── ActivityChart.tsx
│ │ │ ├── RecentEntries.tsx
│ │ │ └── ...
│ │ ├── timetracker/ # Zeiterfassungskomponenten
│ │ │ ├── Timer.tsx
│ │ │ ├── EntryForm.tsx
│ │ │ └── ...
│ │ ├── reports/ # Berichtskomponenten
│ │ │ ├── ReportFilter.tsx
│ │ │ ├── Chart.tsx
│ │ │ └── ...
│ │ └── kanban/ # Kanban-Komponenten (Version 2)
│ │ ├── Board.tsx
│ │ ├── Column.tsx
│ │ ├── Card.tsx
│ │ └── ...
│ ├── hooks/ # Custom React Hooks
│ │ ├── useAuth.ts
│ │ ├── useTimeTracking.ts
│ │ ├── useProjects.ts
│ │ └── ...
│ ├── lib/ # Hilfsfunktionen und Bibliotheken
│ │ ├── api.ts # API Client
│ │ ├── auth.ts # Auth-Utilities
│ │ ├── date-utils.ts # Date-Helpers
│ │ └── ...
│ ├── types/ # TypeScript-Typdefinitionen
│ │ ├── auth.ts
│ │ ├── user.ts
│ │ ├── timeTracking.ts
│ │ ├── project.ts
│ │ └── ...
│ ├── store/ # State Management (falls benötigt)
│ │ ├── slices/
│ │ └── index.ts
│ ├── styles/ # CSS/SCSS Styles
│ │ ├── globals.css
│ │ └── theme.ts
│ └── utils/ # Allgemeine Hilfsfunktionen
│ ├── format.ts
│ ├── validation.ts
│ └── ...
├── .env.local.example
├── .eslintrc.json
├── next.config.js
├── package.json
├── tailwind.config.js
├── tsconfig.json
├── jest.config.js # Test-Konfiguration
├── postcss.config.js # PostCSS-Konfiguration
└── README.md

160
docu/database_schema.md Normal file
View File

@ -0,0 +1,160 @@
# Database Schema (PostgreSQL)
```sql
-- Multi-Tenant
CREATE TABLE companies (
id UUID PRIMARY KEY,
name VARCHAR(255) NOT NULL,
address TEXT,
contact_email VARCHAR(255),
contact_phone VARCHAR(50),
logo_url TEXT,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- Users and Roles
CREATE TABLE roles (
id SERIAL PRIMARY KEY,
name VARCHAR(50) UNIQUE NOT NULL,
permissions JSONB
);
CREATE TABLE users (
id UUID PRIMARY KEY,
company_id UUID REFERENCES companies(id),
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
first_name VARCHAR(100),
last_name VARCHAR(100),
role_id INTEGER REFERENCES roles(id),
hourly_rate DECIMAL(10, 2),
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- Customers
CREATE TABLE customers (
id UUID PRIMARY KEY,
company_id UUID NOT NULL REFERENCES companies(id),
name VARCHAR(255) NOT NULL,
contact_person VARCHAR(255),
email VARCHAR(255),
phone VARCHAR(50),
address TEXT,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- Projects
CREATE TABLE projects (
id UUID PRIMARY KEY,
company_id UUID NOT NULL REFERENCES companies(id),
customer_id UUID REFERENCES customers(id),
name VARCHAR(255) NOT NULL,
description TEXT,
start_date DATE,
end_date DATE,
status VARCHAR(50),
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- Activities
CREATE TABLE activities (
id UUID PRIMARY KEY,
company_id UUID NOT NULL REFERENCES companies(id),
name VARCHAR(255) NOT NULL,
description TEXT,
billing_rate DECIMAL(10, 2),
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- Time bookings
CREATE TABLE time_entries (
id UUID PRIMARY KEY,
company_id UUID NOT NULL REFERENCES companies(id),
user_id UUID NOT NULL REFERENCES users(id),
project_id UUID NOT NULL REFERENCES projects(id),
activity_id UUID NOT NULL REFERENCES activities(id),
start_time TIMESTAMP NOT NULL,
end_time TIMESTAMP NOT NULL,
duration INTEGER NOT NULL, -- in minutes
description TEXT,
billable_percentage INTEGER NOT NULL DEFAULT 100,
billing_rate DECIMAL(10, 2),
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- Version 2: Sprint/Task Management
CREATE TABLE sprints (
id UUID PRIMARY KEY,
project_id UUID NOT NULL REFERENCES projects(id),
name VARCHAR(255) NOT NULL,
start_date DATE NOT NULL,
end_date DATE NOT NULL,
status VARCHAR(50),
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE TABLE task_statuses (
id SERIAL PRIMARY KEY,
company_id UUID NOT NULL REFERENCES companies(id),
name VARCHAR(100) NOT NULL,
color VARCHAR(7),
position INTEGER NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE TABLE tasks (
id UUID PRIMARY KEY,
company_id UUID NOT NULL REFERENCES companies(id),
project_id UUID NOT NULL REFERENCES projects(id),
sprint_id UUID REFERENCES sprints(id),
title VARCHAR(255) NOT NULL,
description TEXT,
assignee_id UUID REFERENCES users(id),
status_id INTEGER REFERENCES task_statuses(id),
priority VARCHAR(50),
estimate INTEGER, -- in minutes
due_date TIMESTAMP,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE TABLE kanban_boards (
id UUID PRIMARY KEY,
company_id UUID NOT NULL REFERENCES companies(id),
project_id UUID NOT NULL REFERENCES projects(id),
name VARCHAR(255) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE TABLE kanban_columns (
id UUID PRIMARY KEY,
board_id UUID NOT NULL REFERENCES kanban_boards(id),
name VARCHAR(100) NOT NULL,
position INTEGER NOT NULL,
task_status_id INTEGER REFERENCES task_statuses(id),
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- Linking time entries and tasks
ALTER TABLE time_entries ADD COLUMN task_id UUID REFERENCES tasks(id);
-- Indexes for performance
CREATE INDEX idx_time_entries_user ON time_entries(user_id);
CREATE INDEX idx_time_entries_project ON time_entries(project_id);
CREATE INDEX idx_time_entries_date ON time_entries(start_time);
CREATE INDEX idx_projects_company ON projects(company_id);
CREATE INDEX idx_users_company ON users(company_id);
CREATE INDEX idx_tasks_project ON tasks(project_id);
CREATE INDEX idx_tasks_sprint ON tasks(sprint_id);

17
docu/deployment_devops.md Normal file
View File

@ -0,0 +1,17 @@
# Deployment and DevOps
## Containerization
- Docker containers for backend and frontend
- Docker Compose for development environment
- Kubernetes manifests for production environment
## CI/CD Pipeline
- Automated tests (Unit, Integration, E2E)
- Automated deployment
- Version management
## Monitoring and Logging
- Prometheus for metrics
- Grafana for visualization
- ELK Stack or similar for logging
- Alerting for critical events

View File

@ -0,0 +1,389 @@
# Zeiterfassungstool - Projektstruktur
## Backend (Go)
```
timetracker-backend/
├── cmd/ # Einstiegspunkte für die Anwendung
│ ├── api/ # API-Server
│ │ └── main.go
│ └── worker/ # Hintergrundprozesse (Reports, Benachrichtigungen usw.)
│ └── main.go
├── internal/ # Interner Code, nicht exportierbar
│ ├── auth/ # Authentifizierung und Autorisierung
│ │ ├── jwt.go
│ │ ├── middleware.go
│ │ ├── permissions.go
│ │ └── service.go
│ ├── tenant/ # Multi-Tenant-Funktionalität
│ │ ├── middleware.go
│ │ └── service.go
│ ├── user/ # Benutzerverwaltung
│ │ ├── model.go
│ │ ├── repository.go
│ │ └── service.go
│ ├── company/ # Unternehmensverwaltung
│ │ ├── model.go
│ │ ├── repository.go
│ │ └── service.go
│ ├── customer/ # Kundenverwaltung
│ │ ├── model.go
│ │ ├── repository.go
│ │ └── service.go
│ ├── project/ # Projektverwaltung
│ │ ├── model.go
│ │ ├── repository.go
│ │ └── service.go
│ ├── activity/ # Tätigkeitsverwaltung
│ │ ├── model.go
│ │ ├── repository.go
│ │ └── service.go
│ ├── timetracking/ # Zeiterfassung
│ │ ├── model.go
│ │ ├── repository.go
│ │ └── service.go
│ ├── billing/ # Abrechnung
│ │ ├── model.go
│ │ ├── repository.go
│ │ └── service.go
│ ├── reporting/ # Berichtswesen
│ │ ├── generator.go
│ │ ├── pdf.go
│ │ └── service.go
│ ├── notification/ # Benachrichtigungen
│ │ ├── email.go
│ │ ├── inapp.go
│ │ └── service.go
│ ├── kanban/ # Kanban-Board (Version 2)
│ │ ├── model.go
│ │ ├── repository.go
│ │ └── service.go
│ ├── task/ # Task-Management (Version 2)
│ │ ├── model.go
│ │ ├── repository.go
│ │ └── service.go
│ ├── sprint/ # Sprint-Management (Version 2)
│ │ ├── model.go
│ │ ├── repository.go
│ │ └── service.go
│ ├── config/ # Konfiguration
│ │ └── config.go
│ └── database/ # Datenbankzugriff
│ ├── migrations/
│ ├── seeds/
│ └── connection.go
├── pkg/ # Öffentliche Pakete, die exportiert werden können
│ ├── apierror/ # API-Fehlerobjekte
│ │ └── error.go
│ ├── logger/ # Logging-Funktionalität
│ │ └── logger.go
│ ├── validator/ # Validierungsfunktionen
│ │ └── validator.go
│ └── utils/ # Allgemeine Hilfsfunktionen
│ ├── dates.go
│ ├── encryption.go
│ └── helpers.go
├── api/ # API-Definitionen
│ ├── handlers/ # API-Handler
│ │ ├── auth.go
│ │ ├── user.go
│ │ ├── company.go
│ │ ├── customer.go
│ │ ├── project.go
│ │ ├── timetracking.go
│ │ ├── reporting.go
│ │ └── task.go
│ ├── middleware/ # API-Middleware
│ │ ├── auth.go
│ │ ├── tenant.go
│ │ └── logging.go
│ ├── routes/ # API-Routen
│ │ └── routes.go
│ └── swagger/ # Swagger-Dokumentation
│ └── swagger.yaml
├── test/ # Tests
│ ├── integration/
│ ├── unit/
│ └── mocks/
├── scripts/ # Skripte für Build, Deployment usw.
│ ├── build.sh
│ ├── migrate.sh
│ └── seed.sh
├── docker/ # Docker-Konfiguration
│ ├── Dockerfile
│ └── docker-compose.yml
├── go.mod
├── go.sum
├── .env.example
└── README.md
```
## Frontend (NextJS)
```
timetracker-frontend/
├── public/ # Statische Dateien
│ ├── assets/
│ │ ├── images/
│ │ ├── icons/
│ │ └── fonts/
│ └── locales/ # Mehrsprachige Inhalte
│ ├── de/
│ └── en/
├── src/
│ ├── app/ # Next.js 13+ App Router
│ │ ├── api/ # API-Routen (falls nötig)
│ │ ├── (auth)/ # Authentifizierungsseiten
│ │ │ ├── login/
│ │ │ └── register/
│ │ ├── dashboard/ # Dashboard-Seiten
│ │ │ ├── page.tsx
│ │ │ └── layout.tsx
│ │ ├── time-tracking/ # Zeiterfassungsseiten
│ │ │ ├── page.tsx
│ │ │ ├── [id]/
│ │ │ └── components/
│ │ ├── projects/ # Projektseiten
│ │ │ ├── page.tsx
│ │ │ └── [id]/
│ │ ├── customers/ # Kundenseiten
│ │ │ ├── page.tsx
│ │ │ └── [id]/
│ │ ├── reports/ # Berichtsseiten
│ │ │ ├── page.tsx
│ │ │ └── [type]/
│ │ ├── admin/ # Administrationsseiten
│ │ │ ├── users/
│ │ │ ├── companies/
│ │ │ └── settings/
│ │ ├── kanban/ # Kanban-Boards (Version 2)
│ │ │ ├── page.tsx
│ │ │ └── [id]/
│ │ ├── layout.tsx
│ │ └── page.tsx
│ ├── components/ # Wiederverwendbare Komponenten
│ │ ├── common/ # Allgemeine Komponenten
│ │ │ ├── Button.tsx
│ │ │ ├── Card.tsx
│ │ │ ├── Input.tsx
│ │ │ └── ...
│ │ ├── layout/ # Layout-Komponenten
│ │ │ ├── Navbar.tsx
│ │ │ ├── Sidebar.tsx
│ │ │ ├── Footer.tsx
│ │ │ └── ...
│ │ ├── dashboard/ # Dashboard-Komponenten
│ │ │ ├── ActivityChart.tsx
│ │ │ ├── RecentEntries.tsx
│ │ │ └── ...
│ │ ├── timetracker/ # Zeiterfassungskomponenten
│ │ │ ├── Timer.tsx
│ │ │ ├── EntryForm.tsx
│ │ │ └── ...
│ │ ├── reports/ # Berichtskomponenten
│ │ │ ├── ReportFilter.tsx
│ │ │ ├── Chart.tsx
│ │ │ └── ...
│ │ └── kanban/ # Kanban-Komponenten (Version 2)
│ │ ├── Board.tsx
│ │ ├── Column.tsx
│ │ ├── Card.tsx
│ │ └── ...
│ ├── hooks/ # Custom React Hooks
│ │ ├── useAuth.ts
│ │ ├── useTimeTracking.ts
│ │ ├── useProjects.ts
│ │ └── ...
│ ├── lib/ # Hilfsfunktionen und Bibliotheken
│ │ ├── api.ts # API Client
│ │ ├── auth.ts # Auth-Utilities
│ │ ├── date-utils.ts # Date-Helpers
│ │ └── ...
│ ├── types/ # TypeScript-Typdefinitionen
│ │ ├── auth.ts
│ │ ├── user.ts
│ │ ├── timeTracking.ts
│ │ ├── project.ts
│ │ └── ...
│ ├── store/ # State Management (falls benötigt)
│ │ ├── slices/
│ │ └── index.ts
│ ├── styles/ # CSS/SCSS Styles
│ │ ├── globals.css
│ │ └── theme.ts
│ └── utils/ # Allgemeine Hilfsfunktionen
│ ├── format.ts
│ ├── validation.ts
│ └── ...
├── .env.local.example
├── .eslintrc.json
├── next.config.js
├── package.json
├── tailwind.config.js
├── tsconfig.json
├── jest.config.js # Test-Konfiguration
├── postcss.config.js # PostCSS-Konfiguration
└── README.md
```
## Datenbankschema (PostgreSQL)
```sql
-- Multi-Tenant
CREATE TABLE companies (
id UUID PRIMARY KEY,
name VARCHAR(255) NOT NULL,
address TEXT,
contact_email VARCHAR(255),
contact_phone VARCHAR(50),
logo_url TEXT,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- Benutzer und Rollen
CREATE TABLE roles (
id SERIAL PRIMARY KEY,
name VARCHAR(50) UNIQUE NOT NULL,
permissions JSONB
);
CREATE TABLE users (
id UUID PRIMARY KEY,
company_id UUID REFERENCES companies(id),
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
first_name VARCHAR(100),
last_name VARCHAR(100),
role_id INTEGER REFERENCES roles(id),
hourly_rate DECIMAL(10, 2),
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- Kunden
CREATE TABLE customers (
id UUID PRIMARY KEY,
company_id UUID NOT NULL REFERENCES companies(id),
name VARCHAR(255) NOT NULL,
contact_person VARCHAR(255),
email VARCHAR(255),
phone VARCHAR(50),
address TEXT,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- Projekte
CREATE TABLE projects (
id UUID PRIMARY KEY,
company_id UUID NOT NULL REFERENCES companies(id),
customer_id UUID REFERENCES customers(id),
name VARCHAR(255) NOT NULL,
description TEXT,
start_date DATE,
end_date DATE,
status VARCHAR(50),
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- Tätigkeiten
CREATE TABLE activities (
id UUID PRIMARY KEY,
company_id UUID NOT NULL REFERENCES companies(id),
name VARCHAR(255) NOT NULL,
description TEXT,
billing_rate DECIMAL(10, 2),
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- Zeitbuchungen
CREATE TABLE time_entries (
id UUID PRIMARY KEY,
company_id UUID NOT NULL REFERENCES companies(id),
user_id UUID NOT NULL REFERENCES users(id),
project_id UUID NOT NULL REFERENCES projects(id),
activity_id UUID NOT NULL REFERENCES activities(id),
start_time TIMESTAMP NOT NULL,
end_time TIMESTAMP NOT NULL,
duration INTEGER NOT NULL, -- in minutes
description TEXT,
billable_percentage INTEGER NOT NULL DEFAULT 100,
billing_rate DECIMAL(10, 2),
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- Version 2: Sprint/Task Management
CREATE TABLE sprints (
id UUID PRIMARY KEY,
project_id UUID NOT NULL REFERENCES projects(id),
name VARCHAR(255) NOT NULL,
start_date DATE NOT NULL,
end_date DATE NOT NULL,
status VARCHAR(50),
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE TABLE task_statuses (
id SERIAL PRIMARY KEY,
company_id UUID NOT NULL REFERENCES companies(id),
name VARCHAR(100) NOT NULL,
color VARCHAR(7),
position INTEGER NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE TABLE tasks (
id UUID PRIMARY KEY,
company_id UUID NOT NULL REFERENCES companies(id),
project_id UUID NOT NULL REFERENCES projects(id),
sprint_id UUID REFERENCES sprints(id),
title VARCHAR(255) NOT NULL,
description TEXT,
assignee_id UUID REFERENCES users(id),
status_id INTEGER REFERENCES task_statuses(id),
priority VARCHAR(50),
estimate INTEGER, -- in minutes
due_date TIMESTAMP,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE TABLE kanban_boards (
id UUID PRIMARY KEY,
company_id UUID NOT NULL REFERENCES companies(id),
project_id UUID NOT NULL REFERENCES projects(id),
name VARCHAR(255) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE TABLE kanban_columns (
id UUID PRIMARY KEY,
board_id UUID NOT NULL REFERENCES kanban_boards(id),
name VARCHAR(100) NOT NULL,
position INTEGER NOT NULL,
task_status_id INTEGER REFERENCES task_statuses(id),
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- Verknüpfung zwischen Zeitbuchungen und Tasks
ALTER TABLE time_entries ADD COLUMN task_id UUID REFERENCES tasks(id);
-- Indizes für Performance
CREATE INDEX idx_time_entries_user ON time_entries(user_id);
CREATE INDEX idx_time_entries_project ON time_entries(project_id);
CREATE INDEX idx_time_entries_date ON time_entries(start_time);
CREATE INDEX idx_projects_company ON projects(company_id);
CREATE INDEX idx_users_company ON users(company_id);
CREATE INDEX idx_tasks_project ON tasks(project_id);
CREATE INDEX idx_tasks_sprint ON tasks(sprint_id);
```

View File

@ -0,0 +1,6 @@
# Extensibility and Integrations
- API for external billing systems and calendar integration
- Single Sign-On (Google, Microsoft, SAML)
- Plugin system and custom fields for extensibility
- Analytics and BI export

View File

@ -0,0 +1,102 @@
# Frontend Architecture (Next.js)
**Note:** This document describes a *conceptual* architecture and is not a final, binding requirement.
The frontend uses **Next.js** with **TypeScript** and **FPTS** for functional programming.
## Project Structure
```
timetracker-frontend/
├── public/ # Statische Dateien
│ ├── assets/
│ └── locales/ # i18n Übersetzungen
├── src/
│ ├── app/ # Next.js App Router
│ │ ├── api/ # API Routes
│ │ ├── (auth)/ # Auth Pages
│ │ ├── dashboard/
│ │ ├── time-tracking/
│ │ ├── projects/
│ │ └── ...
│ ├── domain/ # Domain Model (analog zu Backend)
│ │ ├── entities/ # Domain Entities
│ │ │ ├── user.ts
│ │ │ ├── timeEntry.ts
│ │ │ ├── project.ts
│ │ │ └── ...
│ │ └── valueObjects/ # Value Objects
│ │ ├── money.ts
│ │ ├── duration.ts
│ │ └── ...
│ ├── application/ # Anwendungsfälle
│ │ ├── auth/ # Auth Use Cases
│ │ ├── timeTracking/ # Time Tracking Use Cases
│ │ ├── projects/ # Projects Use Cases
│ │ └── ...
│ ├── infrastructure/ # Infrastruktur
│ │ ├── api/ # API Client
│ │ │ ├── apiClient.ts # Axios Konfiguration
│ │ │ ├── endpoints.ts # API Endpunkte
│ │ │ └── interceptors.ts # Request/Response Interceptors
│ │ ├── storage/ # Lokale Speicherung
│ │ │ ├── localStorage.ts
│ │ │ └── sessionStorage.ts
│ │ └── external/ # Externe Dienste
│ │ └── ...
│ ├── presentation/ # Präsentationsschicht
│ │ ├── components/ # UI Komponenten
│ │ │ ├── common/ # Allgemeine Komponenten
│ │ │ │ ├── Button/
│ │ │ │ ├── Card/
│ │ │ │ └── ...
│ │ │ ├── layout/ # Layout Komponenten
│ │ │ │ ├── Navbar/
│ │ │ │ ├── Sidebar/
│ │ │ │ └── ...
│ │ │ ├── timeTracker/ # Zeiterfassung Komponenten
│ │ │ │ ├── Timer/
│ │ │ │ ├── EntryForm/
│ │ │ │ └── ...
│ │ │ └── ...
│ │ ├── hooks/ # Custom React Hooks
│ │ │ ├── useAuth.ts
│ │ │ ├── useTimeTracking.ts
│ │ │ └── ...
│ │ ├── providers/ # Context Provider
│ │ │ ├── AuthProvider.tsx
│ │ │ ├── ThemeProvider.tsx
│ │ │ └── ...
│ │ └── pages/ # Page Components (für App Router)
│ │ ├── DashboardPage.tsx
│ │ ├── TimeTrackingPage.tsx
│ │ └── ...
│ ├── utils/ # Utilities
│ │ ├── fp/ # Funktionale Programmierung (FPTS)
│ │ │ ├── option.ts
│ │ │ ├── result.ts
│ │ │ └── ...
│ │ ├── date/ # Datumsfunktionen
│ │ │ └── dateUtils.ts
│ │ ├── formatting/ # Formattierung
│ │ │ ├── numberFormat.ts
│ │ │ └── ...
│ │ └── validation/ # Validierung
│ │ └── validators.ts
│ ├── types/ # TypeScript Typendefinitionen
│ │ ├── api.ts # API Response/Request Typen
│ │ ├── auth.ts # Auth Typen
│ │ └── ...
│ └── styles/ # Globale Styles
│ ├── globals.css
│ └── theme.ts
├── docu/ # Frontend-spezifische Dokumentation
│ ├── component_library.md
│ ├── state_management.md
│ └── ...
├── next.config.js
├── tailwind.config.js
├── tsconfig.json
├── package.json
└── README.md
```

40
docu/general_overview.md Normal file
View File

@ -0,0 +1,40 @@
# General Overview
## Technology Stack
### Backend
- Go with fp-go
- PostgreSQL with ORM (GORM or Bun)
- Swagger/OpenAPI
- JWT-based Authentication
### Frontend
- Next.js with fp-ts
- React and Tailwind CSS
- Responsive Webdesign
- Progressive Web App (PWA)
## Multi-Tenancy & Roles
- **Multi-Tenancy**: Isolation of data per company (tenant).
- **Roles**: Admin, Company-Admin, Manager, Auditor, User.
## Data Models
- **Company** (Tenant)
- **User** (with roles, hourly rate)
- **Customer**
- **Project** (with customer reference)
- **Activity** (billing rate)
- **Booking** (time, user, project, activity, optional description, billability 0-100%)
## Functional Requirements
### Version 1
- Master data management (customers, projects, activities, users)
- Time tracking with start/stop function and parameter inheritance from the last booking
- Clear dashboard with recent bookings and tracker
- Aggregated reports by period, project, customer, employee with PDF export
- Graphical dashboards (diagrams)
### Version 2
- Project management with sprints, tasks
- Kanban boards for task management
- Direct linking of tasks with time bookings

92
docu/llm_guidance.md Normal file
View File

@ -0,0 +1,92 @@
# LLM Guidance for the Time Tracking Project
This document provides guidance for Large Language Models (LLMs) working on the Time Tracking and Management System.
## File Locations
Here's a guide to finding information within the project:
**Documentation:**
- **General Project Overview:** `docu/general_overview.md`
- **Backend Architecture (Go):** `docu/backend_architecture.md`
- **Frontend Architecture (Next.js):** `docu/frontend_architecture.md`
- **Database Schema (PostgreSQL):** `docu/database_schema.md`
- **Deployment and DevOps:** `docu/deployment_devops.md`
- **Security and Privacy:** `docu/security_privacy.md`
- **Extensibility and Integrations:** `docu/extensibility_integrations.md`
- **This LLM Guidance Document:** `docu/llm_guidance.md`
- **Top Level Documentation Index:** `docu/README.md`
**Code (Conceptual - see architecture documents for details):**
- **Backend (Go):** (Refer to `docu/backend_architecture.md` for the conceptual structure. Actual code structure may differ.)
- **Conceptual File Locations:**
- `backend-go/internal/domain/entities/`: Core domain entities (User, Company, Project, etc.)
- `backend-go/internal/domain/repositories/`: Interfaces for data access.
- `backend-go/internal/domain/services/`: Business logic implementation.
- `backend-go/internal/infrastructure/persistence/`: Database interactions (GORM).
- `backend-go/internal/interfaces/http/handlers/`: API endpoint handlers.
- `backend-go/internal/interfaces/http/middleware/`: Authentication and tenant isolation middleware.
- **Code Examples:**
- `docu/code_examples/gorm_entities.go`: Example GORM entity definitions.
- `docu/code_examples/fpgo_repository.go`: Example FPGO repository interface.
- `docu/code_examples/fpgo_service.go`: Example FPGO service implementation.
- `docu/code_examples/api_handler.go`: Example API handler.
- **Frontend (Next.js):** (Refer to `docu/frontend_architecture.md` for the conceptual structure. Actual code structure may differ.)
- **Conceptual File Locations:**
- `frontend-nextjs/pages/`: Application pages.
- `frontend-nextjs/components/`: Reusable UI components.
- `frontend-nextjs/lib/`: API interaction and helper functions.
- `frontend-nextjs/types/`: TypeScript type definitions.
- **Code Examples:**
- `docu/code_examples/react_component.tsx`: Example React component.
**Important Note about Code Examples:** The files in `docu/code_examples/` are for illustrative purposes *only*. They do *not* represent a runnable project structure. Treat each file as an isolated example. The package declarations within these files (e.g., `package entities`, `package repositories`, `package main`) are conceptual and should be interpreted in the context of the described architecture, *not* as a literal directory structure. Do not attempt to run `go get` or similar commands based on these examples, as the necessary project structure and dependencies are not present.
## Rules and Guidelines
1. **Clean Architecture:** Adhere to Clean Architecture principles. Separate business logic (domain) from infrastructure concerns (database, UI).
2. **Domain-Driven Design (DDD):** Use DDD concepts to model the domain accurately.
3. **Multi-Tenancy:** Ensure all operations are scoped to the correct tenant (company). Use the `company_id` for data isolation.
4. **FPGO and FPTS:** Favor functional programming paradigms in both Go (FPGO) and TypeScript (FPTS).
5. **Modularity:** Keep code modular and well-organized.
6. **Error Handling:** Implement robust error handling and validation.
7. **Security:** Prioritize security. Use JWT for authentication and RBAC for authorization. Sanitize inputs to prevent injection attacks.
8. **Testing:** Write unit and integration tests for all new code.
9. **Documentation**: Keep the documentation up to date.
10. **Conceptual Architecture**: The architecture files are a *concept*, not a final implementation.
## Ideas to Follow
- **Small, Focused Modules:** Break down tasks into small, well-defined modules.
- **Descriptive Naming:** Use clear and descriptive names for variables, functions, and files.
- **Comments:** Add comments to explain complex logic.
- **Consistency:** Maintain consistent coding style and patterns.
- **Leverage Libraries:** Use existing libraries (FPGO, FPTS, GORM, Gin, Axios, etc.) where appropriate.
- **Ask for Clarification:** If unsure about any aspect of the project, use the `ask_followup_question` tool.
- **Visually Appealing Design:** (Especially for Claude models) Strive for a visually appealing and user-friendly interface. Consider using appropriate colors, layout, and components.
- **Prefer Replacements:** When making changes to existing files, favor the `replace_in_file` tool over `write_to_file` to minimize context usage and cost. Only use `write_to_file` for creating new files or making extensive, non-localized changes.
## Workflow for Limited Context
If you encounter context limitations or are instructed to work in smaller chunks, follow this workflow:
1. **Request a Summary:** If needed, ask for a brief summary of the current task and relevant file content.
2. **Plan in Chunks:** Divide the task into smaller, manageable sub-tasks.
3. **Focus on One Chunk:** Work on one sub-task at a time.
4. **Use `replace_in_file`:** Make targeted changes using `replace_in_file`.
5. **Iterate:** Repeat steps 3 and 4 for each sub-task.
6. **Provide Context Briefing:** When moving to a new chunk or file, provide a concise summary of the previous work and the current objective. This helps maintain context across multiple interactions.
## Code Organization and Style
- **Functional File Division:** Divide functionalities logically into separate files. This improves readability, maintainability, and helps manage context size.
- **Code Reusability:** Design code to be reusable and extensible. Anticipate future requirements and create components or functions that can be adapted for different purposes.
- **Common Sense:** Apply general good coding practices, even if they seem obvious. This includes things like:
- Using meaningful variable and function names.
- Adding comments to explain non-obvious logic.
- Handling edge cases and potential errors.
- Keeping functions and components concise and focused.
- Following consistent indentation and formatting.

6
docu/security_privacy.md Normal file
View File

@ -0,0 +1,6 @@
# Security and Data Privacy
- Tenant isolation
- TLS encryption and encrypted storage of sensitive data
- Audit logs (comprehensive logging)
- GDPR compliant (data export, right to be forgotten)