From 3d47e74ec78f62f1b6c490dce28ad7445a249e47 Mon Sep 17 00:00:00 2001 From: Egutierrez Date: Sat, 18 Apr 2026 17:10:31 +0200 Subject: [PATCH] feat: tipos UploadedFile, StorageConfig, S3Config en infra (issue 0014 fase 1) --- functions/infra/s3_config.go | 11 +++++++++ functions/infra/storage_config.go | 8 +++++++ functions/infra/uploaded_file.go | 13 +++++++++++ types/infra/s3_config.md | 37 +++++++++++++++++++++++++++++++ types/infra/storage_config.md | 31 ++++++++++++++++++++++++++ types/infra/uploaded_file.md | 37 +++++++++++++++++++++++++++++++ 6 files changed, 137 insertions(+) create mode 100644 functions/infra/s3_config.go create mode 100644 functions/infra/storage_config.go create mode 100644 functions/infra/uploaded_file.go create mode 100644 types/infra/s3_config.md create mode 100644 types/infra/storage_config.md create mode 100644 types/infra/uploaded_file.md diff --git a/functions/infra/s3_config.go b/functions/infra/s3_config.go new file mode 100644 index 00000000..9818fcb8 --- /dev/null +++ b/functions/infra/s3_config.go @@ -0,0 +1,11 @@ +package infra + +// S3Config configura la conexion a almacenamiento S3-compatible (AWS S3, MinIO, etc). +type S3Config struct { + Endpoint string `json:"endpoint"` // URL del servidor (ej: "s3.amazonaws.com", "minio.local:9000") + Bucket string `json:"bucket"` // nombre del bucket + AccessKey string `json:"access_key"` // access key id + SecretKey string `json:"secret_key"` // secret access key + Region string `json:"region"` // region (ej: "us-east-1") + UseSSL bool `json:"use_ssl"` // si true, usa https +} diff --git a/functions/infra/storage_config.go b/functions/infra/storage_config.go new file mode 100644 index 00000000..5d291a71 --- /dev/null +++ b/functions/infra/storage_config.go @@ -0,0 +1,8 @@ +package infra + +// StorageConfig configura el almacenamiento local de archivos subidos. +type StorageConfig struct { + BaseDir string `json:"base_dir"` // directorio base para almacenar archivos + MaxFileSize int64 `json:"max_file_size"` // tamano maximo en bytes (ej: 10<<20 = 10MB) + AllowedTypes []string `json:"allowed_types"` // MIME types permitidos (ej: ["image/png", "image/jpeg", "application/pdf"]) +} diff --git a/functions/infra/uploaded_file.go b/functions/infra/uploaded_file.go new file mode 100644 index 00000000..f41a0c49 --- /dev/null +++ b/functions/infra/uploaded_file.go @@ -0,0 +1,13 @@ +package infra + +import "time" + +// UploadedFile contiene la metadata de un archivo subido y almacenado en disco o S3. +type UploadedFile struct { + Filename string `json:"filename"` // nombre original del archivo + StoredName string `json:"stored_name"` // nombre en disco (UUID-based) + Size int64 `json:"size"` // tamano en bytes + ContentType string `json:"content_type"` // MIME type detectado + Path string `json:"path"` // ruta completa en disco (o key S3) + CreatedAt time.Time `json:"created_at"` // timestamp de creacion +} diff --git a/types/infra/s3_config.md b/types/infra/s3_config.md new file mode 100644 index 00000000..5de0a369 --- /dev/null +++ b/types/infra/s3_config.md @@ -0,0 +1,37 @@ +--- +name: S3Config +lang: go +domain: infra +version: "1.0.0" +algebraic: product +definition: | + type S3Config struct { + Endpoint string + Bucket string + AccessKey string + SecretKey string + Region string + UseSSL bool + } +description: "Configura la conexion a un almacenamiento S3-compatible (AWS S3, MinIO, Wasabi, etc)." +tags: [s3, storage, config, cloud, infra] +uses_types: [] +file_path: "functions/infra/s3_config.go" +--- + +## Ejemplo + +```go +cfg := S3Config{ + Endpoint: "s3.amazonaws.com", + Bucket: "mi-bucket", + AccessKey: os.Getenv("S3_ACCESS_KEY"), + SecretKey: os.Getenv("S3_SECRET_KEY"), + Region: "us-east-1", + UseSSL: true, +} +``` + +## Notas + +Tipo producto. Para AWS S3 usar `Endpoint = "s3.amazonaws.com"` y la region apropiada. Para MinIO local usar `Endpoint = "minio.local:9000"` y `UseSSL = false`. Las credenciales NUNCA se hardcodean — se inyectan desde env vars o un secret manager. diff --git a/types/infra/storage_config.md b/types/infra/storage_config.md new file mode 100644 index 00000000..799dd8d1 --- /dev/null +++ b/types/infra/storage_config.md @@ -0,0 +1,31 @@ +--- +name: StorageConfig +lang: go +domain: infra +version: "1.0.0" +algebraic: product +definition: | + type StorageConfig struct { + BaseDir string + MaxFileSize int64 + AllowedTypes []string + } +description: "Configura el almacenamiento local de archivos: directorio base, tamano maximo y tipos MIME permitidos." +tags: [storage, config, upload, file, infra] +uses_types: [] +file_path: "functions/infra/storage_config.go" +--- + +## Ejemplo + +```go +cfg := StorageConfig{ + BaseDir: "./uploads", + MaxFileSize: 10 << 20, // 10 MB + AllowedTypes: []string{"image/jpeg", "image/png", "application/pdf"}, +} +``` + +## Notas + +Tipo producto — todos los campos son obligatorios. `BaseDir` debe existir o ser creable por la app. `MaxFileSize` se aplica con `http.MaxBytesReader` durante el parse del multipart. `AllowedTypes` es una lista blanca verificada por magic bytes (no por el header Content-Type del request). diff --git a/types/infra/uploaded_file.md b/types/infra/uploaded_file.md new file mode 100644 index 00000000..d4ea94c2 --- /dev/null +++ b/types/infra/uploaded_file.md @@ -0,0 +1,37 @@ +--- +name: UploadedFile +lang: go +domain: infra +version: "1.0.0" +algebraic: product +definition: | + type UploadedFile struct { + Filename string `json:"filename"` + StoredName string `json:"stored_name"` + Size int64 `json:"size"` + ContentType string `json:"content_type"` + Path string `json:"path"` + CreatedAt time.Time `json:"created_at"` + } +description: "Metadata de un archivo subido y almacenado. Combina nombre original, nombre unico en disco, tamano, MIME type, ruta y timestamp de creacion." +tags: [upload, file, storage, http, infra] +uses_types: [] +file_path: "functions/infra/uploaded_file.go" +--- + +## Ejemplo + +```go +file := UploadedFile{ + Filename: "vacaciones.png", + StoredName: "a1b2c3d4-e5f6-7890-abcd-ef1234567890.png", + Size: 102400, + ContentType: "image/png", + Path: "/var/uploads/a1b2c3d4-e5f6-7890-abcd-ef1234567890.png", + CreatedAt: time.Now(), +} +``` + +## Notas + +Tipo producto — todos los campos siempre presentes. `Filename` se preserva por trazabilidad pero NO se usa como nombre real en disco (riesgo path traversal). `StoredName` es generado con UUID por `file_unique_name`. `Path` es la ruta completa en disco para storage local, o la key del objeto para S3.