All checks were successful
build-and-push / build (push) Successful in 33s
- ProjectMailMsg(헤더 저장)·ProjectMailState(동기화 상태) 모델, AutoMigrate 등록 - mailsync.FetchForDomain: nextPageToken 따라 전체 히스토리 페이지네이션(maxPerBox=0=전부) - 백그라운드 주기 동기화 StartMailSyncLoop(MAIL_SYNC_INTERVAL 기본 15m, 0=비활성) · 미동기화 프로젝트=full 백필, 이후=최신 페이지 top-up - GET /mails는 DB에서 읽어 참여자(from/to/cc) 필터 + 공동 메모 인라인 결합 + lastSyncedAt - POST /mails/sync(강제 풀싱크), PUT /mail-hide(프로젝트 단위 숨김) - mailCache 제거(DB가 캐시), config MailSyncInterval Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
67 lines
1.6 KiB
Go
67 lines
1.6 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"net/http"
|
|
"time"
|
|
|
|
"spin/internal/config"
|
|
"spin/internal/db"
|
|
"spin/internal/httpapi"
|
|
"spin/internal/mailsync"
|
|
"spin/internal/push"
|
|
"spin/internal/seed"
|
|
"spin/internal/storage"
|
|
)
|
|
|
|
func main() {
|
|
cfg := config.Load()
|
|
|
|
gdb, err := db.Connect(cfg.DatabaseURL)
|
|
if err != nil {
|
|
log.Fatalf("database connection failed: %v", err)
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
|
|
store, err := storage.New(ctx, cfg)
|
|
if err != nil {
|
|
log.Printf("storage init failed (continuing without S3): %v", err)
|
|
store = nil
|
|
} else if err := store.EnsureBucket(ctx); err != nil {
|
|
log.Printf("ensure bucket failed (retrying once): %v", err)
|
|
time.Sleep(2 * time.Second)
|
|
if err := store.EnsureBucket(ctx); err != nil {
|
|
log.Printf("ensure bucket failed (best-effort): %v", err)
|
|
}
|
|
}
|
|
|
|
if cfg.SeedData {
|
|
if err := seed.Run(gdb); err != nil {
|
|
log.Printf("seed failed (continuing): %v", err)
|
|
}
|
|
} else {
|
|
log.Printf("seed skipped (SEED=false)")
|
|
}
|
|
|
|
pusher := push.New(cfg.FCMCredentialsFile)
|
|
mailer := mailsync.New(cfg.GoogleSACredentialsFile)
|
|
router := httpapi.NewRouter(gdb, store, cfg, pusher, mailer)
|
|
httpapi.StartMailSyncLoop(context.Background(), gdb, mailer, cfg.MailSyncInterval)
|
|
|
|
addr := ":" + cfg.Port
|
|
srv := &http.Server{
|
|
Addr: addr,
|
|
Handler: router,
|
|
ReadTimeout: 30 * time.Second,
|
|
WriteTimeout: 60 * time.Second,
|
|
}
|
|
|
|
log.Printf("spin backend listening on %s (devAuth=%v)", addr, cfg.DevAuth)
|
|
if err := srv.ListenAndServe(); err != nil {
|
|
log.Fatalf("server error: %v", err)
|
|
}
|
|
}
|