docu: Add documentation for security, extensibility, deployment, and general overview
This commit is contained in:
parent
e31b93df93
commit
be6340332e
22
docu/README.md
Normal file
22
docu/README.md
Normal 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
153
docu/Roadmap.md
Normal 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.
|
144
docu/backend_architecture.md
Normal file
144
docu/backend_architecture.md
Normal 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
|
||||||
|
```
|
101
docu/code_examples/api_handler.go
Normal file
101
docu/code_examples/api_handler.go
Normal 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)
|
||||||
|
}
|
52
docu/code_examples/fpgo_repository.go
Normal file
52
docu/code_examples/fpgo_repository.go
Normal 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
|
||||||
|
}
|
99
docu/code_examples/fpgo_service.go
Normal file
99
docu/code_examples/fpgo_service.go
Normal 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)
|
||||||
|
}
|
104
docu/code_examples/gorm_entities.go
Normal file
104
docu/code_examples/gorm_entities.go
Normal 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)
|
||||||
|
}
|
136
docu/code_examples/react_component.tsx
Normal file
136
docu/code_examples/react_component.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
};
|
@ -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
160
docu/database_schema.md
Normal 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
17
docu/deployment_devops.md
Normal 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
|
389
docu/draft/concept/claude.md
Normal file
389
docu/draft/concept/claude.md
Normal 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);
|
||||||
|
```
|
6
docu/extensibility_integrations.md
Normal file
6
docu/extensibility_integrations.md
Normal 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
|
102
docu/frontend_architecture.md
Normal file
102
docu/frontend_architecture.md
Normal 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
40
docu/general_overview.md
Normal 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
92
docu/llm_guidance.md
Normal 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
6
docu/security_privacy.md
Normal 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)
|
Loading…
x
Reference in New Issue
Block a user