feat: add core data model

This commit is contained in:
2026-07-18 15:52:54 +08:00
parent 619a8b4b3b
commit cccd0e6ce5
5 changed files with 233 additions and 0 deletions

10
backend/internal/db/db.go Normal file
View File

@@ -0,0 +1,10 @@
package db
import (
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
func Open(databaseURL string) (*gorm.DB, error) {
return gorm.Open(postgres.Open(databaseURL), &gorm.Config{})
}

View File

@@ -0,0 +1,138 @@
package domain
import (
"time"
"gorm.io/gorm"
)
type User struct {
ID uint `gorm:"primaryKey"`
Email string `gorm:"uniqueIndex;not null"`
DisplayName string `gorm:"not null"`
PasswordHash string `gorm:"not null"`
Role string `gorm:"not null;default:user"`
CreatedAt time.Time
UpdatedAt time.Time
}
type Project struct {
ID uint `gorm:"primaryKey"`
OwnerID uint `gorm:"index;not null"`
Name string `gorm:"not null"`
Description string
CreatedAt time.Time
UpdatedAt time.Time
}
type InboxItem struct {
ID uint `gorm:"primaryKey"`
ProjectID uint `gorm:"index;not null"`
CreatedBy uint `gorm:"index;not null"`
SourceType string `gorm:"not null"`
Title string
Body string
Status string `gorm:"not null;default:open"`
CreatedAt time.Time
UpdatedAt time.Time
}
type Task struct {
ID uint `gorm:"primaryKey"`
ProjectID uint `gorm:"index;not null"`
CreatedBy uint `gorm:"index;not null"`
AssigneeID *uint `gorm:"index"`
Title string `gorm:"not null"`
Description string
Status string `gorm:"not null;default:open"`
SortOrder int `gorm:"not null;default:0"`
DueAt *time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
type Note struct {
ID uint `gorm:"primaryKey"`
ProjectID uint `gorm:"index;not null"`
CreatedBy uint `gorm:"index;not null"`
Title string `gorm:"not null"`
Markdown string `gorm:"type:text"`
CreatedAt time.Time
UpdatedAt time.Time
}
type Source struct {
ID uint `gorm:"primaryKey"`
ProjectID uint `gorm:"index;not null"`
CreatedBy uint `gorm:"index;not null"`
Kind string `gorm:"not null"`
Title string `gorm:"not null"`
URL string
FilePath string
ContentText string `gorm:"type:text"`
CreatedAt time.Time
UpdatedAt time.Time
}
type AISession struct {
ID uint `gorm:"primaryKey"`
ProjectID uint `gorm:"index;not null"`
CreatedBy uint `gorm:"index;not null"`
Title string `gorm:"not null"`
Context string `gorm:"type:text"`
CreatedAt time.Time
UpdatedAt time.Time
}
type Tag struct {
ID uint `gorm:"primaryKey"`
ProjectID uint `gorm:"index;not null"`
Name string `gorm:"not null"`
CreatedAt time.Time
}
type ProjectEvent struct {
ID uint `gorm:"primaryKey"`
ProjectID uint `gorm:"index;not null"`
ActorID uint `gorm:"index;not null"`
EventType string `gorm:"not null"`
EntityType string `gorm:"not null"`
EntityID uint `gorm:"not null"`
Summary string `gorm:"not null"`
CreatedAt time.Time
}
type AIKey struct {
ID uint `gorm:"primaryKey"`
UserID uint `gorm:"uniqueIndex;not null"`
Provider string `gorm:"not null"`
EncryptedAPIKey string `gorm:"not null"`
CreatedAt time.Time
UpdatedAt time.Time
}
type AICallLog struct {
ID uint `gorm:"primaryKey"`
UserID uint `gorm:"index;not null"`
Provider string `gorm:"not null"`
UsedKeyType string `gorm:"not null"`
Action string `gorm:"not null"`
Status string `gorm:"not null"`
Error string
CreatedAt time.Time
}
type TaskShare struct {
ID uint `gorm:"primaryKey"`
TaskID uint `gorm:"index;not null"`
ObjectType string `gorm:"not null"`
ObjectID uint `gorm:"not null"`
CreatedAt time.Time
}
func AutoMigrate(database *gorm.DB) error {
return database.AutoMigrate(
&User{}, &Project{}, &InboxItem{}, &Task{}, &Note{}, &Source{},
&AISession{}, &Tag{}, &ProjectEvent{}, &AIKey{}, &AICallLog{}, &TaskShare{},
)
}

View File

@@ -0,0 +1,23 @@
package domain
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/glebarez/sqlite"
"gorm.io/gorm"
)
func TestAutoMigrateCreatesCoreTables(t *testing.T) {
database, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
require.NoError(t, err)
require.NoError(t, AutoMigrate(database))
for _, table := range []string{
"users", "projects", "inbox_items", "tasks", "notes", "sources",
"ai_sessions", "tags", "project_events", "ai_keys", "ai_call_logs", "task_shares",
} {
require.True(t, database.Migrator().HasTable(table), "missing table %s", table)
}
}