session.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. package models
  2. import (
  3. "time"
  4. )
  5. // CelestiaSession represents a field record ("现场记录") session
  6. type CelestiaSession struct {
  7. ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"`
  8. UserID string `gorm:"type:uuid;not null;index;uniqueIndex:idx_session_user_client" json:"userId"`
  9. ClientID *string `gorm:"size:100;uniqueIndex:idx_session_user_client" json:"clientId,omitempty"`
  10. Title string `gorm:"size:200;not null" json:"title"`
  11. StartTime time.Time `gorm:"not null" json:"startTime"`
  12. EndTime *time.Time `json:"endTime,omitempty"`
  13. DurationMs int64 `gorm:"default:0" json:"durationMs"`
  14. LocalAudioPath string `gorm:"size:500" json:"localAudioPath,omitempty"`
  15. IsSynced bool `gorm:"default:true" json:"isSynced"`
  16. PhotoCount int `gorm:"default:0" json:"photoCount"`
  17. NoteCount int `gorm:"default:0" json:"noteCount"`
  18. Events []TimelineEvent `gorm:"foreignKey:SessionID;constraint:OnDelete:CASCADE" json:"events"`
  19. Assets []MediaAsset `gorm:"foreignKey:SessionID;constraint:OnDelete:CASCADE" json:"assets"`
  20. Revision int64 `gorm:"default:1" json:"revision"`
  21. DeletedAt *time.Time `gorm:"index" json:"deletedAt,omitempty"`
  22. CreatedAt time.Time `gorm:"autoCreateTime" json:"createdAt"`
  23. UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updatedAt"`
  24. }
  25. // SessionSyncIndexItem is the lightweight first phase of synchronization.
  26. // Events and asset descriptors are intentionally omitted; clients fetch the
  27. // full session only when UpdatedAt or Revision differs from local state.
  28. type SessionSyncIndexItem struct {
  29. ID string `json:"id"`
  30. ClientID *string `json:"clientId,omitempty"`
  31. Title string `json:"title"`
  32. StartTime time.Time `json:"startTime"`
  33. EndTime *time.Time `json:"endTime,omitempty"`
  34. DurationMs int64 `json:"durationMs"`
  35. PhotoCount int `json:"photoCount"`
  36. NoteCount int `json:"noteCount"`
  37. Revision int64 `json:"revision"`
  38. DeletedAt *time.Time `json:"deletedAt,omitempty"`
  39. UpdatedAt time.Time `json:"updatedAt"`
  40. }
  41. func (session CelestiaSession) SyncIndexItem() SessionSyncIndexItem {
  42. return SessionSyncIndexItem{
  43. ID: session.ID,
  44. ClientID: session.ClientID,
  45. Title: session.Title,
  46. StartTime: session.StartTime,
  47. EndTime: session.EndTime,
  48. DurationMs: session.DurationMs,
  49. PhotoCount: session.PhotoCount,
  50. NoteCount: session.NoteCount,
  51. Revision: session.Revision,
  52. DeletedAt: session.DeletedAt,
  53. UpdatedAt: session.UpdatedAt,
  54. }
  55. }
  56. // TimelineEvent represents an event (NOTE, PHOTO, MARKER, VOICE) within a session
  57. type TimelineEvent struct {
  58. ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"`
  59. SessionID string `gorm:"type:uuid;not null;index;uniqueIndex:idx_event_session_client" json:"sessionId"`
  60. ClientID *string `gorm:"size:100;uniqueIndex:idx_event_session_client" json:"clientId,omitempty"`
  61. RelativeTimeMs int64 `gorm:"not null" json:"relativeTimeMs"`
  62. EventType string `gorm:"size:20;not null" json:"eventType"` // PHOTO, NOTE, MARKER, VOICE
  63. TextContent string `gorm:"type:text" json:"textContent,omitempty"`
  64. LocalFilePath string `gorm:"size:500" json:"localFilePath,omitempty"`
  65. VoiceStartOffsetMs *int64 `json:"voiceStartOffsetMs,omitempty"`
  66. VoiceEndOffsetMs *int64 `json:"voiceEndOffsetMs,omitempty"`
  67. LocationName string `gorm:"size:200" json:"locationName,omitempty"`
  68. LocationAddress string `gorm:"size:500" json:"locationAddress,omitempty"`
  69. Latitude *float64 `json:"latitude,omitempty"`
  70. Longitude *float64 `json:"longitude,omitempty"`
  71. CreatedAt time.Time `gorm:"autoCreateTime" json:"createdAt"`
  72. }
  73. // MediaAsset is an uploaded audio or photo belonging to a session. StoragePath
  74. // is never serialized because it is an implementation detail of the server.
  75. type MediaAsset struct {
  76. ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"`
  77. SessionID string `gorm:"type:uuid;not null;index;uniqueIndex:idx_asset_session_client" json:"sessionId"`
  78. UserID string `gorm:"type:uuid;not null;index" json:"userId"`
  79. ClientID string `gorm:"size:120;not null;uniqueIndex:idx_asset_session_client" json:"clientId"`
  80. Kind string `gorm:"size:20;not null" json:"kind"`
  81. FileName string `gorm:"size:255;not null" json:"fileName"`
  82. MIMEType string `gorm:"size:120" json:"mimeType"`
  83. SizeBytes int64 `gorm:"not null" json:"sizeBytes"`
  84. SHA256 string `gorm:"size:64;not null;index" json:"sha256"`
  85. StoragePath string `gorm:"size:1000;not null" json:"-"`
  86. CreatedAt time.Time `gorm:"autoCreateTime" json:"createdAt"`
  87. }
  88. type CreateSessionRequest struct {
  89. ClientID string `json:"clientId" binding:"required"`
  90. Title string `json:"title" binding:"required"`
  91. StartTime time.Time `json:"startTime" binding:"required"`
  92. EndTime *time.Time `json:"endTime"`
  93. DurationMs int64 `json:"durationMs"`
  94. LocalAudioPath string `json:"localAudioPath"`
  95. Events []CreateEventSubSchema `json:"events"`
  96. BaseRevision *int64 `json:"baseRevision"`
  97. DeletedEventClientIds []string `json:"deletedEventClientIds"`
  98. }
  99. type CreateEventSubSchema struct {
  100. ClientID string `json:"clientId" binding:"required"`
  101. RelativeTimeMs int64 `json:"relativeTimeMs"`
  102. EventType string `json:"eventType" binding:"required"`
  103. TextContent string `json:"textContent"`
  104. LocalFilePath string `json:"localFilePath"`
  105. VoiceStartOffsetMs *int64 `json:"voiceStartOffsetMs"`
  106. VoiceEndOffsetMs *int64 `json:"voiceEndOffsetMs"`
  107. LocationName string `json:"locationName"`
  108. LocationAddress string `json:"locationAddress"`
  109. Latitude *float64 `json:"latitude"`
  110. Longitude *float64 `json:"longitude"`
  111. }
  112. type CreateEventRequest struct {
  113. ClientID string `json:"clientId" binding:"required"`
  114. RelativeTimeMs int64 `json:"relativeTimeMs"`
  115. EventType string `json:"eventType" binding:"required"`
  116. TextContent string `json:"textContent"`
  117. LocalFilePath string `json:"localFilePath"`
  118. VoiceStartOffsetMs *int64 `json:"voiceStartOffsetMs"`
  119. VoiceEndOffsetMs *int64 `json:"voiceEndOffsetMs"`
  120. LocationName string `json:"locationName"`
  121. LocationAddress string `json:"locationAddress"`
  122. Latitude *float64 `json:"latitude"`
  123. Longitude *float64 `json:"longitude"`
  124. }