theorose49 995dd36167
All checks were successful
build-and-push / build (push) Successful in 32s
feat: 대시보드 내 이슈(/my/tasks) + 전체 캘린더(CalendarEvent) + 메일 AI 요약(OpenAI)
- GET /my/tasks: 전 프로젝트에서 나에게 배정된 작업 + projectName (대시보드 JIRA 보드용)
  · fix: ORDER BY "end"(예약어) 따옴표 처리
- CalendarEvent 모델 + /calendar/events CRUD(본인 소유), nav에 캘린더 추가
- internal/ai(OpenAI, stdlib): 메일 동기화 시 신규 메일에 한 줄 AI 요약 생성(OPENAI_API_KEY)
  · ProjectMailMsg.Summary, 회당 40건 상한
- nav inbox 라벨 쪽지함으로 통일

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 16:06:55 +09:00

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.OpenAIKey, 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)
}
}