diff --git a/backend/internal/domain/entities/activity.go b/backend/internal/domain/entities/activity.go index 3035183..9bfdf02 100644 --- a/backend/internal/domain/entities/activity.go +++ b/backend/internal/domain/entities/activity.go @@ -5,7 +5,7 @@ import ( ) type Activity struct { - ID ulid.ULID + EntityBase Name string BillingRate float64 } diff --git a/backend/internal/domain/entities/base.go b/backend/internal/domain/entities/base.go new file mode 100644 index 0000000..2f9a623 --- /dev/null +++ b/backend/internal/domain/entities/base.go @@ -0,0 +1,14 @@ +package entities + +import ( + "time" + + "github.com/oklog/ulid/v2" +) + +type EntityBase struct { + ID ulid.ULID + CreatedAt time.Time + UpdatedAt time.Time + LastEditorID ulid.ULID +} diff --git a/backend/internal/domain/entities/company.go b/backend/internal/domain/entities/company.go index e6fb88f..a6fdc77 100644 --- a/backend/internal/domain/entities/company.go +++ b/backend/internal/domain/entities/company.go @@ -3,7 +3,7 @@ package entities import "github.com/oklog/ulid/v2" type Company struct { - ID ulid.ULID + EntityBase Name string } diff --git a/backend/internal/domain/entities/timeentry.go b/backend/internal/domain/entities/timeentry.go index 7dbdda9..8dde54e 100644 --- a/backend/internal/domain/entities/timeentry.go +++ b/backend/internal/domain/entities/timeentry.go @@ -7,7 +7,7 @@ import ( ) type TimeEntry struct { - ID ulid.ULID + EntityBase UserID int ProjectID int ActivityID int diff --git a/backend/internal/domain/entities/user.go b/backend/internal/domain/entities/user.go index 7818183..08a0d13 100644 --- a/backend/internal/domain/entities/user.go +++ b/backend/internal/domain/entities/user.go @@ -3,7 +3,7 @@ package entities import "github.com/oklog/ulid/v2" type User struct { - ID ulid.ULID + EntityBase Username string Password string Role string diff --git a/backend/internal/interfaces/http/dto/activity_dto.go b/backend/internal/interfaces/http/dto/activity_dto.go index cdb24ff..c743991 100644 --- a/backend/internal/interfaces/http/dto/activity_dto.go +++ b/backend/internal/interfaces/http/dto/activity_dto.go @@ -1,13 +1,18 @@ package dto import ( + "time" + "github.com/oklog/ulid/v2" ) type ActivityDto struct { - ID ulid.ULID `json:"id"` - Name string `json:"name"` - BillingRate float64 `json:"billingRate"` + ID ulid.ULID `json:"id"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + LastEditorID ulid.ULID `json:"lastEditorID"` + Name string `json:"name"` + BillingRate float64 `json:"billingRate"` } type ActivityCreateDto struct { @@ -16,7 +21,10 @@ type ActivityCreateDto struct { } type ActivityUpdateDto struct { - ID ulid.ULID `json:"id"` - Name *string `json:"name"` - BillingRate *float64 `json:"billingRate"` + ID ulid.ULID `json:"id"` + CreatedAt *time.Time `json:"createdAt"` + UpdatedAt *time.Time `json:"updatedAt"` + LastEditorID *ulid.ULID `json:"lastEditorID"` + Name *string `json:"name"` + BillingRate *float64 `json:"billingRate"` } diff --git a/backend/internal/interfaces/http/dto/company_dto.go b/backend/internal/interfaces/http/dto/company_dto.go index a151ec2..28f9991 100644 --- a/backend/internal/interfaces/http/dto/company_dto.go +++ b/backend/internal/interfaces/http/dto/company_dto.go @@ -1,12 +1,17 @@ package dto import ( + "time" + "github.com/oklog/ulid/v2" ) type CompanyDto struct { - ID ulid.ULID `json:"id"` - Name string `json:"name"` + ID ulid.ULID `json:"id"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + LastEditorID ulid.ULID `json:"lastEditorID"` + Name string `json:"name"` } type CompanyCreateDto struct { @@ -14,6 +19,9 @@ type CompanyCreateDto struct { } type CompanyUpdateDto struct { - ID ulid.ULID `json:"id"` - Name *string `json:"name"` + ID ulid.ULID `json:"id"` + CreatedAt *time.Time `json:"createdAt"` + UpdatedAt *time.Time `json:"updatedAt"` + LastEditorID *ulid.ULID `json:"lastEditorID"` + Name *string `json:"name"` } diff --git a/backend/internal/interfaces/http/dto/customer_dto.go b/backend/internal/interfaces/http/dto/customer_dto.go index 2616586..958d907 100644 --- a/backend/internal/interfaces/http/dto/customer_dto.go +++ b/backend/internal/interfaces/http/dto/customer_dto.go @@ -1,13 +1,18 @@ package dto import ( + "time" + "github.com/oklog/ulid/v2" ) type CustomerDto struct { - ID ulid.ULID `json:"id"` - Name string `json:"name"` - CompanyID int `json:"companyId"` + ID ulid.ULID `json:"id"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + LastEditorID ulid.ULID `json:"lastEditorID"` + Name string `json:"name"` + CompanyID int `json:"companyId"` } type CustomerCreateDto struct { @@ -16,7 +21,10 @@ type CustomerCreateDto struct { } type CustomerUpdateDto struct { - ID ulid.ULID `json:"id"` - Name *string `json:"name"` - CompanyID *int `json:"companyId"` + ID ulid.ULID `json:"id"` + CreatedAt *time.Time `json:"createdAt"` + UpdatedAt *time.Time `json:"updatedAt"` + LastEditorID *ulid.ULID `json:"lastEditorID"` + Name *string `json:"name"` + CompanyID *int `json:"companyId"` } diff --git a/backend/internal/interfaces/http/dto/project_dto.go b/backend/internal/interfaces/http/dto/project_dto.go index c0b3692..30805a6 100644 --- a/backend/internal/interfaces/http/dto/project_dto.go +++ b/backend/internal/interfaces/http/dto/project_dto.go @@ -1,13 +1,18 @@ package dto import ( + "time" + "github.com/oklog/ulid/v2" ) type ProjectDto struct { - ID ulid.ULID `json:"id"` - Name string `json:"name"` - CustomerID int `json:"customerId"` + ID ulid.ULID `json:"id"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + LastEditorID ulid.ULID `json:"lastEditorID"` + Name string `json:"name"` + CustomerID int `json:"customerId"` } type ProjectCreateDto struct { @@ -16,7 +21,10 @@ type ProjectCreateDto struct { } type ProjectUpdateDto struct { - ID ulid.ULID `json:"id"` - Name *string `json:"name"` - CustomerID *int `json:"customerId"` + ID ulid.ULID `json:"id"` + CreatedAt *time.Time `json:"createdAt"` + UpdatedAt *time.Time `json:"updatedAt"` + LastEditorID *ulid.ULID `json:"lastEditorID"` + Name *string `json:"name"` + CustomerID *int `json:"customerId"` } diff --git a/backend/internal/interfaces/http/dto/timeentry_dto.go b/backend/internal/interfaces/http/dto/timeentry_dto.go index a182f7a..3d780e0 100644 --- a/backend/internal/interfaces/http/dto/timeentry_dto.go +++ b/backend/internal/interfaces/http/dto/timeentry_dto.go @@ -7,14 +7,17 @@ import ( ) type TimeEntryDto struct { - ID ulid.ULID `json:"id"` - UserID int `json:"userId"` - ProjectID int `json:"projectId"` - ActivityID int `json:"activityId"` - Start time.Time `json:"start"` - End time.Time `json:"end"` - Description string `json:"description"` - Billable int `json:"billable"` // Percentage (0-100) + ID ulid.ULID `json:"id"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + LastEditorID ulid.ULID `json:"lastEditorID"` + UserID int `json:"userId"` + ProjectID int `json:"projectId"` + ActivityID int `json:"activityId"` + Start time.Time `json:"start"` + End time.Time `json:"end"` + Description string `json:"description"` + Billable int `json:"billable"` // Percentage (0-100) } type TimeEntryCreateDto struct { @@ -28,12 +31,15 @@ type TimeEntryCreateDto struct { } type TimeEntryUpdateDto struct { - ID ulid.ULID `json:"id"` - UserID *int `json:"userId"` - ProjectID *int `json:"projectId"` - ActivityID *int `json:"activityId"` - Start *time.Time `json:"start"` - End *time.Time `json:"end"` - Description *string `json:"description"` - Billable *int `json:"billable"` // Percentage (0-100) + ID ulid.ULID `json:"id"` + CreatedAt *time.Time `json:"createdAt"` + UpdatedAt *time.Time `json:"updatedAt"` + LastEditorID *ulid.ULID `json:"lastEditorID"` + UserID *int `json:"userId"` + ProjectID *int `json:"projectId"` + ActivityID *int `json:"activityId"` + Start *time.Time `json:"start"` + End *time.Time `json:"end"` + Description *string `json:"description"` + Billable *int `json:"billable"` // Percentage (0-100) } diff --git a/backend/internal/interfaces/http/dto/user_dto.go b/backend/internal/interfaces/http/dto/user_dto.go index f73cca4..12b36c2 100644 --- a/backend/internal/interfaces/http/dto/user_dto.go +++ b/backend/internal/interfaces/http/dto/user_dto.go @@ -1,16 +1,21 @@ package dto import ( + "time" + "github.com/oklog/ulid/v2" ) type UserDto struct { - ID ulid.ULID `json:"id"` - Username string `json:"username"` - Password string `json:"password"` // Note: In a real application, you would NEVER send the password in a DTO. This is just for demonstration. - Role string `json:"role"` - CompanyID int `json:"companyId"` - HourlyRate float64 `json:"hourlyRate"` + ID ulid.ULID `json:"id"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + LastEditorID ulid.ULID `json:"lastEditorID"` + Username string `json:"username"` + Password string `json:"password"` // Note: In a real application, you would NEVER send the password in a DTO. This is just for demonstration. + Role string `json:"role"` + CompanyID int `json:"companyId"` + HourlyRate float64 `json:"hourlyRate"` } type UserCreateDto struct { @@ -22,10 +27,13 @@ type UserCreateDto struct { } type UserUpdateDto struct { - ID ulid.ULID `json:"id"` - Username *string `json:"username"` - Password *string `json:"password"` // Note: In a real application, you would NEVER send the password in a DTO. This is just for demonstration. - Role *string `json:"role"` - CompanyID *int `json:"companyId"` - HourlyRate *float64 `json:"hourlyRate"` + ID ulid.ULID `json:"id"` + CreatedAt *time.Time `json:"createdAt"` + UpdatedAt *time.Time `json:"updatedAt"` + LastEditorID *ulid.ULID `json:"lastEditorID"` + Username *string `json:"username"` + Password *string `json:"password"` // Note: In a real application, you would NEVER send the password in a DTO. This is just for demonstration. + Role *string `json:"role"` + CompanyID *int `json:"companyId"` + HourlyRate *float64 `json:"hourlyRate"` } diff --git a/docu/README.md b/docu/README.md index f242092..a0e392b 100644 --- a/docu/README.md +++ b/docu/README.md @@ -13,6 +13,8 @@ This document provides an overview of the Time Tracking and Management System. F - [Extensibility and Integrations](extensibility_integrations.md) - [LLM Guidance](llm_guidance.md) - [Roadmap](Roadmap.md) +- [Domain Types](domain_types.md) +- [DTOs](dtos.md) ## Code Examples - [GORM Entities](code_examples/gorm_entities.go) diff --git a/docu/database_schema.md b/docu/database_schema.md index 2d45884..995fd0d 100644 --- a/docu/database_schema.md +++ b/docu/database_schema.md @@ -13,6 +13,40 @@ CREATE TABLE companies ( updated_at TIMESTAMP NOT NULL DEFAULT NOW() ); +-- Go structs for creating and updating customers +-- type CustomerCreate struct { +-- Name string +-- CompanyID int +-- } + +-- type CustomerUpdate struct { +-- ID ulid.ULID +-- Name *string +-- CompanyID *int +-- } + +-- Go structs for creating and updating companies +-- type CompanyCreate struct { +-- Name string +-- } + +-- type CompanyUpdate struct { +-- ID ulid.ULID +-- Name *string +-- } + +-- Go structs for creating and updating activities +-- type ActivityCreate struct { +-- Name string +-- BillingRate float64 +-- } + +-- type ActivityUpdate struct { +-- ID ulid.ULID +-- Name *string +-- BillingRate *float64 +-- } + -- Users and Roles CREATE TABLE roles ( id SERIAL PRIMARY KEY, diff --git a/docu/domain_types.md b/docu/domain_types.md new file mode 100644 index 0000000..9a6aab2 --- /dev/null +++ b/docu/domain_types.md @@ -0,0 +1,27 @@ +# Domain Types + +This document describes the domain types used in the Time Tracker application. Domain types represent the core business concepts and are used throughout the application. + +## Activity + +The `Activity` type represents a specific activity that can be tracked, such as "Development", "Meeting", or "Bug Fixing". + +## Company + +The `Company` type represents a tenant in the multi-tenant application. Each company has its own set of users, customers, projects, and activities. + +## Customer + +The `Customer` type represents a customer of a company. + +## Project + +The `Project` type represents a project for a specific customer. + +## TimeEntry + +The `TimeEntry` type represents a time booking for a specific user, project, and activity. + +## User + +The `User` type represents a user of the application. Each user belongs to a company and has a specific role. diff --git a/docu/dtos.md b/docu/dtos.md new file mode 100644 index 0000000..a20622e --- /dev/null +++ b/docu/dtos.md @@ -0,0 +1,27 @@ +# Data Transfer Objects (DTOs) + +This document describes the Data Transfer Objects (DTOs) used in the Time Tracker application. DTOs are used to transfer data between the backend and frontend, and between different layers of the backend. + +## ActivityDto + +The `ActivityDto` type represents a specific activity that can be tracked, such as "Development", "Meeting", or "Bug Fixing". It is used to transfer activity data between the backend and frontend. + +## CompanyDto + +The `CompanyDto` type represents a tenant in the multi-tenant application. Each company has its own set of users, customers, projects, and activities. It is used to transfer company data between the backend and frontend. + +## CustomerDto + +The `CustomerDto` type represents a customer of a company. It is used to transfer customer data between the backend and frontend. + +## ProjectDto + +The `ProjectDto` type represents a project for a specific customer. It is used to transfer project data between the backend and frontend. + +## TimeEntryDto + +The `TimeEntryDto` type represents a time booking for a specific user, project, and activity. It is used to transfer time entry data between the backend and frontend. + +## UserDto + +The `UserDto` type represents a user of the application. Each user belongs to a company and has a specific role. It is used to transfer user data between the backend and frontend. diff --git a/frontend/src/types/base.ts b/frontend/src/types/base.ts new file mode 100644 index 0000000..5c3af01 --- /dev/null +++ b/frontend/src/types/base.ts @@ -0,0 +1,6 @@ +export type BaseEntity = { + createdAt: Date; + updatedAt: Date; + lastEditorID: string; +}; + diff --git a/frontend/src/types/dto.ts b/frontend/src/types/dto.ts index 3a02b9e..1140fd4 100644 --- a/frontend/src/types/dto.ts +++ b/frontend/src/types/dto.ts @@ -5,6 +5,9 @@ export interface ActivityDto { id: string; + createdAt: string; + updatedAt: string; + lastEditorID: string; name: string; billingRate: number /* float64 */; } @@ -14,6 +17,9 @@ export interface ActivityCreateDto { } export interface ActivityUpdateDto { id: string; + createdAt?: string; + updatedAt?: string; + lastEditorID?: string; name?: string; billingRate?: number /* float64 */; } @@ -23,6 +29,9 @@ export interface ActivityUpdateDto { export interface CompanyDto { id: string; + createdAt: string; + updatedAt: string; + lastEditorID: string; name: string; } export interface CompanyCreateDto { @@ -30,6 +39,9 @@ export interface CompanyCreateDto { } export interface CompanyUpdateDto { id: string; + createdAt?: string; + updatedAt?: string; + lastEditorID?: string; name?: string; } @@ -38,6 +50,9 @@ export interface CompanyUpdateDto { export interface CustomerDto { id: string; + createdAt: string; + updatedAt: string; + lastEditorID: string; name: string; companyId: number /* int */; } @@ -47,6 +62,9 @@ export interface CustomerCreateDto { } export interface CustomerUpdateDto { id: string; + createdAt?: string; + updatedAt?: string; + lastEditorID?: string; name?: string; companyId?: number /* int */; } @@ -56,6 +74,9 @@ export interface CustomerUpdateDto { export interface ProjectDto { id: string; + createdAt: string; + updatedAt: string; + lastEditorID: string; name: string; customerId: number /* int */; } @@ -65,6 +86,9 @@ export interface ProjectCreateDto { } export interface ProjectUpdateDto { id: string; + createdAt?: string; + updatedAt?: string; + lastEditorID?: string; name?: string; customerId?: number /* int */; } @@ -74,6 +98,9 @@ export interface ProjectUpdateDto { export interface TimeEntryDto { id: string; + createdAt: string; + updatedAt: string; + lastEditorID: string; userId: number /* int */; projectId: number /* int */; activityId: number /* int */; @@ -93,6 +120,9 @@ export interface TimeEntryCreateDto { } export interface TimeEntryUpdateDto { id: string; + createdAt?: string; + updatedAt?: string; + lastEditorID?: string; userId?: number /* int */; projectId?: number /* int */; activityId?: number /* int */; @@ -107,6 +137,9 @@ export interface TimeEntryUpdateDto { export interface UserDto { id: string; + createdAt: string; + updatedAt: string; + lastEditorID: string; username: string; password: string; // Note: In a real application, you would NEVER send the password in a DTO. This is just for demonstration. role: string; @@ -122,6 +155,9 @@ export interface UserCreateDto { } export interface UserUpdateDto { id: string; + createdAt?: string; + updatedAt?: string; + lastEditorID?: string; username?: string; password?: string; // Note: In a real application, you would NEVER send the password in a DTO. This is just for demonstration. role?: string; diff --git a/frontend/src/types/value-ids.ts b/frontend/src/types/value-ids.ts new file mode 100644 index 0000000..ddca1cf --- /dev/null +++ b/frontend/src/types/value-ids.ts @@ -0,0 +1,9 @@ +export type ValueId = string & { __valueId: T }; + +export type CustomerId = ValueId<"CustomerId">; +export type ProjectId = ValueId<"ProjectId">; +export type TimeEntryId = ValueId<"TimeEntryId">; +export type CompanyId = ValueId<"CompanyId">; +export type UserId = ValueId<"UserId">; +export type RoleId = ValueId<"RoleId">; +export type PermissionId = ValueId<"PermissionId">; \ No newline at end of file