diff --git a/internal/httpapi/handlers_projects.go b/internal/httpapi/handlers_projects.go index f0bb186..5c93cbf 100644 --- a/internal/httpapi/handlers_projects.go +++ b/internal/httpapi/handlers_projects.go @@ -6,6 +6,7 @@ import ( "fmt" "net/http" "net/url" + "sort" "strings" "time" @@ -569,6 +570,8 @@ type mailItem struct { models.ProjectMailMsg Note string `json:"note"` // 공동 메모 본문 NoteEditedBy string `json:"noteEditedBy"` // 메모 마지막 수정자 + ThreadIndex int `json:"threadIndex"` // 스레드 내 순번(1=원문) + ThreadCount int `json:"threadCount"` // 스레드 총 메일 수 } // handleListProjectMails returns the stored client-domain mail for the project, @@ -623,6 +626,25 @@ func (s *Server) handleListProjectMails(w http.ResponseWriter, r *http.Request) notes[n.MessageID] = n } me := s.email(r) + // 스레드 내 순번 계산(저장된 전체 메일 기준, ts 오름차순). 1=원문. + type tpos struct{ idx, cnt int } + byThread := map[string][]models.ProjectMailMsg{} + for _, row := range rows { + byThread[row.ThreadID] = append(byThread[row.ThreadID], row) + } + pos := map[string]tpos{} + for tid, group := range byThread { + if tid == "" { + for _, g := range group { + pos[g.MessageID] = tpos{1, 1} + } + continue + } + sort.Slice(group, func(i, j int) bool { return group[i].TS < group[j].TS }) + for i, g := range group { + pos[g.MessageID] = tpos{i + 1, len(group)} + } + } // 가시성: 단일 메일 기준 — 그 메일의 from/to/cc에 내가 있으면 보인다(답장도 각각 개별 판정). items := make([]mailItem, 0, len(rows)) for _, row := range rows { @@ -630,7 +652,7 @@ func (s *Server) handleListProjectMails(w http.ResponseWriter, r *http.Request) if !m.Involves(me) { continue } - it := mailItem{ProjectMailMsg: row} + it := mailItem{ProjectMailMsg: row, ThreadIndex: pos[row.MessageID].idx, ThreadCount: pos[row.MessageID].cnt} if n, ok := notes[row.MessageID]; ok { it.Note = n.Body it.NoteEditedBy = n.LastEditedBy diff --git a/internal/mailsync/mailsync.go b/internal/mailsync/mailsync.go index f3a7d93..df857b2 100644 --- a/internal/mailsync/mailsync.go +++ b/internal/mailsync/mailsync.go @@ -364,11 +364,12 @@ func (s *Service) GetFull(ctx context.Context, mailbox, rfc822 string) (FullMess } walk(out.Payload) fm := FullMessage{GmailID: gid, Attachments: atts} - if plain != "" { - fm.Body = plain - } else { + // 메일앱처럼 보이도록 HTML 본문 우선, 없으면 텍스트. + if html != "" { fm.Body = html fm.IsHTML = true + } else { + fm.Body = plain } return fm, nil }