diff --git a/.env.template b/.env.template deleted file mode 100644 index 07506a0..0000000 --- a/.env.template +++ /dev/null @@ -1,14 +0,0 @@ -# Change all vars before going to production and remove all comments (!) -# Below all environment variables and default values - -GRPC_PORT=50051 -GRPC_ENABLE_REFLECTION=false -HTTP_HANDLER_ENABLE=false -HTTP_PORT=8080 -LOG_LEVEL=info -POSTGRES_HOST=localhost -POSTGRES_PORT=5432 -POSTGRES_USERNAME=postgres -POSTGRES_PASSWORD=postgres -POSTGRES_DATABASE=postgres -REDIS_URI=redis://localhost:6379 diff --git a/Containerfile b/Containerfile index 454012f..e66ba23 100644 --- a/Containerfile +++ b/Containerfile @@ -44,7 +44,7 @@ ARG SERVICE WORKDIR /app -COPY --from=build --chown=1000:1000 /out/${SERVICE} /app/bin/${SERVICE} +COPY --from=build --chown=1000:1000 /out/${SERVICE} /app/bin EXPOSE 8080 50051 @@ -54,6 +54,6 @@ LABEL org.opencontainers.image.created="${BUILD_TIME}" \ USER 1000 -ENTRYPOINT ["/app/bin/${SERVICE}"] +ENTRYPOINT ["/app/bin"] CMD [] diff --git a/cmd/competition/main.go b/cmd/competition/main.go index f10a1ed..9cb8526 100644 --- a/cmd/competition/main.go +++ b/cmd/competition/main.go @@ -29,4 +29,4 @@ func main() { log.Println("shutting down competition server...") srv.Stop() log.Println("competition server stopped") -} \ No newline at end of file +} diff --git a/cmd/gw/main.go b/cmd/gw/main.go index c1f2f83..9cd7d3c 100644 --- a/cmd/gw/main.go +++ b/cmd/gw/main.go @@ -31,42 +31,53 @@ func main() { authClient, err := grpc_client.NewAuthClient(ctx, cfg.GRPC.AuthServiceAddr, clientFactory) if err != nil { - log.Fatalf("Failed to create auth client: %v", err) + log.Printf("Warning: Failed to create auth client: %v", err) + authClient = nil } + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + userClient, err := grpc_client.NewUserClient(ctx, cfg.GRPC.UserServiceAddr, clientFactory) if err != nil { - log.Fatalf("Failed to create user client: %v", err) + log.Printf("Warning: Failed to create user client: %v", err) + userClient = nil } competitionClient, err := grpc_client.NewCompetitionClient(ctx, cfg.GRPC.CompetitionServiceAddr, clientFactory) if err != nil { - log.Fatalf("Failed to create competition client: %v", err) + log.Printf("Warning: Failed to create competition client: %v", err) + competitionClient = nil } taskClient, err := grpc_client.NewTaskClient(ctx, cfg.GRPC.TaskServiceAddr, clientFactory) if err != nil { - log.Fatalf("Failed to create task client: %v", err) + log.Printf("Warning: Failed to create task client: %v", err) + taskClient = nil } submissionClient, err := grpc_client.NewSubmissionClient(ctx, cfg.GRPC.SubmissionServiceAddr, clientFactory) if err != nil { - log.Fatalf("Failed to create submission client: %v", err) + log.Printf("Warning: Failed to create submission client: %v", err) + submissionClient = nil } resultsClient, err := grpc_client.NewResultsClient(ctx, cfg.GRPC.ResultsServiceAddr, clientFactory) if err != nil { - log.Fatalf("Failed to create results client: %v", err) + log.Printf("Warning: Failed to create results client: %v", err) + resultsClient = nil } reviewClient, err := grpc_client.NewReviewClient(ctx, cfg.GRPC.ReviewServiceAddr, clientFactory) if err != nil { - log.Fatalf("Failed to create review client: %v", err) + log.Printf("Warning: Failed to create review client: %v", err) + reviewClient = nil } achievementsClient, err := grpc_client.NewAchievementsClient(ctx, cfg.GRPC.AchievementsServiceAddr, clientFactory) if err != nil { - log.Fatalf("Failed to create achievements client: %v", err) + log.Printf("Warning: Failed to create achievements client: %v", err) + achievementsClient = nil } s3Storage, err := storage.NewS3Storage(storage.S3Config{ @@ -82,23 +93,65 @@ func main() { authMiddleware := middleware.NewAuthMiddleware(authClient) - authHandler := handler.NewAuthHandler(authClient, userClient) - competitionHandler := handler.NewCompetitionHandler(competitionClient, userClient) - taskHandler := handler.NewTaskHandler(taskClient) - submissionHandler := handler.NewSubmissionHandler(submissionClient, s3Storage) - resultsHandler := handler.NewResultsHandler(resultsClient) - reviewHandler := handler.NewReviewHandler(reviewClient) - achievementsHandler := handler.NewAchievementsHandler(achievementsClient) + var authHandler handler.AuthHandler + if authClient != nil { + authHandler = *handler.NewAuthHandler(authClient, userClient) + } else { + log.Printf("Warning: AuthHandler not initialized due to missing authClient") + } + + var competitionHandler handler.CompetitionHandler + if competitionClient != nil { + competitionHandler = *handler.NewCompetitionHandler(competitionClient, userClient) + } else { + log.Printf("Warning: CompetitionHandler not initialized due to missing competitionClient") + } + + var taskHandler handler.TaskHandler + if taskClient != nil { + taskHandler = *handler.NewTaskHandler(taskClient) + } else { + log.Printf("Warning: TaskHandler not initialized due to missing taskClient") + } + + var submissionHandler handler.SubmissionHandler + if submissionClient != nil { + submissionHandler = *handler.NewSubmissionHandler(submissionClient, s3Storage) + } else { + log.Printf("Warning: SubmissionHandler not initialized due to missing submissionClient") + } + + var resultsHandler handler.ResultsHandler + if resultsClient != nil { + resultsHandler = *handler.NewResultsHandler(resultsClient) + } else { + log.Printf("Warning: ResultsHandler not initialized due to missing resultsClient") + } + + var reviewHandler handler.ReviewHandler + if reviewClient != nil { + reviewHandler = *handler.NewReviewHandler(reviewClient) + } else { + log.Printf("Warning: ReviewHandler not initialized due to missing reviewClient") + } + + var achievementsHandler handler.AchievementsHandler + if achievementsClient != nil { + achievementsHandler = *handler.NewAchievementsHandler(achievementsClient) + } else { + log.Printf("Warning: AchievementsHandler not initialized due to missing achievementsClient") + } + pingHandler := handler.NewPingHandler() rt := router.NewRouter( - authHandler, - competitionHandler, - taskHandler, - submissionHandler, - resultsHandler, - reviewHandler, - achievementsHandler, + &authHandler, + &competitionHandler, + &taskHandler, + &submissionHandler, + &resultsHandler, + &reviewHandler, + &achievementsHandler, pingHandler, authMiddleware, ) diff --git a/compose.yaml b/compose.yaml index 2afbdcf..0e86e88 100644 --- a/compose.yaml +++ b/compose.yaml @@ -1,82 +1,12 @@ name: datarush services: - auth: - build: - context: . - dockerfile: Containerfile - depends_on: - postgres: - restart: false - condition: service_healthy - required: true - env_file: - - path: ./infrastructure/auth/.env.template - required: true - - path: ./infrastructure/auth/.env - required: false - ports: - - name: http - target: 8081 - published: 13443 - host_ip: 127.0.0.1 - protocol: tcp - app_protocol: http - - name: grpc - target: 50052 - published: 13444 - host_ip: 127.0.0.1 - protocol: tcp - app_protocol: http - networks: - - default - restart: unless-stopped - shm_size: 4mb - - competition: - build: - context: . - dockerfile: Containerfile - depends_on: - postgres: - restart: false - condition: service_healthy - required: true - redis: - restart: false - condition: service_healthy - required: true - auth: - restart: false - condition: service_started - required: true - env_file: - - path: ./infrastructure/competition/.env.template - required: true - - path: ./infrastructure/competition/.env - required: false - ports: - - name: http - target: 8082 - published: 13445 - host_ip: 127.0.0.1 - protocol: tcp - app_protocol: http - - name: grpc - target: 50053 - published: 13446 - host_ip: 127.0.0.1 - protocol: tcp - app_protocol: http - networks: - - default - restart: unless-stopped - shm_size: 4mb - - core: + gw: build: context: . dockerfile: Containerfile + args: + SERVICE: gw depends_on: migrate: restart: false @@ -99,22 +29,10 @@ services: condition: service_started required: true env_file: - - path: ./infrastructure/core/.env.template + - path: ./infrastructure/gw/.env.template required: true - - path: ./infrastructure/core/.env - ports: - - name: http - target: 8080 - published: 13440 - host_ip: 127.0.0.1 - protocol: tcp - app_protocol: http - - name: grpc - target: 50051 - published: 13441 - host_ip: 127.0.0.1 - protocol: tcp - app_protocol: http + - path: ./infrastructure/gw/.env + required: false networks: - default restart: unless-stopped @@ -124,20 +42,102 @@ services: build: context: . dockerfile: Containerfile + args: + SERVICE: migrate depends_on: postgres: restart: false condition: service_healthy required: true env_file: - - path: ./infrastructure/core/.env.template + - path: ./infrastructure/migrate/.env.template required: true - - path: ./infrastructure/core/.env + - path: ./infrastructure/migrate/.env + required: false networks: - default restart: no shm_size: 4mb + auth: + build: + context: . + dockerfile: Containerfile + args: + SERVICE: auth + depends_on: + postgres: + restart: false + condition: service_healthy + required: true + env_file: + - path: ./infrastructure/auth/.env.template + required: true + - path: ./infrastructure/auth/.env + required: false + networks: + - default + restart: unless-stopped + shm_size: 4mb + + competition: + build: + context: . + dockerfile: Containerfile + args: + SERVICE: competition + depends_on: + postgres: + restart: false + condition: service_healthy + required: true + redis: + restart: false + condition: service_healthy + required: true + auth: + restart: false + condition: service_started + required: true + env_file: + - path: ./infrastructure/competition/.env.template + required: true + - path: ./infrastructure/competition/.env + required: false + networks: + - default + restart: unless-stopped + shm_size: 4mb + + nginx: + image: docker.io/nginx:1.29-alpine + configs: + - source: nginx_config + target: /etc/nginx/nginx.conf + depends_on: + gw: + restart: false + condition: service_started + required: true + healthcheck: + test: ["CMD", "wget", "-O", "-", "http://localhost:80/healthz"] + interval: 1m30s + timeout: 5s + start_period: 5s + start_interval: 2s + retries: 5 + ports: + - name: web + target: 80 + published: 8080 + host_ip: 0.0.0.0 + protocol: tcp + app_protocol: http + networks: + - default + restart: unless-stopped + shm_size: 4mb + postgres: image: docker.io/postgres:17-alpine configs: @@ -234,6 +234,60 @@ services: target: /data read_only: false + minio-init: + image: docker.io/minio/minio:RELEASE.2025-09-07T16-13-09Z + entrypoint: > + /bin/sh -c " + sleep 5; + /usr/bin/mc alias set minio http://minio:9000 admin password; + /usr/bin/mc mb minio/datarush; + exit 0; + " + env_file: + - path: ./infrastructure/minio/.env.template + required: true + - path: ./infrastructure/minio/.env + required: false + restart: no + volumes: + - type: volume + source: minio_data + target: /data + + minio: + image: docker.io/minio/minio:RELEASE.2025-09-07T16-13-09Z + command: server --console-address ":9001" + healthcheck: + test: [ "CMD", "mc", "ready", "local" ] + interval: 1m30s + timeout: 5s + start_period: 5s + start_interval: 2s + retries: 5 + env_file: + - path: ./infrastructure/minio/.env.template + required: true + - path: ./infrastructure/minio/.env + required: false + ports: + - name: api + target: 9000 + published: 8005 + host_ip: 127.0.0.1 + protocol: tcp + app_protocol: http + - name: console + target: 9001 + published: 8006 + host_ip: 127.0.0.1 + protocol: tcp + app_protocol: http + restart: unless-stopped + volumes: + - type: volume + source: minio_data + target: /data + networks: default: @@ -249,9 +303,12 @@ volumes: postgres_data: pgadmin_data: redis_data: + minio_data: configs: + nginx_config: + file: ./infrastructure/nginx/nginx.conf postgres_config: file: ./infrastructure/postgres/postgresql.conf pgadmin_servers_config: diff --git a/go.mod b/go.mod index 6dd554c..1870f7c 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,10 @@ toolchain go1.24.9 require ( github.com/Masterminds/squirrel v1.5.4 - github.com/go-playground/validator/v10 v10.28.0 + github.com/aws/aws-sdk-go-v2 v1.41.0 + github.com/aws/aws-sdk-go-v2/config v1.32.6 + github.com/aws/aws-sdk-go-v2/credentials v1.19.6 + github.com/aws/aws-sdk-go-v2/service/s3 v1.27.11 github.com/golang-jwt/jwt/v5 v5.3.0 github.com/golang-migrate/migrate/v4 v4.19.0 github.com/golang/mock v1.6.0 @@ -43,9 +46,6 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/gabriel-vasile/mimetype v1.4.10 // indirect - github.com/go-playground/locales v0.14.1 // indirect - github.com/go-playground/universal-translator v0.18.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/kr/text v0.2.0 // indirect diff --git a/go.sum b/go.sum index 371f8e4..f5c7641 100644 --- a/go.sum +++ b/go.sum @@ -78,20 +78,10 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0= -github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= -github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= -github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= -github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688= -github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -132,8 +122,6 @@ github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= -github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= -github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= @@ -152,8 +140,6 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/redis/go-redis/v9 v9.16.0 h1:OotgqgLSRCmzfqChbQyG1PHC3tLNR89DG4jdOERSEP4= -github.com/redis/go-redis/v9 v9.16.0/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370= github.com/redis/go-redis/v9 v9.17.2 h1:P2EGsA4qVIM3Pp+aPocCJ7DguDHhqrXNhVcEp4ViluI= github.com/redis/go-redis/v9 v9.17.2/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= diff --git a/infrastructure/auth/.env.template b/infrastructure/auth/.env.template index 1607dd9..284b31f 100644 --- a/infrastructure/auth/.env.template +++ b/infrastructure/auth/.env.template @@ -1,5 +1,5 @@ -AUTH_GRPC_PORT=50052 -AUTH_HTTP_PORT=8081 +AUTH_GRPC_PORT=50051 +AUTH_HTTP_PORT=8080 AUTH_GRPC_ENABLE_REFLECTION=true POSTGRES_HOST=postgres diff --git a/infrastructure/competition/.env.template b/infrastructure/competition/.env.template index 2526129..02f122f 100644 --- a/infrastructure/competition/.env.template +++ b/infrastructure/competition/.env.template @@ -1,31 +1,19 @@ -# Competition Service Configuration - -# gRPC server port -COMPETITION_GRPC_PORT=50053 - -# Enable/disable gRPC reflection +COMPETITION_GRPC_PORT=50051 COMPETITION_GRPC_ENABLE_REFLECTION=true +COMPETITION_HTTP_PORT=8080 -# HTTP server port (if applicable) -COMPETITION_HTTP_PORT=8082 - -# Log level (e.g., debug, info, warn, error) LOG_LEVEL=info -# PostgreSQL database connection POSTGRES_HOST=postgres POSTGRES_PORT=5432 POSTGRES_USERNAME=postgres POSTGRES_PASSWORD=postgres POSTGRES_DATABASE=postgres -# Address of the authentication gRPC service -AUTH_SVC_ADDR=auth:50052 +AUTH_SVC_ADDR=auth:50051 -# Redis connection for caching REDIS_ADDR=redis:6379 REDIS_PASSWORD= REDIS_DB=0 -# Enable/disable caching -CACHE_ENABLED=true \ No newline at end of file +CACHE_ENABLED=true diff --git a/infrastructure/gw/.env.template b/infrastructure/gw/.env.template index 12f1b1c..3e59c69 100644 --- a/infrastructure/gw/.env.template +++ b/infrastructure/gw/.env.template @@ -1,19 +1,19 @@ SERVER_PORT=8080 SERVER_HOST=0.0.0.0 -AUTH_SERVICE_ADDR=auth:50052 -USER_SERVICE_ADDR=user:50052 -COMPETITION_SERVICE_ADDR=competition:50052 -TASK_SERVICE_ADDR=task:50052 -SUBMISSION_SERVICE_ADDR=submission:50052 -RESULTS_SERVICE_ADDR=results:50052 -REVIEW_SERVICE_ADDR=review:50052 -ACHIEVEMENTS_SERVICE_ADDR=achievements:50052 +AUTH_SERVICE_ADDR=auth:50051 +USER_SERVICE_ADDR=user:50051 +COMPETITION_SERVICE_ADDR=competition:50051 +TASK_SERVICE_ADDR=task:50051 +SUBMISSION_SERVICE_ADDR=submission:50051 +RESULTS_SERVICE_ADDR=results:50051 +REVIEW_SERVICE_ADDR=review:50051 +ACHIEVEMENTS_SERVICE_ADDR=achievements:50051 -AWS_ACCESS_KEY_ID=your_access_key_here -AWS_SECRET_ACCESS_KEY=your_secret_key_here -AWS_REGION=us-east-1 -S3_BUCKET=datarush-submissions -S3_ENDPOINT= +AWS_ACCESS_KEY_ID=admin +AWS_SECRET_ACCESS_KEY=password +AWS_REGION= +S3_BUCKET=datarush +S3_ENDPOINT=http://localhost:9000 JWT_SECRET=your_jwt_secret_here diff --git a/infrastructure/migrate/.env.template b/infrastructure/migrate/.env.template new file mode 100644 index 0000000..cf0da61 --- /dev/null +++ b/infrastructure/migrate/.env.template @@ -0,0 +1,5 @@ +POSTGRES_HOST=localhost +POSTGRES_PORT=5432 +POSTGRES_USERNAME=postgres +POSTGRES_PASSWORD=postgres +POSTGRES_DATABASE=postgres diff --git a/infrastructure/minio/.env.template b/infrastructure/minio/.env.template new file mode 100644 index 0000000..9d55c3a --- /dev/null +++ b/infrastructure/minio/.env.template @@ -0,0 +1,3 @@ +MINIO_ROOT_USER=admin +MINIO_ROOT_PASSWORD=password +MINIO_VOLUMES=/data diff --git a/infrastructure/nginx/nginx.conf b/infrastructure/nginx/nginx.conf new file mode 100644 index 0000000..e00cef4 --- /dev/null +++ b/infrastructure/nginx/nginx.conf @@ -0,0 +1,156 @@ +user nginx; +worker_processes auto; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +events { + worker_connections 4096; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + ssl_session_cache shared:SSL:50m; + ssl_session_timeout 1d; + ssl_session_tickets off; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256; + ssl_ecdh_curve X25519:secp521r1:secp384r1; + ssl_prefer_server_ciphers on; + ssl_stapling on; + ssl_stapling_verify on; + resolver 127.0.0.11 valid=30s; + resolver_timeout 5s; + server_names_hash_bucket_size 128; + + add_header X-Content-Type-Options "nosniff" always; + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-XSS-Protection "0"; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; + add_header Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()" always; + add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https:; img-src 'self' data: https:; style-src 'self' 'unsafe-inline' https:; font-src 'self' https:; frame-ancestors 'none'; form-action 'self'; object-src 'none'; base-uri 'self';" always; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 75; + client_body_timeout 15; + client_header_timeout 15; + reset_timedout_connection on; + send_timeout 15; + + client_body_buffer_size 128k; + client_header_buffer_size 4k; + client_max_body_size 100M; + large_client_header_buffers 4 16k; + + gzip on; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_min_length 1024; + gzip_types + text/plain + text/css + text/xml + text/javascript + application/json + application/javascript + application/x-javascript + application/xml + application/xml+rss + font/woff + font/woff2 + image/svg+xml; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + server_tokens off; + + upstream gw { + zone gw 64k; + server gw:8080 resolve; + } + + upstream minio { + zone minio 64k; + server minio:9000 resolve; + } + + upstream minio-ui { + zone minio-ui 64k; + server minio:9001 resolve; + } + + server { + listen 80; + server_name _; + + location / { + proxy_pass http://gw; + + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + } + + server { + listen 80; + listen [::]:80; + server_name minio; + + http2 on; + + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + + ignore_invalid_headers off; + client_max_body_size 0; + proxy_buffering off; + proxy_request_buffering off; + + location / { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_connect_timeout 300; + proxy_http_version 1.1; + proxy_set_header Connection ""; + chunked_transfer_encoding off; + + proxy_pass http://minio; + } + + location /minio/ui/ { + rewrite ^/minio/ui/(.*) /$1 break; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-NginX-Proxy true; + + real_ip_header X-Real-IP; + + proxy_connect_timeout 300; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + chunked_transfer_encoding off; + + proxy_pass http://minio-ui; + } + } +} diff --git a/internal/auth/config/config.go b/internal/auth/config/config.go index c29d095..4e8891d 100644 --- a/internal/auth/config/config.go +++ b/internal/auth/config/config.go @@ -27,7 +27,7 @@ func Load() (*Config, error) { _ = godotenv.Load() return &Config{ - GRPCPort: mustGetInt("AUTH_GRPC_PORT", 50052), + GRPCPort: mustGetInt("AUTH_GRPC_PORT", 50051), GRPCEnableReflection: mustGetBool("AUTH_GRPC_ENABLE_REFLECTION", false), HTTPPort: mustGetInt("AUTH_HTTP_PORT", 8081), LogLevel: getEnv("LOG_LEVEL", "info"), diff --git a/internal/auth/handler/grpc/auth.go b/internal/auth/handler/grpc/auth.go index f8d1907..4c593d2 100644 --- a/internal/auth/handler/grpc/auth.go +++ b/internal/auth/handler/grpc/auth.go @@ -53,7 +53,10 @@ func (h *AuthHandler) SignIn(ctx context.Context, req *pb.SignInRequest) (*pb.Si return &pb.SignInResponse{Token: token}, nil } -func (h *AuthHandler) ValidateToken(ctx context.Context, req *pb.ValidateTokenRequest) (*pb.ValidateTokenResponse, error) { +func (h *AuthHandler) ValidateToken( + ctx context.Context, + req *pb.ValidateTokenRequest, +) (*pb.ValidateTokenResponse, error) { token := req.Token if token == "" { diff --git a/internal/auth/handler/http/auth.go b/internal/auth/handler/http/auth.go index 682c4b5..67e046d 100644 --- a/internal/auth/handler/http/auth.go +++ b/internal/auth/handler/http/auth.go @@ -12,13 +12,13 @@ import ( ) type SignUpRequest struct { - Email string `json:"email" binding:"required,email"` + Email string `json:"email" binding:"required,email"` Username string `json:"username" binding:"required"` Password string `json:"password" binding:"required"` } type SignInRequest struct { - Email string `json:"email" binding:"required,email"` + Email string `json:"email" binding:"required,email"` Password string `json:"password" binding:"required"` } diff --git a/internal/competition/config/config.go b/internal/competition/config/config.go index 20e1d75..b1f97af 100644 --- a/internal/competition/config/config.go +++ b/internal/competition/config/config.go @@ -31,7 +31,7 @@ func Load() (*Config, error) { _ = godotenv.Load() return &Config{ - GRPCPort: mustGetInt("COMPETITION_GRPC_PORT", 50053), + GRPCPort: mustGetInt("COMPETITION_GRPC_PORT", 50051), GRPCEnableReflection: mustGetBool("COMPETITION_GRPC_ENABLE_REFLECTION", false), HTTPPort: mustGetInt("COMPETITION_HTTP_PORT", 8082), LogLevel: getEnv("LOG_LEVEL", "info"), diff --git a/internal/gw/config/config.go b/internal/gw/config/config.go index ec66c0d..80f0efd 100644 --- a/internal/gw/config/config.go +++ b/internal/gw/config/config.go @@ -60,7 +60,7 @@ func Load() (*Config, error) { S3: S3Config{ AccessKeyID: getEnvRequired("AWS_ACCESS_KEY_ID"), SecretAccessKey: getEnvRequired("AWS_SECRET_ACCESS_KEY"), - Region: getEnvRequired("AWS_REGION"), + Region: getEnv("AWS_REGION", ""), Bucket: getEnvRequired("S3_BUCKET"), Endpoint: getEnv("S3_ENDPOINT", ""), }, diff --git a/internal/migrate/config/config.go b/internal/migrate/config/config.go index 47280f9..0d2a479 100644 --- a/internal/migrate/config/config.go +++ b/internal/migrate/config/config.go @@ -22,27 +22,17 @@ type Config struct { DBPassword string DBName string RedisURI string - AuthGRPCAddr string - CacheEnabled bool } func Load() (*Config, error) { _ = godotenv.Load() return &Config{ - GRPCPort: mustGetInt("GRPC_PORT", 50051), //nolint:mnd // false-positive - GRPCEnableReflection: mustGetBool("GRPC_ENABLE_REFLECTION", false), - EnableHTTPHandler: mustGetBool("HTTP_HANDLER_ENABLE", false), - HTTPPort: mustGetInt("HTTP_PORT", 8080), //nolint:mnd // false-positive - LogLevel: getEnv("LOG_LEVEL", "info"), DBHost: getEnv("POSTGRES_HOST", "localhost"), DBPort: mustGetInt("POSTGRES_PORT", 5432), //nolint:mnd // false-positive DBUser: getEnv("POSTGRES_USERNAME", "postgres"), DBPassword: getEnv("POSTGRES_PASSWORD", "postgres"), DBName: getEnv("POSTGRES_DATABASE", "postgres"), - RedisURI: getEnv("REDIS_URI", "redis://localhost:6379"), - AuthGRPCAddr: getEnv("AUTH_GRPC_ADDR", "localhost:50052"), - CacheEnabled: mustGetBool("CACHE_ENABLED", true), }, nil } diff --git a/pkg/api/competition/competition.pb.go b/pkg/api/competition/competition.pb.go index fe3873b..767908e 100644 --- a/pkg/api/competition/competition.pb.go +++ b/pkg/api/competition/competition.pb.go @@ -7,24 +7,13 @@ package competition import ( - "context" - "io" - "net/http" - "unsafe" - - "reflect" - "sync" - - "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "google.golang.org/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" emptypb "google.golang.org/protobuf/types/known/emptypb" timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" + unsafe "unsafe" ) const (