dealspace/lib/types.go

324 lines
11 KiB
Go

package lib
import "database/sql"
// Entry is the single core data type. One table to rule them all.
type Entry struct {
EntryID string `json:"entry_id"`
ProjectID string `json:"project_id"`
ParentID string `json:"parent_id"`
Type string `json:"type"`
Depth int `json:"depth"`
SortOrder int `json:"sort_order"`
SearchKey []byte `json:"-"` // blind index (HMAC-SHA256)
SearchKey2 []byte `json:"-"` // blind index (HMAC-SHA256)
Summary []byte `json:"-"` // packed: zstd + AES-256-GCM
Data []byte `json:"-"` // packed: zstd + AES-256-GCM
Stage string `json:"stage"`
// Workflow routing (plain, indexed)
AssigneeID string `json:"assignee_id"`
ReturnToID string `json:"return_to_id"`
OriginID string `json:"origin_id"`
// Optimistic locking
Version int `json:"version"`
// Soft delete
DeletedAt *int64 `json:"deleted_at,omitempty"`
DeletedBy *string `json:"deleted_by,omitempty"`
// Key rotation
KeyVersion int `json:"key_version"`
// Timestamps
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
CreatedBy string `json:"created_by"`
// Unpacked fields (not stored directly, populated by lib)
SummaryText string `json:"summary,omitempty"`
DataText string `json:"data_text,omitempty"`
}
// Entry types
const (
TypeProject = "project"
TypeWorkstream = "workstream"
TypeRequestList = "request_list"
TypeRequest = "request"
TypeAnswer = "answer"
TypeSection = "section"
TypeComment = "comment"
TypeOrganization = "organization"
TypeDealOrg = "deal_org"
)
// Stages
const (
StagePreDataroom = "pre_dataroom"
StageDataroom = "dataroom"
StageClosed = "closed"
)
// OrgData is the JSON structure packed into an organization entry's Data field.
type OrgData struct {
Name string `json:"name"`
Domains []string `json:"domains"` // required, e.g. ["kaseya.com","datto.com"]
Role string `json:"role"` // seller | buyer | ib | advisor
Website string `json:"website,omitempty"`
Description string `json:"description,omitempty"`
ContactName string `json:"contact_name,omitempty"`
ContactEmail string `json:"contact_email,omitempty"`
}
// DealOrgData is the JSON structure packed into a deal_org entry's Data field.
// A deal_org entry links an organization into a specific deal (project).
type DealOrgData struct {
OrgID string `json:"org_id"` // entry_id of the organization
Role string `json:"role"` // seller | buyer | ib | advisor
DomainLock bool `json:"domain_lock"` // if true, enforce domain check on invites
Permissions *DealOrgPerms `json:"permissions,omitempty"`
Members []DealOrgMember `json:"members,omitempty"`
}
// DealOrgPerms defines what an org can do in a deal.
type DealOrgPerms struct {
Download string `json:"download"` // "full" | "watermark" | "none"
Upload bool `json:"upload"`
AddRequestLists bool `json:"add_request_lists"`
EditRequestLists bool `json:"edit_request_lists"`
FolderAccess string `json:"folder_access"` // "all" | "assigned"
}
// DealOrgMember is a person associated with a deal org.
type DealOrgMember struct {
Name string `json:"name"`
Email string `json:"email"`
Title string `json:"title,omitempty"`
}
// User represents an account.
type User struct {
UserID string `json:"user_id"`
Email string `json:"email"`
Name string `json:"name"`
Password string `json:"-"` // bcrypt
OrgID string `json:"org_id"`
OrgName string `json:"org_name"`
MFASecret string `json:"-"`
Active bool `json:"active"`
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
}
// Access is an RBAC grant.
type Access struct {
ID string `json:"id"`
ProjectID string `json:"project_id"`
WorkstreamID string `json:"workstream_id,omitempty"`
UserID string `json:"user_id"`
Role string `json:"role"`
Ops string `json:"ops"`
CanGrant bool `json:"can_grant"`
GrantedBy string `json:"granted_by"`
GrantedAt int64 `json:"granted_at"`
RevokedAt *int64 `json:"revoked_at,omitempty"`
RevokedBy string `json:"revoked_by,omitempty"`
}
// Roles
const (
RoleSuperAdmin = "super_admin"
RoleIBAdmin = "ib_admin"
RoleIBMember = "ib_member"
RoleSellerAdmin = "seller_admin"
RoleSellerMember = "seller_member"
RoleBuyerAdmin = "buyer_admin"
RoleBuyerMember = "buyer_member"
RoleObserver = "observer"
)
// RoleHierarchy defines privilege levels. Higher = more privileged.
var RoleHierarchy = map[string]int{
RoleSuperAdmin: 200,
RoleIBAdmin: 100,
RoleIBMember: 80,
RoleSellerAdmin: 70,
RoleSellerMember: 50,
RoleBuyerAdmin: 40,
RoleBuyerMember: 30,
RoleObserver: 10,
}
// AnswerLink connects answers to requests (many-to-many).
type AnswerLink struct {
AnswerID string `json:"answer_id"`
RequestID string `json:"request_id"`
LinkedBy string `json:"linked_by"`
LinkedAt int64 `json:"linked_at"`
Confirmed bool `json:"confirmed"`
AIScore *float64 `json:"ai_score,omitempty"`
Status string `json:"status"`
ReviewedBy string `json:"reviewed_by,omitempty"`
ReviewedAt *int64 `json:"reviewed_at,omitempty"`
RejectReason string `json:"reject_reason,omitempty"`
}
// EntryEvent is a workflow thread item.
type EntryEvent struct {
ID string `json:"id"`
EntryID string `json:"entry_id"`
ActorID string `json:"actor_id"`
Channel string `json:"channel"`
Action []byte `json:"-"` // packed
Data []byte `json:"-"` // packed
Ts int64 `json:"ts"`
ActionText string `json:"action,omitempty"`
DataText string `json:"data_text,omitempty"`
}
// AuditEntry is a security audit log row.
type AuditEntry struct {
ID string `json:"id"`
ProjectID string `json:"project_id"`
ActorID string `json:"actor_id"`
Action []byte `json:"-"`
TargetID string `json:"target_id,omitempty"`
Details []byte `json:"-"`
IP string `json:"ip,omitempty"`
Ts int64 `json:"ts"`
ActionText string `json:"action,omitempty"`
DetailsText string `json:"details,omitempty"`
}
// Session tracks active user sessions.
type Session struct {
ID string `json:"id"`
UserID string `json:"user_id"`
Fingerprint string `json:"fingerprint"`
CreatedAt int64 `json:"created_at"`
ExpiresAt int64 `json:"expires_at"`
Revoked bool `json:"revoked"`
TestRole string `json:"test_role,omitempty"` // super-admin test impersonation
}
// Theme is a CSS custom properties bundle.
type Theme struct {
ID string `json:"id"`
Name string `json:"name"`
ProjectID string `json:"project_id,omitempty"`
Properties string `json:"properties"` // packed CSS vars as JSON
}
// EntryFilter is used by EntryRead to query entries.
type EntryFilter struct {
ProjectID string
ParentID *string
Type string
Stage string
AssigneeID string
SearchKey []byte // blind index to match
Limit int
Offset int
}
// DB wraps the database connection.
type DB struct {
Conn *sql.DB
}
// Challenge represents an email OTP challenge for passwordless login.
type Challenge struct {
ChallengeID string `json:"challenge_id"`
Email string `json:"email"`
Code string `json:"code"`
CreatedAt int64 `json:"created_at"`
ExpiresAt int64 `json:"expires_at"`
Used bool `json:"used"`
}
// Config holds application configuration.
type Config struct {
MasterKey []byte
DBPath string
StorePath string
Port string
Env string // "development" | "production"
JWTSecret []byte
Mailer *Mailer
BackdoorCode string // OTP backdoor for dev/testing
}
// RequestData is the JSON structure packed into a request entry's Data field.
// Represents a diligence request item imported from CSV/XLSX.
type RequestData struct {
Title string `json:"title"` // human-readable description
ItemNumber string `json:"item_number"` // e.g. "1.3", "A-12"
Section string `json:"section"` // e.g. "Financial", "Legal"
Description string `json:"description"` // full detail / context
Priority string `json:"priority"` // critical | high | medium | low
Status string `json:"status"` // open | in_process | partial | complete
AssigneeID string `json:"assignee_id,omitempty"`
AssigneeName string `json:"assignee_name,omitempty"`
ReviewerID string `json:"reviewer_id,omitempty"`
DueDate string `json:"due_date,omitempty"` // YYYY-MM-DD
CompletedAt string `json:"completed_at,omitempty"` // YYYY-MM-DD
BuyerComment string `json:"buyer_comment,omitempty"`
SellerComment string `json:"seller_comment,omitempty"`
Label string `json:"label,omitempty"`
Tags []string `json:"tags,omitempty"`
LinkedEntryIDs []string `json:"linked_entry_ids,omitempty"` // linked answer/file entries
}
// SectionData is the JSON structure packed into a section entry's Data field.
type SectionData struct {
Name string `json:"name"`
}
// RequestListData is the JSON structure packed into a request_list entry's Data field.
type RequestListData struct {
Name string `json:"name"`
OrgID string `json:"org_id,omitempty"` // PE firm org entry_id
VisibilityOrgID string `json:"visibility_org_id,omitempty"` // restrict visibility to this org (+ IB)
}
// WorkstreamData is the JSON structure packed into a workstream entry's Data field.
type WorkstreamData struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
}
// OAuthClient represents a registered OAuth 2.0 client application.
type OAuthClient struct {
ClientID string `json:"client_id"`
ClientName string `json:"client_name"`
RedirectURIs []string `json:"redirect_uris"`
CreatedAt int64 `json:"created_at"`
}
// OAuthCode represents an OAuth 2.0 authorization code.
type OAuthCode struct {
Code string `json:"code"`
ClientID string `json:"client_id"`
UserID string `json:"user_id"`
RedirectURI string `json:"redirect_uri"`
CodeChallenge string `json:"code_challenge"`
Scope string `json:"scope"`
ExpiresAt int64 `json:"expires_at"`
Used bool `json:"used"`
}
// OAuthToken represents an OAuth 2.0 access token.
type OAuthToken struct {
Token string `json:"token"`
ClientID string `json:"client_id"`
UserID string `json:"user_id"`
Scope string `json:"scope"`
ExpiresAt int64 `json:"expires_at"`
Revoked bool `json:"revoked"`
CreatedAt int64 `json:"created_at"`
}