Go handlers, models, stores and migrations for all SDK modules. Updates developer portal navigation and BYOEH page. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
489 lines
21 KiB
Go
489 lines
21 KiB
Go
package vendor
|
|
|
|
import (
|
|
"encoding/json"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// ============================================================================
|
|
// Constants / Enums
|
|
// ============================================================================
|
|
|
|
// VendorRole represents the GDPR role of a vendor in data processing
|
|
type VendorRole string
|
|
|
|
const (
|
|
VendorRoleProcessor VendorRole = "PROCESSOR"
|
|
VendorRoleController VendorRole = "CONTROLLER"
|
|
VendorRoleJointController VendorRole = "JOINT_CONTROLLER"
|
|
VendorRoleSubProcessor VendorRole = "SUB_PROCESSOR"
|
|
VendorRoleThirdParty VendorRole = "THIRD_PARTY"
|
|
)
|
|
|
|
// VendorStatus represents the lifecycle status of a vendor
|
|
type VendorStatus string
|
|
|
|
const (
|
|
VendorStatusActive VendorStatus = "ACTIVE"
|
|
VendorStatusInactive VendorStatus = "INACTIVE"
|
|
VendorStatusPendingReview VendorStatus = "PENDING_REVIEW"
|
|
VendorStatusTerminated VendorStatus = "TERMINATED"
|
|
)
|
|
|
|
// DocumentType represents the type of a contract/compliance document
|
|
type DocumentType string
|
|
|
|
const (
|
|
DocumentTypeAVV DocumentType = "AVV"
|
|
DocumentTypeMSA DocumentType = "MSA"
|
|
DocumentTypeSLA DocumentType = "SLA"
|
|
DocumentTypeSCC DocumentType = "SCC"
|
|
DocumentTypeNDA DocumentType = "NDA"
|
|
DocumentTypeTOMAnnex DocumentType = "TOM_ANNEX"
|
|
DocumentTypeCertification DocumentType = "CERTIFICATION"
|
|
DocumentTypeSubProcessorList DocumentType = "SUB_PROCESSOR_LIST"
|
|
)
|
|
|
|
// FindingType represents the type of a compliance finding
|
|
type FindingType string
|
|
|
|
const (
|
|
FindingTypeOK FindingType = "OK"
|
|
FindingTypeGap FindingType = "GAP"
|
|
FindingTypeRisk FindingType = "RISK"
|
|
FindingTypeUnknown FindingType = "UNKNOWN"
|
|
)
|
|
|
|
// FindingStatus represents the resolution status of a finding
|
|
type FindingStatus string
|
|
|
|
const (
|
|
FindingStatusOpen FindingStatus = "OPEN"
|
|
FindingStatusInProgress FindingStatus = "IN_PROGRESS"
|
|
FindingStatusResolved FindingStatus = "RESOLVED"
|
|
FindingStatusAccepted FindingStatus = "ACCEPTED"
|
|
FindingStatusFalsePositive FindingStatus = "FALSE_POSITIVE"
|
|
)
|
|
|
|
// ControlStatus represents the assessment status of a control instance
|
|
type ControlStatus string
|
|
|
|
const (
|
|
ControlStatusPass ControlStatus = "PASS"
|
|
ControlStatusPartial ControlStatus = "PARTIAL"
|
|
ControlStatusFail ControlStatus = "FAIL"
|
|
ControlStatusNotApplicable ControlStatus = "NOT_APPLICABLE"
|
|
ControlStatusPlanned ControlStatus = "PLANNED"
|
|
)
|
|
|
|
// ============================================================================
|
|
// Main Entities
|
|
// ============================================================================
|
|
|
|
// Vendor represents a third-party vendor/service provider subject to GDPR compliance
|
|
type Vendor struct {
|
|
ID uuid.UUID `json:"id" db:"id"`
|
|
TenantID uuid.UUID `json:"tenant_id" db:"tenant_id"`
|
|
|
|
// Basic info
|
|
Name string `json:"name" db:"name"`
|
|
LegalForm string `json:"legal_form,omitempty" db:"legal_form"`
|
|
Country string `json:"country" db:"country"`
|
|
Address json.RawMessage `json:"address,omitempty" db:"address"`
|
|
Website string `json:"website,omitempty" db:"website"`
|
|
|
|
// Contact
|
|
ContactName string `json:"contact_name,omitempty" db:"contact_name"`
|
|
ContactEmail string `json:"contact_email,omitempty" db:"contact_email"`
|
|
ContactPhone string `json:"contact_phone,omitempty" db:"contact_phone"`
|
|
ContactDepartment string `json:"contact_department,omitempty" db:"contact_department"`
|
|
|
|
// GDPR role & service
|
|
Role VendorRole `json:"role" db:"role"`
|
|
ServiceCategory string `json:"service_category,omitempty" db:"service_category"`
|
|
ServiceDescription string `json:"service_description,omitempty" db:"service_description"`
|
|
DataAccessLevel string `json:"data_access_level,omitempty" db:"data_access_level"`
|
|
|
|
// Processing details (JSONB)
|
|
ProcessingLocations json.RawMessage `json:"processing_locations,omitempty" db:"processing_locations"`
|
|
Certifications json.RawMessage `json:"certifications,omitempty" db:"certifications"`
|
|
|
|
// Risk scoring
|
|
InherentRiskScore *int `json:"inherent_risk_score,omitempty" db:"inherent_risk_score"`
|
|
ResidualRiskScore *int `json:"residual_risk_score,omitempty" db:"residual_risk_score"`
|
|
ManualRiskAdjustment *int `json:"manual_risk_adjustment,omitempty" db:"manual_risk_adjustment"`
|
|
|
|
// Review schedule
|
|
ReviewFrequency string `json:"review_frequency,omitempty" db:"review_frequency"`
|
|
LastReviewDate *time.Time `json:"last_review_date,omitempty" db:"last_review_date"`
|
|
NextReviewDate *time.Time `json:"next_review_date,omitempty" db:"next_review_date"`
|
|
|
|
// Links to processing activities (JSONB)
|
|
ProcessingActivityIDs json.RawMessage `json:"processing_activity_ids,omitempty" db:"processing_activity_ids"`
|
|
|
|
// Status & template
|
|
Status VendorStatus `json:"status" db:"status"`
|
|
TemplateID *string `json:"template_id,omitempty" db:"template_id"`
|
|
|
|
// Audit
|
|
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
|
CreatedBy string `json:"created_by" db:"created_by"`
|
|
}
|
|
|
|
// Contract represents a contract/AVV document associated with a vendor
|
|
type Contract struct {
|
|
ID uuid.UUID `json:"id" db:"id"`
|
|
TenantID uuid.UUID `json:"tenant_id" db:"tenant_id"`
|
|
VendorID uuid.UUID `json:"vendor_id" db:"vendor_id"`
|
|
|
|
// File metadata
|
|
FileName string `json:"file_name" db:"file_name"`
|
|
OriginalName string `json:"original_name" db:"original_name"`
|
|
MimeType string `json:"mime_type" db:"mime_type"`
|
|
FileSize *int64 `json:"file_size,omitempty" db:"file_size"`
|
|
StoragePath string `json:"storage_path" db:"storage_path"`
|
|
|
|
// Document classification
|
|
DocumentType DocumentType `json:"document_type" db:"document_type"`
|
|
|
|
// Contract details
|
|
Parties json.RawMessage `json:"parties,omitempty" db:"parties"`
|
|
EffectiveDate *time.Time `json:"effective_date,omitempty" db:"effective_date"`
|
|
ExpirationDate *time.Time `json:"expiration_date,omitempty" db:"expiration_date"`
|
|
AutoRenewal bool `json:"auto_renewal" db:"auto_renewal"`
|
|
RenewalNoticePeriod string `json:"renewal_notice_period,omitempty" db:"renewal_notice_period"`
|
|
|
|
// Review
|
|
ReviewStatus string `json:"review_status" db:"review_status"`
|
|
ReviewCompletedAt *time.Time `json:"review_completed_at,omitempty" db:"review_completed_at"`
|
|
ComplianceScore *int `json:"compliance_score,omitempty" db:"compliance_score"`
|
|
|
|
// Versioning
|
|
Version string `json:"version" db:"version"`
|
|
PreviousVersionID *string `json:"previous_version_id,omitempty" db:"previous_version_id"`
|
|
|
|
// Extracted content
|
|
ExtractedText string `json:"extracted_text,omitempty" db:"extracted_text"`
|
|
PageCount *int `json:"page_count,omitempty" db:"page_count"`
|
|
|
|
// Audit
|
|
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
|
CreatedBy string `json:"created_by" db:"created_by"`
|
|
}
|
|
|
|
// Finding represents a compliance finding from a contract review
|
|
type Finding struct {
|
|
ID uuid.UUID `json:"id" db:"id"`
|
|
TenantID uuid.UUID `json:"tenant_id" db:"tenant_id"`
|
|
ContractID *string `json:"contract_id,omitempty" db:"contract_id"`
|
|
VendorID uuid.UUID `json:"vendor_id" db:"vendor_id"`
|
|
|
|
// Finding details
|
|
FindingType FindingType `json:"finding_type" db:"finding_type"`
|
|
Category string `json:"category" db:"category"`
|
|
Severity string `json:"severity" db:"severity"`
|
|
Title string `json:"title" db:"title"`
|
|
Description string `json:"description" db:"description"`
|
|
Recommendation string `json:"recommendation,omitempty" db:"recommendation"`
|
|
|
|
// Evidence (JSONB)
|
|
Citations json.RawMessage `json:"citations,omitempty" db:"citations"`
|
|
|
|
// Resolution workflow
|
|
Status FindingStatus `json:"status" db:"status"`
|
|
Assignee string `json:"assignee,omitempty" db:"assignee"`
|
|
DueDate *time.Time `json:"due_date,omitempty" db:"due_date"`
|
|
Resolution string `json:"resolution,omitempty" db:"resolution"`
|
|
ResolvedAt *time.Time `json:"resolved_at,omitempty" db:"resolved_at"`
|
|
ResolvedBy *string `json:"resolved_by,omitempty" db:"resolved_by"`
|
|
|
|
// Audit
|
|
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
|
}
|
|
|
|
// ControlInstance represents an applied control assessment for a specific vendor
|
|
type ControlInstance struct {
|
|
ID uuid.UUID `json:"id" db:"id"`
|
|
TenantID uuid.UUID `json:"tenant_id" db:"tenant_id"`
|
|
VendorID uuid.UUID `json:"vendor_id" db:"vendor_id"`
|
|
|
|
// Control reference
|
|
ControlID string `json:"control_id" db:"control_id"`
|
|
ControlDomain string `json:"control_domain" db:"control_domain"`
|
|
|
|
// Assessment
|
|
Status ControlStatus `json:"status" db:"status"`
|
|
EvidenceIDs json.RawMessage `json:"evidence_ids,omitempty" db:"evidence_ids"`
|
|
Notes string `json:"notes,omitempty" db:"notes"`
|
|
|
|
// Assessment tracking
|
|
LastAssessedAt *time.Time `json:"last_assessed_at,omitempty" db:"last_assessed_at"`
|
|
LastAssessedBy *string `json:"last_assessed_by,omitempty" db:"last_assessed_by"`
|
|
NextAssessmentDate *time.Time `json:"next_assessment_date,omitempty" db:"next_assessment_date"`
|
|
|
|
// Audit
|
|
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
|
}
|
|
|
|
// Template represents a pre-filled vendor compliance template
|
|
type Template struct {
|
|
ID uuid.UUID `json:"id" db:"id"`
|
|
TenantID *string `json:"tenant_id,omitempty" db:"tenant_id"`
|
|
|
|
// Template classification
|
|
TemplateType string `json:"template_type" db:"template_type"`
|
|
TemplateID string `json:"template_id" db:"template_id"`
|
|
Category string `json:"category" db:"category"`
|
|
|
|
// Localized names & descriptions
|
|
NameDE string `json:"name_de" db:"name_de"`
|
|
NameEN string `json:"name_en" db:"name_en"`
|
|
DescriptionDE string `json:"description_de" db:"description_de"`
|
|
DescriptionEN string `json:"description_en" db:"description_en"`
|
|
|
|
// Template content (JSONB)
|
|
TemplateData json.RawMessage `json:"template_data" db:"template_data"`
|
|
|
|
// Classification
|
|
Industry string `json:"industry,omitempty" db:"industry"`
|
|
Tags json.RawMessage `json:"tags,omitempty" db:"tags"`
|
|
|
|
// Flags
|
|
IsSystem bool `json:"is_system" db:"is_system"`
|
|
IsActive bool `json:"is_active" db:"is_active"`
|
|
|
|
// Usage tracking
|
|
UsageCount int `json:"usage_count" db:"usage_count"`
|
|
|
|
// Audit
|
|
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
|
}
|
|
|
|
// ============================================================================
|
|
// Statistics
|
|
// ============================================================================
|
|
|
|
// VendorStats contains aggregated vendor compliance statistics for a tenant
|
|
type VendorStats struct {
|
|
TotalVendors int `json:"total_vendors"`
|
|
ByStatus map[string]int `json:"by_status"`
|
|
ByRole map[string]int `json:"by_role"`
|
|
ByRiskLevel map[string]int `json:"by_risk_level"`
|
|
PendingReviews int `json:"pending_reviews"`
|
|
ExpiredContracts int `json:"expired_contracts"`
|
|
}
|
|
|
|
// ============================================================================
|
|
// API Request/Response Types
|
|
// ============================================================================
|
|
|
|
// -- Vendor -------------------------------------------------------------------
|
|
|
|
// CreateVendorRequest is the API request for creating a vendor
|
|
type CreateVendorRequest struct {
|
|
Name string `json:"name" binding:"required"`
|
|
LegalForm string `json:"legal_form,omitempty"`
|
|
Country string `json:"country" binding:"required"`
|
|
Address json.RawMessage `json:"address,omitempty"`
|
|
Website string `json:"website,omitempty"`
|
|
ContactName string `json:"contact_name,omitempty"`
|
|
ContactEmail string `json:"contact_email,omitempty"`
|
|
ContactPhone string `json:"contact_phone,omitempty"`
|
|
ContactDepartment string `json:"contact_department,omitempty"`
|
|
Role VendorRole `json:"role" binding:"required"`
|
|
ServiceCategory string `json:"service_category,omitempty"`
|
|
ServiceDescription string `json:"service_description,omitempty"`
|
|
DataAccessLevel string `json:"data_access_level,omitempty"`
|
|
ProcessingLocations json.RawMessage `json:"processing_locations,omitempty"`
|
|
Certifications json.RawMessage `json:"certifications,omitempty"`
|
|
ReviewFrequency string `json:"review_frequency,omitempty"`
|
|
ProcessingActivityIDs json.RawMessage `json:"processing_activity_ids,omitempty"`
|
|
TemplateID *string `json:"template_id,omitempty"`
|
|
}
|
|
|
|
// UpdateVendorRequest is the API request for updating a vendor
|
|
type UpdateVendorRequest struct {
|
|
Name *string `json:"name,omitempty"`
|
|
LegalForm *string `json:"legal_form,omitempty"`
|
|
Country *string `json:"country,omitempty"`
|
|
Address json.RawMessage `json:"address,omitempty"`
|
|
Website *string `json:"website,omitempty"`
|
|
ContactName *string `json:"contact_name,omitempty"`
|
|
ContactEmail *string `json:"contact_email,omitempty"`
|
|
ContactPhone *string `json:"contact_phone,omitempty"`
|
|
ContactDepartment *string `json:"contact_department,omitempty"`
|
|
Role *VendorRole `json:"role,omitempty"`
|
|
ServiceCategory *string `json:"service_category,omitempty"`
|
|
ServiceDescription *string `json:"service_description,omitempty"`
|
|
DataAccessLevel *string `json:"data_access_level,omitempty"`
|
|
ProcessingLocations json.RawMessage `json:"processing_locations,omitempty"`
|
|
Certifications json.RawMessage `json:"certifications,omitempty"`
|
|
InherentRiskScore *int `json:"inherent_risk_score,omitempty"`
|
|
ResidualRiskScore *int `json:"residual_risk_score,omitempty"`
|
|
ManualRiskAdjustment *int `json:"manual_risk_adjustment,omitempty"`
|
|
ReviewFrequency *string `json:"review_frequency,omitempty"`
|
|
LastReviewDate *time.Time `json:"last_review_date,omitempty"`
|
|
NextReviewDate *time.Time `json:"next_review_date,omitempty"`
|
|
ProcessingActivityIDs json.RawMessage `json:"processing_activity_ids,omitempty"`
|
|
Status *VendorStatus `json:"status,omitempty"`
|
|
TemplateID *string `json:"template_id,omitempty"`
|
|
}
|
|
|
|
// -- Contract -----------------------------------------------------------------
|
|
|
|
// CreateContractRequest is the API request for creating a contract
|
|
type CreateContractRequest struct {
|
|
VendorID uuid.UUID `json:"vendor_id" binding:"required"`
|
|
FileName string `json:"file_name" binding:"required"`
|
|
OriginalName string `json:"original_name" binding:"required"`
|
|
MimeType string `json:"mime_type" binding:"required"`
|
|
FileSize *int64 `json:"file_size,omitempty"`
|
|
StoragePath string `json:"storage_path" binding:"required"`
|
|
DocumentType DocumentType `json:"document_type" binding:"required"`
|
|
Parties json.RawMessage `json:"parties,omitempty"`
|
|
EffectiveDate *time.Time `json:"effective_date,omitempty"`
|
|
ExpirationDate *time.Time `json:"expiration_date,omitempty"`
|
|
AutoRenewal bool `json:"auto_renewal"`
|
|
RenewalNoticePeriod string `json:"renewal_notice_period,omitempty"`
|
|
Version string `json:"version,omitempty"`
|
|
PreviousVersionID *string `json:"previous_version_id,omitempty"`
|
|
}
|
|
|
|
// UpdateContractRequest is the API request for updating a contract
|
|
type UpdateContractRequest struct {
|
|
DocumentType *DocumentType `json:"document_type,omitempty"`
|
|
Parties json.RawMessage `json:"parties,omitempty"`
|
|
EffectiveDate *time.Time `json:"effective_date,omitempty"`
|
|
ExpirationDate *time.Time `json:"expiration_date,omitempty"`
|
|
AutoRenewal *bool `json:"auto_renewal,omitempty"`
|
|
RenewalNoticePeriod *string `json:"renewal_notice_period,omitempty"`
|
|
ReviewStatus *string `json:"review_status,omitempty"`
|
|
ReviewCompletedAt *time.Time `json:"review_completed_at,omitempty"`
|
|
ComplianceScore *int `json:"compliance_score,omitempty"`
|
|
Version *string `json:"version,omitempty"`
|
|
ExtractedText *string `json:"extracted_text,omitempty"`
|
|
PageCount *int `json:"page_count,omitempty"`
|
|
}
|
|
|
|
// -- Finding ------------------------------------------------------------------
|
|
|
|
// CreateFindingRequest is the API request for creating a compliance finding
|
|
type CreateFindingRequest struct {
|
|
ContractID *string `json:"contract_id,omitempty"`
|
|
VendorID uuid.UUID `json:"vendor_id" binding:"required"`
|
|
FindingType FindingType `json:"finding_type" binding:"required"`
|
|
Category string `json:"category" binding:"required"`
|
|
Severity string `json:"severity" binding:"required"`
|
|
Title string `json:"title" binding:"required"`
|
|
Description string `json:"description" binding:"required"`
|
|
Recommendation string `json:"recommendation,omitempty"`
|
|
Citations json.RawMessage `json:"citations,omitempty"`
|
|
Assignee string `json:"assignee,omitempty"`
|
|
DueDate *time.Time `json:"due_date,omitempty"`
|
|
}
|
|
|
|
// UpdateFindingRequest is the API request for updating a finding
|
|
type UpdateFindingRequest struct {
|
|
FindingType *FindingType `json:"finding_type,omitempty"`
|
|
Category *string `json:"category,omitempty"`
|
|
Severity *string `json:"severity,omitempty"`
|
|
Title *string `json:"title,omitempty"`
|
|
Description *string `json:"description,omitempty"`
|
|
Recommendation *string `json:"recommendation,omitempty"`
|
|
Citations json.RawMessage `json:"citations,omitempty"`
|
|
Status *FindingStatus `json:"status,omitempty"`
|
|
Assignee *string `json:"assignee,omitempty"`
|
|
DueDate *time.Time `json:"due_date,omitempty"`
|
|
Resolution *string `json:"resolution,omitempty"`
|
|
}
|
|
|
|
// ResolveFindingRequest is the API request for resolving a finding
|
|
type ResolveFindingRequest struct {
|
|
Resolution string `json:"resolution" binding:"required"`
|
|
}
|
|
|
|
// -- ControlInstance ----------------------------------------------------------
|
|
|
|
// UpdateControlInstanceRequest is the API request for updating a control instance
|
|
type UpdateControlInstanceRequest struct {
|
|
Status *ControlStatus `json:"status,omitempty"`
|
|
EvidenceIDs json.RawMessage `json:"evidence_ids,omitempty"`
|
|
Notes *string `json:"notes,omitempty"`
|
|
NextAssessmentDate *time.Time `json:"next_assessment_date,omitempty"`
|
|
}
|
|
|
|
// -- Template -----------------------------------------------------------------
|
|
|
|
// CreateTemplateRequest is the API request for creating a vendor template
|
|
type CreateTemplateRequest struct {
|
|
TemplateType string `json:"template_type" binding:"required"`
|
|
TemplateID string `json:"template_id" binding:"required"`
|
|
Category string `json:"category" binding:"required"`
|
|
NameDE string `json:"name_de" binding:"required"`
|
|
NameEN string `json:"name_en" binding:"required"`
|
|
DescriptionDE string `json:"description_de,omitempty"`
|
|
DescriptionEN string `json:"description_en,omitempty"`
|
|
TemplateData json.RawMessage `json:"template_data" binding:"required"`
|
|
Industry string `json:"industry,omitempty"`
|
|
Tags json.RawMessage `json:"tags,omitempty"`
|
|
IsSystem bool `json:"is_system"`
|
|
}
|
|
|
|
// ============================================================================
|
|
// List / Filter Types
|
|
// ============================================================================
|
|
|
|
// VendorFilters defines filters for listing vendors
|
|
type VendorFilters struct {
|
|
Status VendorStatus
|
|
Role VendorRole
|
|
Search string
|
|
Limit int
|
|
Offset int
|
|
}
|
|
|
|
// ContractFilters defines filters for listing contracts
|
|
type ContractFilters struct {
|
|
VendorID *uuid.UUID
|
|
DocumentType DocumentType
|
|
ReviewStatus string
|
|
Limit int
|
|
Offset int
|
|
}
|
|
|
|
// FindingFilters defines filters for listing findings
|
|
type FindingFilters struct {
|
|
VendorID *uuid.UUID
|
|
ContractID *string
|
|
Status FindingStatus
|
|
FindingType FindingType
|
|
Severity string
|
|
Limit int
|
|
Offset int
|
|
}
|
|
|
|
// VendorListResponse is the API response for listing vendors
|
|
type VendorListResponse struct {
|
|
Vendors []Vendor `json:"vendors"`
|
|
Total int `json:"total"`
|
|
}
|
|
|
|
// ContractListResponse is the API response for listing contracts
|
|
type ContractListResponse struct {
|
|
Contracts []Contract `json:"contracts"`
|
|
Total int `json:"total"`
|
|
}
|
|
|
|
// FindingListResponse is the API response for listing findings
|
|
type FindingListResponse struct {
|
|
Findings []Finding `json:"findings"`
|
|
Total int `json:"total"`
|
|
}
|