[split-required] [guardrail-change] Enforce 500 LOC budget across all services
Install LOC guardrails (check-loc.sh, architecture.md, pre-commit hook) and split all 44 files exceeding 500 LOC into domain-focused modules: - consent-service (Go): models, handlers, services, database splits - backend-core (Python): security_api, rbac_api, pdf_service, auth splits - admin-core (TypeScript): 5 page.tsx + sidebar extractions - pitch-deck (TypeScript): 6 slides, 3 UI components, engine.ts splits - voice-service (Python): enhanced_task_orchestrator split Result: 0 violations, 36 exempted (pipeline, tests, pure-data files). Go build verified clean. No behavior changes — pure structural splits. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
237
consent-service/internal/models/consent.go
Normal file
237
consent-service/internal/models/consent.go
Normal file
@@ -0,0 +1,237 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// LegalDocument represents a type of legal document (e.g., Terms, Privacy Policy)
|
||||
type LegalDocument struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
Type string `json:"type" db:"type"` // 'terms', 'privacy', 'cookies', 'community'
|
||||
Name string `json:"name" db:"name"`
|
||||
Description *string `json:"description" db:"description"`
|
||||
IsMandatory bool `json:"is_mandatory" db:"is_mandatory"`
|
||||
IsActive bool `json:"is_active" db:"is_active"`
|
||||
SortOrder int `json:"sort_order" db:"sort_order"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
||||
}
|
||||
|
||||
// DocumentVersion represents a specific version of a legal document
|
||||
type DocumentVersion struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
DocumentID uuid.UUID `json:"document_id" db:"document_id"`
|
||||
Version string `json:"version" db:"version"` // Semver: 1.0.0, 1.1.0
|
||||
Language string `json:"language" db:"language"` // ISO 639-1: de, en
|
||||
Title string `json:"title" db:"title"`
|
||||
Content string `json:"content" db:"content"` // HTML or Markdown
|
||||
Summary *string `json:"summary" db:"summary"` // Summary of changes
|
||||
Status string `json:"status" db:"status"` // 'draft', 'review', 'approved', 'scheduled', 'published', 'archived'
|
||||
PublishedAt *time.Time `json:"published_at" db:"published_at"`
|
||||
ScheduledPublishAt *time.Time `json:"scheduled_publish_at" db:"scheduled_publish_at"`
|
||||
CreatedBy *uuid.UUID `json:"created_by" db:"created_by"`
|
||||
ApprovedBy *uuid.UUID `json:"approved_by" db:"approved_by"`
|
||||
ApprovedAt *time.Time `json:"approved_at" db:"approved_at"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
||||
}
|
||||
|
||||
// UserConsent represents a user's consent to a document version
|
||||
type UserConsent struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
UserID uuid.UUID `json:"user_id" db:"user_id"`
|
||||
DocumentVersionID uuid.UUID `json:"document_version_id" db:"document_version_id"`
|
||||
Consented bool `json:"consented" db:"consented"`
|
||||
IPAddress *string `json:"ip_address" db:"ip_address"`
|
||||
UserAgent *string `json:"user_agent" db:"user_agent"`
|
||||
ConsentedAt time.Time `json:"consented_at" db:"consented_at"`
|
||||
WithdrawnAt *time.Time `json:"withdrawn_at" db:"withdrawn_at"`
|
||||
}
|
||||
|
||||
// AuditLog represents an audit trail entry for GDPR compliance
|
||||
type AuditLog struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
UserID *uuid.UUID `json:"user_id" db:"user_id"`
|
||||
Action string `json:"action" db:"action"` // 'consent_given', 'consent_withdrawn', 'data_export', 'data_delete'
|
||||
EntityType *string `json:"entity_type" db:"entity_type"` // 'document', 'cookie_category'
|
||||
EntityID *uuid.UUID `json:"entity_id" db:"entity_id"`
|
||||
Details *string `json:"details" db:"details"` // JSON string
|
||||
IPAddress *string `json:"ip_address" db:"ip_address"`
|
||||
UserAgent *string `json:"user_agent" db:"user_agent"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
}
|
||||
|
||||
// DataExportRequest represents a user's request to export their data
|
||||
type DataExportRequest struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
UserID uuid.UUID `json:"user_id" db:"user_id"`
|
||||
Status string `json:"status" db:"status"` // 'pending', 'processing', 'completed', 'failed'
|
||||
DownloadURL *string `json:"download_url" db:"download_url"`
|
||||
ExpiresAt *time.Time `json:"expires_at" db:"expires_at"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
CompletedAt *time.Time `json:"completed_at" db:"completed_at"`
|
||||
}
|
||||
|
||||
// DataDeletionRequest represents a user's request to delete their data
|
||||
type DataDeletionRequest struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
UserID uuid.UUID `json:"user_id" db:"user_id"`
|
||||
Status string `json:"status" db:"status"` // 'pending', 'processing', 'completed', 'failed'
|
||||
Reason *string `json:"reason" db:"reason"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
ProcessedAt *time.Time `json:"processed_at" db:"processed_at"`
|
||||
ProcessedBy *uuid.UUID `json:"processed_by" db:"processed_by"`
|
||||
}
|
||||
|
||||
// VersionApproval tracks the approval workflow
|
||||
type VersionApproval struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
VersionID uuid.UUID `json:"version_id" db:"version_id"`
|
||||
ApproverID uuid.UUID `json:"approver_id" db:"approver_id"`
|
||||
Action string `json:"action" db:"action"` // 'submitted_for_review', 'approved', 'rejected', 'published'
|
||||
Comment *string `json:"comment,omitempty" db:"comment"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
}
|
||||
|
||||
// ConsentDeadline tracks consent deadlines per user
|
||||
type ConsentDeadline struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
UserID uuid.UUID `json:"user_id" db:"user_id"`
|
||||
DocumentVersionID uuid.UUID `json:"document_version_id" db:"document_version_id"`
|
||||
DeadlineAt time.Time `json:"deadline_at" db:"deadline_at"`
|
||||
ReminderCount int `json:"reminder_count" db:"reminder_count"`
|
||||
LastReminderAt *time.Time `json:"last_reminder_at,omitempty" db:"last_reminder_at"`
|
||||
ConsentGivenAt *time.Time `json:"consent_given_at,omitempty" db:"consent_given_at"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
}
|
||||
|
||||
// AccountSuspension tracks account suspensions
|
||||
type AccountSuspension struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
UserID uuid.UUID `json:"user_id" db:"user_id"`
|
||||
Reason string `json:"reason" db:"reason"` // 'consent_deadline_exceeded'
|
||||
Details *string `json:"details,omitempty" db:"details"` // JSON
|
||||
SuspendedAt time.Time `json:"suspended_at" db:"suspended_at"`
|
||||
LiftedAt *time.Time `json:"lifted_at,omitempty" db:"lifted_at"`
|
||||
LiftedReason *string `json:"lifted_reason,omitempty" db:"lifted_reason"`
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Consent DTOs
|
||||
// ========================================
|
||||
|
||||
// CreateConsentRequest is the request body for creating a consent
|
||||
type CreateConsentRequest struct {
|
||||
DocumentType string `json:"document_type" binding:"required"`
|
||||
VersionID string `json:"version_id" binding:"required"`
|
||||
Consented bool `json:"consented"`
|
||||
}
|
||||
|
||||
// ConsentCheckResponse is the response for checking consent status
|
||||
type ConsentCheckResponse struct {
|
||||
HasConsent bool `json:"has_consent"`
|
||||
CurrentVersionID *string `json:"current_version_id,omitempty"`
|
||||
ConsentedVersion *string `json:"consented_version,omitempty"`
|
||||
NeedsUpdate bool `json:"needs_update"`
|
||||
ConsentedAt *time.Time `json:"consented_at,omitempty"`
|
||||
}
|
||||
|
||||
// DocumentWithVersion combines document info with its latest published version
|
||||
type DocumentWithVersion struct {
|
||||
Document LegalDocument `json:"document"`
|
||||
LatestVersion *DocumentVersion `json:"latest_version,omitempty"`
|
||||
}
|
||||
|
||||
// ConsentHistory represents a user's consent history for a document
|
||||
type ConsentHistory struct {
|
||||
Document LegalDocument `json:"document"`
|
||||
Version DocumentVersion `json:"version"`
|
||||
Consent UserConsent `json:"consent"`
|
||||
}
|
||||
|
||||
// ConsentStats represents statistics about consents
|
||||
type ConsentStats struct {
|
||||
TotalUsers int `json:"total_users"`
|
||||
ConsentedUsers int `json:"consented_users"`
|
||||
ConsentRate float64 `json:"consent_rate"`
|
||||
RecentConsents int `json:"recent_consents"` // Last 7 days
|
||||
RecentWithdrawals int `json:"recent_withdrawals"`
|
||||
}
|
||||
|
||||
// MyDataResponse represents all data we have about a user
|
||||
type MyDataResponse struct {
|
||||
User User `json:"user"`
|
||||
Consents []ConsentHistory `json:"consents"`
|
||||
CookieConsents []CookieConsent `json:"cookie_consents"`
|
||||
AuditLog []AuditLog `json:"audit_log"`
|
||||
ExportedAt time.Time `json:"exported_at"`
|
||||
}
|
||||
|
||||
// CreateDocumentRequest is the request body for creating a document
|
||||
type CreateDocumentRequest struct {
|
||||
Type string `json:"type" binding:"required"`
|
||||
Name string `json:"name" binding:"required"`
|
||||
Description *string `json:"description"`
|
||||
IsMandatory bool `json:"is_mandatory"`
|
||||
}
|
||||
|
||||
// CreateVersionRequest is the request body for creating a document version
|
||||
type CreateVersionRequest struct {
|
||||
DocumentID string `json:"document_id" binding:"required"`
|
||||
Version string `json:"version" binding:"required"`
|
||||
Language string `json:"language" binding:"required"`
|
||||
Title string `json:"title" binding:"required"`
|
||||
Content string `json:"content" binding:"required"`
|
||||
Summary *string `json:"summary"`
|
||||
}
|
||||
|
||||
// UpdateVersionRequest is the request body for updating a version
|
||||
type UpdateVersionRequest struct {
|
||||
Title *string `json:"title"`
|
||||
Content *string `json:"content"`
|
||||
Summary *string `json:"summary"`
|
||||
Status *string `json:"status"`
|
||||
}
|
||||
|
||||
// SubmitForReviewRequest for submitting a version for review
|
||||
type SubmitForReviewRequest struct {
|
||||
Comment *string `json:"comment"`
|
||||
}
|
||||
|
||||
// ApproveVersionRequest for approving a version (DSB)
|
||||
type ApproveVersionRequest struct {
|
||||
Comment *string `json:"comment"`
|
||||
ScheduledPublishAt *string `json:"scheduled_publish_at"` // ISO 8601 datetime for scheduled publishing
|
||||
}
|
||||
|
||||
// RejectVersionRequest for rejecting a version
|
||||
type RejectVersionRequest struct {
|
||||
Comment string `json:"comment" binding:"required"`
|
||||
}
|
||||
|
||||
// VersionCompareResponse for comparing versions
|
||||
type VersionCompareResponse struct {
|
||||
Published *DocumentVersion `json:"published,omitempty"`
|
||||
Draft *DocumentVersion `json:"draft"`
|
||||
Diff *string `json:"diff,omitempty"`
|
||||
Approvals []VersionApproval `json:"approvals"`
|
||||
}
|
||||
|
||||
// PendingConsentResponse for pending consents with deadline info
|
||||
type PendingConsentResponse struct {
|
||||
Document LegalDocument `json:"document"`
|
||||
Version DocumentVersion `json:"version"`
|
||||
DeadlineAt time.Time `json:"deadline_at"`
|
||||
DaysLeft int `json:"days_left"`
|
||||
IsOverdue bool `json:"is_overdue"`
|
||||
}
|
||||
|
||||
// AccountStatusResponse for account status check
|
||||
type AccountStatusResponse struct {
|
||||
Status string `json:"status"` // 'active', 'suspended'
|
||||
PendingConsents []PendingConsentResponse `json:"pending_consents,omitempty"`
|
||||
SuspensionReason *string `json:"suspension_reason,omitempty"`
|
||||
CanAccess bool `json:"can_access"`
|
||||
}
|
||||
Reference in New Issue
Block a user