Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 92 additions & 73 deletions docs/DDD.puml
Original file line number Diff line number Diff line change
Expand Up @@ -187,105 +187,124 @@ rectangle "Kleff Hosting Domain" as Domain #line.dashed {
WorkspaceMember "*" --> "1" ID : userId
}

' ==================================
' Project Management BC
' ==================================
' Project Management BC (UPDATED PER SQL SCHEMA)
' ==================================
package "Project Management BC\n(Project Lifecycle & Collaboration)" #D1C4E9 {

AGGREGATE_ROOT(Project) #lightblue {
projectId: ProjectIdentifier
workspaceId: WorkspaceIdentifier
projectId: UUID
name: String
description: String
ownerId: ID
repositoryUrl: String
branch: String
dockerComposePath: String
environmentVariables: Map<String, String>
status: ProjectStatus
createdAt: DateTime
updatedAt: DateTime
description: Text
ownerId: String
environmentVariables: JSONB
projectStatus: String
createdDate: Timestamp
updatedDate: Timestamp
}

AGGREGATE(Invitation) #lightblue {
id: Integer
projectId: String
inviterId: String
inviteeEmail: String
role: RoleEnum
status: InvitationStatus
expiresAt: Timestamp
createdAt: Timestamp
updatedAt: Timestamp
}

ENTITY(ProjectCollaborator) #lightblue {
collaboratorId: CollaboratorIdentifier
projectId: ProjectIdentifier
userId: ID
role: CollaboratorRole
permissions: Set<ProjectPermission>
invitedBy: ID
invitedAt: DateTime
acceptedAt: DateTime
}

VALUE_OBJECT(ProjectIdentifier) #Bisque {
projectId: UUID
id: Integer
projectId: String
userId: String
role: RoleEnum
status: CollaboratorStatus
invitedBy: String
invitedAt: Timestamp
acceptedAt: Timestamp
expiresAt: Timestamp
lastAccessedAt: Timestamp
createdAt: Timestamp
updatedAt: Timestamp
}

ENTITY(FeatureFlag) #lightgrey {
id: Integer
flagKey: String
enabled: Boolean
description: Text
}

VALUE_OBJECT(CollaboratorIdentifier) #Bisque {
collaboratorId: UUID
ENTITY(AuthorizationAuditLog) #lightgrey {
id: BigInt
userId: String
projectId: String
action: String
resourceType: String
resourceId: String
permissionChecked: String
authorizationResult: AuthResultEnum
shadowMode: Boolean
ipAddress: String
userAgent: Text
requestId: String
changes: JSON
createdAt: Timestamp
}

ENUM(ProjectStatus) #SandyBrown {
ACTIVE,
PAUSED,
ARCHIVED,
DELETED
ENUM(RoleEnum) #SandyBrown {
OWNER
ADMIN
DEVELOPER
VIEWER
}

ENUM(CollaboratorRole) #SandyBrown {
OWNER,
ADMIN,
DEVELOPER,
VIEWER
ENUM(InvitationStatus) #SandyBrown {
PENDING
ACCEPTED
EXPIRED
}

ENUM(ProjectPermission) #SandyBrown {
READ_PROJECT,
WRITE_PROJECT,
DEPLOY,
MANAGE_ENV_VARS,
VIEW_LOGS,
VIEW_METRICS,
MANAGE_COLLABORATORS,
DELETE_PROJECT,
MANAGE_BILLING
ENUM(CollaboratorStatus) #SandyBrown {
PENDING
ACCEPTED
REFUSED
EXPIRED
}

VALUE_OBJECT(GitWebhook) #Bisque {
webhookUrl: String
secret: String
enabled: Boolean
ENUM(AuthResultEnum) #SandyBrown {
ALLOW
DENY
SHADOW_ALLOW
SHADOW_DENY
}

note right of Project
Invariant:
- Must have exactly one OWNER
- Repository URL must be valid Git URL
- Name must be unique per owner
- Docker Compose path must be valid
Invariants:
- Project name is NOT NULL
- Uses JSONB for environment variables
end note

note right of ProjectCollaborator
Invariant:
- OWNER has all permissions
- Cannot remove last OWNER
- User cannot be added twice to same project
- Permissions must match role constraints
Invariants:
- Unique constraint on (projectId, userId)
- Tracks last access for security auditing
end note

Project "1" o--> "1" ProjectIdentifier
Project "1" --> "*" ProjectCollaborator : collaborators
Project "1" --> "1" ProjectStatus : status
Project "1" --> "1" ID : ownerId
Project "1" --> "0..1" GitWebhook : webhook

ProjectCollaborator "*" --> "1" WorkspaceIdentifier : viaProjectWorkspace
ProjectCollaborator "1" o--> "1" CollaboratorIdentifier
ProjectCollaborator "*" --> "1" Project : belongsTo
ProjectCollaborator "1" --> "1" ID : userId
ProjectCollaborator "1" --> "1" CollaboratorRole : role
ProjectCollaborator "*" --> "*" ProjectPermission : permissions
Project "1" *-- "*" ProjectCollaborator : consists of
Project "1" *-- "*" Invitation : tracks
ProjectCollaborator --> RoleEnum
Invitation --> RoleEnum
Invitation --> InvitationStatus
ProjectCollaborator --> CollaboratorStatus
AuthorizationAuditLog --> AuthResultEnum

' Links to Identity
Project --> ID : ownerId
ProjectCollaborator --> ID : userId
Invitation --> ID : inviterId
}

' ==================================
Expand Down
31 changes: 24 additions & 7 deletions docs/Project/C4L3-Project.puml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ title Level 3 - Component Diagram for Project Management Service (Project Lifecy
' ==== External Containers / Systems (from C4L2) ====
Container(spa, "Kleff Dashboard (SPA)", "TypeScript, React", "Frontend for project owners & collaborators.")
Container(identity_svc, "Identity & Access Service", "Java/Go", "Manages users, roles, and tenants.")
ContainerDb(project_db, "project-db", "PostgreSQL", "Stores Projects, Collaborators, permissions, and webhook configuration.")
ContainerDb(project_db, "project-db", "PostgreSQL", "Stores Projects, Invitations, Collaborators, Feature Flags, and Audit Logs.")
System_Ext(email_service, "Email Service", "SMTP / Email API", "Sends collaboration invitations and notifications.")
System_Ext(git_provider, "Git Provider", "GitHub/GitLab", "Hosts repositories and webhooks.")

Expand All @@ -35,9 +35,18 @@ Container_Boundary(project_svc, "Project Management Service") {
Component(collab_domain, "ProjectCollaborator Entity", "Domain Model", "Represents membership of a user in a project with a role and fine-grained permissions.")


' ---- Infrastructure / Adapters ----
Component(project_repo, "ProjectRepository", "Repository Adapter", "Persists and retrieves Project aggregates and collaborator entities from project-db.")
' ---- Infrastructure / Adapters (Repositories) ----
Component(project_repo, "ProjectRepository", "Repository Adapter", "Persists and retrieves Project aggregates (projects table).")

Component(collab_repo, "CollaboratorRepository", "Repository Adapter", "Manages project membership and unique constraints (collaborators table).")

Component(invite_repo, "InvitationRepository", "Repository Adapter", "Handles the lifecycle of project invites (invitations table).")

Component(feature_flag_repo, "FeatureFlagRepository", "Repository Adapter", "Retrieves authorization toggle states (feature_flags table).")

Component(audit_repo, "AuthorizationAuditRepository", "Repository Adapter", "Records authorization decisions and changes (authorization_audit_logs table).")

' ---- Infrastructure / Adapters (Clients) ----
Component(identity_client, "IdentityServiceClient", "Integration Adapter", "Looks up users by ID/email and validates their existence in the Identity & Access BC.")

Component(email_adapter, "ProjectNotification", "Integration Adapter", "Sends collaboration invitations and project notifications via the application")
Expand All @@ -64,16 +73,24 @@ Rel(project_app_svc, project_repo, "Creates/updates Projects & webhook config",
Rel(project_app_svc, project_domain, "Applies domain logic", "Method calls")
Rel(project_app_svc, git_integration, "Configures webhooks on repository", "HTTPS/API")

Rel(collab_app_svc, project_repo, "Updates collaborator roles & permissions", "Repository API")
Rel(collab_app_svc, collab_repo, "Updates collaborator roles & permissions", "Repository API")
Rel(collab_app_svc, invite_repo, "Creates/Updates invitations", "Repository API")
Rel(collab_app_svc, collab_domain, "Applies collaboration domain rules", "Method calls")
Rel(collab_app_svc, identity_client, "Resolves invitee user IDs", "JSON/REST/HTTPS")
Rel(collab_app_svc, email_adapter, "Sends invitations to collaborators", "Send email")

Rel(project_permission_svc, project_repo, "Reads project collaborators & permissions", "Repository API")
Rel(project_permission_svc, collab_repo, "Reads project collaborators & permissions", "Repository API")
Rel(project_permission_svc, feature_flag_repo, "Checks shadow/enforce modes", "Repository API")
Rel(project_permission_svc, audit_repo, "Logs auth decisions", "Repository API")
Rel(project_permission_svc, collab_domain, "Evaluates project-level permissions", "Method calls")

' ==== Adapters -> External Systems ====
Rel(project_repo, project_db, "Reads/Writes Projects & Collaborators", "SQL")
Rel(project_repo, project_db, "Reads/Writes projects", "SQL")
Rel(collab_repo, project_db, "Reads/Writes collaborators", "SQL")
Rel(invite_repo, project_db, "Reads/Writes invitations", "SQL")
Rel(feature_flag_repo, project_db, "Reads feature_flags", "SQL")
Rel(audit_repo, project_db, "Writes authorization_audit_logs", "SQL")

Rel(identity_client, identity_svc, "Reads User info from Identity & Access BC", "JSON/REST/HTTPS")
Rel(git_integration, git_provider, "Configures webhooks & repo metadata", "HTTPS/Git API")

Expand Down Expand Up @@ -101,4 +118,4 @@ Rel(git_integration, git_provider, "Configures webhooks & repo metadata", "HTTPS
' - DELETE /api/projects/{projectId}/permissions/grants/{grantId}


@enduml
@enduml
1 change: 0 additions & 1 deletion docs/Project/ProjectManagementUseCase.puml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ Collab -- UC14
Dev -- UC15

' Internal relationships
UC10 ..> UC11 : <<includes>>
UC12 ..> UC13 : <<includes>>
UC14 ..> UC13 : <<includes>>

Expand Down
42 changes: 42 additions & 0 deletions docs/Project/UC10-DLCD.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
@startuml
title UC-01: Create Project - Design-Level Class Diagram (DLCD)

class Project {
- UUID id
- String name
- String repositoryUrl
- ProjectStatus status
+ validate()
+ updateSettings()
}

enum ProjectStatus {
CREATING
ACTIVE
ARCHIVED
}

interface ProjectRepository {
+ save(Project): Project
+ findByName(String): Project
}

class ProjectApplicationService {
+ createProject(DTO): Project
}

class ProjectApiController {
+ createProject(HttpRequest): HttpResponse
}

class GitIntegrationAdapter {
+ configureWebhooks(String): String
}

ProjectApiController --> ProjectApplicationService : uses
ProjectApplicationService --> ProjectRepository : uses
ProjectApplicationService --> GitIntegrationAdapter : uses
ProjectApplicationService ..> Project : manages
ProjectRepository ..> Project : persists

@enduml
43 changes: 43 additions & 0 deletions docs/Project/UC10-DLSD.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
@startuml
title UC-01: Create Project - Design-Level Sequence Diagram (DLSD)

actor "Project Owner" as Owner
participant "Kleff Dashboard (SPA)" as SPA
participant "Project API Controller" as Controller
participant "Project Application Service" as AppService
participant "Project Aggregate" as Domain
participant "ProjectRepository" as Repo
participant "GitIntegrationAdapter" as GitAdapter
database "project-db" as DB

Owner -> SPA: Clicks "Create Project"
SPA -> Controller: POST /api/projects (name, repoUrl)
activate Controller

Controller -> AppService: createProject(projectData)
activate AppService

AppService -> Domain: validate(projectData)
activate Domain
Domain --> AppService: valid
deactivate Domain

AppService -> GitAdapter: configureWebhooks(repoUrl)
activate GitAdapter
GitAdapter --> AppService: webhookConfigId
deactivate GitAdapter

AppService -> Repo: save(new Project())
activate Repo
Repo -> DB: INSERT INTO projects ...
DB --> Repo: Success
Repo --> AppService: projectEntity
deactivate Repo

AppService --> Controller: projectResponseDTO
deactivate AppService

Controller --> SPA: 201 Created (Project JSON)
deactivate Controller
SPA --> Owner: Displays Project Dashboard
@enduml
16 changes: 16 additions & 0 deletions docs/Project/UC10-SSD.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@startuml
title UC-01: Create Project - System Sequence Diagram (SSD)
skinparam ParticipantPadding 20
skinparam BoxPadding 10

actor "Project Owner" as Owner
participant "Kleff Hosting Platform" as System

Owner -> System: createProject(name, description, settings)
activate System
System -> System: Validate uniqueness of project id
System -> System: Link repository & setup webhooks
System --> Owner: Project Created Confirmation (Project ID)
deactivate System

@enduml
20 changes: 20 additions & 0 deletions docs/Project/UC10-STD.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@startuml
title UC-01: Create Project - State Transition Diagram (STD)

[*] --> Creating : User Submits Form
state Creating {
[*] --> ValidatingName
ValidatingName --> ConfiguringGit : Name Unique
ConfiguringGit --> Persisting : Webhook Configured
}

Creating --> Active : Persistence Successful
Creating --> Failed : Error (Name Conflict / Git Error)

Active --> Archived : Project Owner Deletes/Archives
Active --> Active : Settings Updated

Failed --> Creating : User Retries
Archived --> [*]

@enduml