feat(upload): add file upload API with S3 + CloudFront signed cookies
Add POST /api/upload-file endpoint that uploads files to S3 and returns CDN URLs protected by CloudFront signed cookies (same pattern as Linear). Infrastructure: - Two private S3 buckets (static.multica.ai, static-staging.multica.ai) - Two CloudFront distributions with OAC and Trusted Key Groups - ACM wildcard cert in us-east-1, DNS records in Route 53 - RSA signing key stored in AWS Secrets Manager Backend: - S3 storage service with CloudFront CDN domain support - CloudFront signed cookie generation (RSA-SHA1) - Private key loaded from Secrets Manager (env var fallback for local dev) - Cookies set on login (VerifyCode) with 72h expiry matching JWT - Upload handler: multipart form → S3 → CloudFront URL response Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
961de18c97
commit
29a80e057e
10 changed files with 425 additions and 3 deletions
|
|
@ -12,10 +12,12 @@ import (
|
|||
"github.com/jackc/pgx/v5/pgconn"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
db "github.com/multica-ai/multica/server/pkg/db/generated"
|
||||
"github.com/multica-ai/multica/server/internal/auth"
|
||||
"github.com/multica-ai/multica/server/internal/events"
|
||||
"github.com/multica-ai/multica/server/internal/middleware"
|
||||
"github.com/multica-ai/multica/server/internal/realtime"
|
||||
"github.com/multica-ai/multica/server/internal/service"
|
||||
"github.com/multica-ai/multica/server/internal/storage"
|
||||
"github.com/multica-ai/multica/server/internal/util"
|
||||
)
|
||||
|
||||
|
|
@ -38,9 +40,11 @@ type Handler struct {
|
|||
TaskService *service.TaskService
|
||||
EmailService *service.EmailService
|
||||
PingStore *PingStore
|
||||
Storage *storage.S3Storage
|
||||
CFSigner *auth.CloudFrontSigner
|
||||
}
|
||||
|
||||
func New(queries *db.Queries, txStarter txStarter, hub *realtime.Hub, bus *events.Bus, emailService *service.EmailService) *Handler {
|
||||
func New(queries *db.Queries, txStarter txStarter, hub *realtime.Hub, bus *events.Bus, emailService *service.EmailService, s3 *storage.S3Storage, cfSigner *auth.CloudFrontSigner) *Handler {
|
||||
var executor dbExecutor
|
||||
if candidate, ok := txStarter.(dbExecutor); ok {
|
||||
executor = candidate
|
||||
|
|
@ -55,6 +59,8 @@ func New(queries *db.Queries, txStarter txStarter, hub *realtime.Hub, bus *event
|
|||
TaskService: service.NewTaskService(queries, hub, bus),
|
||||
EmailService: emailService,
|
||||
PingStore: NewPingStore(),
|
||||
Storage: s3,
|
||||
CFSigner: cfSigner,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue