first commit

This commit is contained in:
domrichardson
2026-03-24 16:03:04 +00:00
commit df40cc57e1
80 changed files with 16766 additions and 0 deletions

View File

@@ -0,0 +1,51 @@
package entities
import (
"time"
"go.mongodb.org/mongo-driver/v2/bson"
)
// AuthProvider represents a configured OAuth/OIDC provider
type AuthProvider struct {
ID bson.ObjectID `bson:"_id,omitempty"`
Name string `bson:"name"`
Type string `bson:"type"` // "oidc", "oauth2"
ClientID string `bson:"client_id"`
ClientSecret string `bson:"client_secret"` // Encrypted in DB
AuthorizationURL string `bson:"authorization_url"`
TokenURL string `bson:"token_url"`
UserInfoURL string `bson:"userinfo_url"`
Scopes []string `bson:"scopes"`
IDTokenClaim string `bson:"id_token_claim,omitempty"`
IsActive bool `bson:"is_active"`
CreatedAt time.Time `bson:"created_at"`
UpdatedAt time.Time `bson:"updated_at"`
}
// LoginAttempt tracks login attempts for brute-force protection
type LoginAttempt struct {
ID bson.ObjectID `bson:"_id,omitempty"`
Email string `bson:"email"`
IPAddress string `bson:"ip_address"`
Success bool `bson:"success"`
Reason string `bson:"reason,omitempty"`
CreatedAt time.Time `bson:"created_at"`
ExpiresAt time.Time `bson:"expires_at"`
}
// FeatureFlags controls app-wide behavior toggles.
type FeatureFlags struct {
RegistrationEnabled bool `bson:"registration_enabled"`
ProviderLoginEnabled bool `bson:"provider_login_enabled"`
PublicSharingEnabled bool `bson:"public_sharing_enabled"`
}
// NewDefaultFeatureFlags returns safe defaults for a new deployment.
func NewDefaultFeatureFlags() *FeatureFlags {
return &FeatureFlags{
RegistrationEnabled: true,
ProviderLoginEnabled: true,
PublicSharingEnabled: true,
}
}

View File

@@ -0,0 +1,55 @@
package entities
import (
"time"
"go.mongodb.org/mongo-driver/v2/bson"
)
// Note represents a note within a space
type Note struct {
ID bson.ObjectID `bson:"_id,omitempty"`
SpaceID bson.ObjectID `bson:"space_id"`
CategoryID *bson.ObjectID `bson:"category_id,omitempty"`
Title string `bson:"title"`
Description string `bson:"description"`
Content string `bson:"content"`
PasswordHash string `bson:"password_hash,omitempty"`
Tags []string `bson:"tags"`
IsPinned bool `bson:"is_pinned"`
IsFavorite bool `bson:"is_favorite"`
IsPublic bool `bson:"is_public"`
IsPasswordProtected bool `bson:"is_password_protected"`
CreatedBy bson.ObjectID `bson:"created_by"`
UpdatedBy bson.ObjectID `bson:"updated_by"`
CreatedAt time.Time `bson:"created_at"`
UpdatedAt time.Time `bson:"updated_at"`
ViewedAt *time.Time `bson:"viewed_at,omitempty"`
}
// Category represents a folder/category within a space
type Category struct {
ID bson.ObjectID `bson:"_id,omitempty"`
SpaceID bson.ObjectID `bson:"space_id"`
Name string `bson:"name"`
Description string `bson:"description,omitempty"`
ParentID *bson.ObjectID `bson:"parent_id,omitempty"`
Icon string `bson:"icon,omitempty"`
Order int `bson:"order"`
CreatedBy bson.ObjectID `bson:"created_by"`
UpdatedBy bson.ObjectID `bson:"updated_by"`
CreatedAt time.Time `bson:"created_at"`
UpdatedAt time.Time `bson:"updated_at"`
}
// NoteRevision represents a historical version of a note
type NoteRevision struct {
ID bson.ObjectID `bson:"_id,omitempty"`
NoteID bson.ObjectID `bson:"note_id"`
SpaceID bson.ObjectID `bson:"space_id"`
Title string `bson:"title"`
Content string `bson:"content"`
ChangedBy bson.ObjectID `bson:"changed_by"`
CreatedAt time.Time `bson:"created_at"`
ChangeRef string `bson:"change_ref,omitempty"`
}

View File

@@ -0,0 +1,83 @@
package entities
import (
"regexp"
"strings"
"time"
"go.mongodb.org/mongo-driver/v2/bson"
)
var permissionTokenSanitizer = regexp.MustCompile(`[^a-z0-9_-]+`)
// PermissionGroup represents a named group of permissions.
type PermissionGroup struct {
ID bson.ObjectID `bson:"_id,omitempty"`
Name string `bson:"name"`
NameKey string `bson:"name_key"`
Description string `bson:"description,omitempty"`
Permissions []string `bson:"permissions"`
IsSystem bool `bson:"is_system"`
CreatedAt time.Time `bson:"created_at"`
UpdatedAt time.Time `bson:"updated_at"`
}
// NormalizePermission lowercases and trims a permission string.
func NormalizePermission(permission string) string {
return strings.ToLower(strings.TrimSpace(permission))
}
// SpacePermissionToken converts a space name to a dot-safe permission token.
func SpacePermissionToken(spaceName string) string {
normalized := strings.ToLower(strings.TrimSpace(spaceName))
normalized = strings.ReplaceAll(normalized, " ", "_")
normalized = permissionTokenSanitizer.ReplaceAllString(normalized, "_")
normalized = strings.Trim(normalized, "_")
if normalized == "" {
return "space"
}
return normalized
}
// PermissionMatches reports whether a wildcard pattern matches a concrete permission.
func PermissionMatches(pattern, permission string) bool {
pattern = NormalizePermission(pattern)
permission = NormalizePermission(permission)
if pattern == "" || permission == "" {
return false
}
if pattern == "*" || pattern == permission {
return true
}
if !strings.Contains(pattern, "*") {
return false
}
parts := strings.Split(pattern, "*")
remaining := permission
if parts[0] != "" {
if !strings.HasPrefix(remaining, parts[0]) {
return false
}
remaining = remaining[len(parts[0]):]
}
for i := 1; i < len(parts); i++ {
part := parts[i]
if part == "" {
continue
}
idx := strings.Index(remaining, part)
if idx < 0 {
return false
}
remaining = remaining[idx+len(part):]
}
if parts[len(parts)-1] != "" {
return strings.HasSuffix(permission, parts[len(parts)-1])
}
return true
}

View File

@@ -0,0 +1,41 @@
package entities
import (
"time"
"go.mongodb.org/mongo-driver/v2/bson"
)
// Space represents a top-level container for notes and categories
type Space struct {
ID bson.ObjectID `bson:"_id,omitempty"`
Name string `bson:"name"`
Description string `bson:"description,omitempty"`
Icon string `bson:"icon,omitempty"`
OwnerID bson.ObjectID `bson:"owner_id"`
IsPublic bool `bson:"is_public"`
CreatedAt time.Time `bson:"created_at"`
UpdatedAt time.Time `bson:"updated_at"`
}
// Membership represents a user's membership in a space
type Membership struct {
ID bson.ObjectID `bson:"_id,omitempty"`
UserID bson.ObjectID `bson:"user_id"`
SpaceID bson.ObjectID `bson:"space_id"`
JoinedAt time.Time `bson:"joined_at"`
InvitedBy bson.ObjectID `bson:"invited_by,omitempty"`
InvitedAt *time.Time `bson:"invited_at,omitempty"`
}
// SpaceInvitation represents an invitation to join a space
type SpaceInvitation struct {
ID bson.ObjectID `bson:"_id,omitempty"`
SpaceID bson.ObjectID `bson:"space_id"`
Email string `bson:"email"`
Token string `bson:"token"`
CreatedBy bson.ObjectID `bson:"created_by"`
CreatedAt time.Time `bson:"created_at"`
ExpiresAt time.Time `bson:"expires_at"`
AcceptedAt *time.Time `bson:"accepted_at,omitempty"`
}

View File

@@ -0,0 +1,51 @@
package entities
import (
"time"
"go.mongodb.org/mongo-driver/v2/bson"
)
// User represents a system user
type User struct {
ID bson.ObjectID `bson:"_id,omitempty"`
Email string `bson:"email"`
Username string `bson:"username"`
PasswordHash string `bson:"password_hash"`
FirstName string `bson:"first_name"`
LastName string `bson:"last_name"`
Avatar string `bson:"avatar,omitempty"`
GroupIDs []bson.ObjectID `bson:"group_ids,omitempty"`
Permissions []string `bson:"permissions,omitempty"`
IsActive bool `bson:"is_active"`
EmailVerified bool `bson:"email_verified"`
CreatedAt time.Time `bson:"created_at"`
UpdatedAt time.Time `bson:"updated_at"`
LastLoginAt *time.Time `bson:"last_login_at,omitempty"`
}
// UserProviderLink links external OAuth/OIDC providers to a user
type UserProviderLink struct {
ID bson.ObjectID `bson:"_id,omitempty"`
UserID bson.ObjectID `bson:"user_id"`
ProviderID bson.ObjectID `bson:"provider_id"`
ProviderUserID string `bson:"provider_user_id"`
Email string `bson:"email"`
ProfileData map[string]any `bson:"profile_data,omitempty"`
AccessToken string `bson:"access_token"` // Consider encrypting in production
RefreshToken string `bson:"refresh_token,omitempty"`
AccessTokenExp *time.Time `bson:"access_token_exp,omitempty"`
LinkedAt time.Time `bson:"linked_at"`
LastUsedAt *time.Time `bson:"last_used_at,omitempty"`
}
// AccountRecovery represents account recovery tokens
type AccountRecovery struct {
ID bson.ObjectID `bson:"_id,omitempty"`
UserID bson.ObjectID `bson:"user_id"`
Token string `bson:"token"`
Type string `bson:"type"` // "password_reset", "email_verification"
ExpiresAt time.Time `bson:"expires_at"`
UsedAt *time.Time `bson:"used_at,omitempty"`
CreatedAt time.Time `bson:"created_at"`
}