sojorn/go-backend/internal/models/group.go
2026-02-15 00:33:24 -06:00

106 lines
4.9 KiB
Go

package models
import (
"encoding/json"
"time"
"github.com/google/uuid"
)
type Group struct {
ID uuid.UUID `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Description string `json:"description" db:"description"`
Type string `json:"type" db:"type"` // 'geo', 'social', 'public_geo', 'private_capsule'
Privacy string `json:"privacy" db:"privacy"` // 'public' or 'private'
LocationCenter any `json:"location_center,omitempty" db:"location_center"`
Lat *float64 `json:"lat,omitempty"`
Long *float64 `json:"long,omitempty"`
RadiusMeters int `json:"radius_meters" db:"radius_meters"`
AvatarURL *string `json:"avatar_url" db:"avatar_url"`
CreatedBy *uuid.UUID `json:"created_by" db:"created_by"`
MemberCount int `json:"member_count" db:"member_count"`
IsActive bool `json:"is_active" db:"is_active"`
IsEncrypted bool `json:"is_encrypted" db:"is_encrypted"`
PublicKey *string `json:"public_key,omitempty" db:"public_key"`
Settings json.RawMessage `json:"settings,omitempty" db:"settings"`
InviteCode *string `json:"invite_code,omitempty" db:"invite_code"`
Category string `json:"category" db:"category"` // general, hobby, sports, professional, local_business, support, education
KeyVersion int `json:"key_version" db:"key_version"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
}
// IsCapsule returns true if this group uses E2EE
func (g *Group) IsCapsule() bool {
return g.Type == "private_capsule" && g.IsEncrypted
}
type GroupMember struct {
ID uuid.UUID `json:"id" db:"id"`
GroupID uuid.UUID `json:"group_id" db:"group_id"`
UserID uuid.UUID `json:"user_id" db:"user_id"`
Role string `json:"role" db:"role"` // owner, admin, moderator, member
EncryptedGroupKey *string `json:"encrypted_group_key,omitempty" db:"encrypted_group_key"`
KeyVersion int `json:"key_version" db:"key_version"`
JoinedAt time.Time `json:"joined_at" db:"joined_at"`
}
// CapsuleEntry holds E2EE content — the server NEVER decrypts this
type CapsuleEntry struct {
ID uuid.UUID `json:"id" db:"id"`
GroupID uuid.UUID `json:"group_id" db:"group_id"`
AuthorID uuid.UUID `json:"author_id" db:"author_id"`
IV string `json:"iv" db:"iv"`
EncryptedPayload string `json:"encrypted_payload" db:"encrypted_payload"`
DataType string `json:"data_type" db:"data_type"` // chat, forum_post, document, image
ReplyToID *uuid.UUID `json:"reply_to_id,omitempty" db:"reply_to_id"`
KeyVersion int `json:"key_version" db:"key_version"`
IsDeleted bool `json:"is_deleted" db:"is_deleted"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
// Joined fields (not encrypted — public metadata)
AuthorHandle string `json:"author_handle,omitempty" db:"author_handle"`
AuthorDisplayName string `json:"author_display_name,omitempty" db:"author_display_name"`
AuthorAvatarURL string `json:"author_avatar_url,omitempty" db:"author_avatar_url"`
}
// GroupWithDistance is returned by nearest-geo-group queries
type GroupWithDistance struct {
Group
DistanceMeters float64 `json:"distance_meters" db:"distance_meters"`
}
// GroupSettings defines what features are enabled for a group
type GroupSettings struct {
Chat bool `json:"chat"`
Forum bool `json:"forum"`
Files bool `json:"files"`
}
// CapsuleKey stores a per-user encrypted copy of a group's symmetric key.
// Security: Backend MUST only return rows WHERE user_id = authenticated user.
type CapsuleKey struct {
ID uuid.UUID `json:"id" db:"id"`
UserID uuid.UUID `json:"user_id" db:"user_id"`
GroupID uuid.UUID `json:"group_id" db:"group_id"`
EncryptedKeyBlob string `json:"encrypted_key_blob" db:"encrypted_key_blob"`
KeyVersion int `json:"key_version" db:"key_version"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
}
// CapsuleKeyBackup stores a PIN-encrypted backup of the user's private key.
// Zero-Knowledge: the server sees ONLY ciphertext — it cannot derive the PIN or key.
type CapsuleKeyBackup struct {
ID uuid.UUID `json:"id" db:"id"`
UserID uuid.UUID `json:"user_id" db:"user_id"`
Salt string `json:"salt" db:"salt"`
IV string `json:"iv" db:"iv"`
Payload string `json:"payload" db:"payload"`
PublicKey string `json:"pub" db:"public_key"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
}