diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..d5f03e1
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,15 @@
+.git
+.gitignore
+.vscode
+**/.DS_Store
+**/node_modules
+**/dist
+**/coverage
+**/.cache
+**/*.log
+docs
+frontend
+infrastructure/dev
+infrastructure/prod
+.tmp
+tmp
diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml
new file mode 100644
index 0000000..2a00f82
--- /dev/null
+++ b/.github/workflows/deploy-dev.yml
@@ -0,0 +1,29 @@
+name: Deploy Dev
+
+on:
+ push:
+ branches:
+ - develop
+
+jobs:
+ deploy-dev:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup Task
+ uses: arduino/setup-task@v2
+
+ - name: Setup SSH agent
+ uses: webfactory/ssh-agent@v0.9.0
+ with:
+ ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
+
+ - name: Deploy to dev host
+ env:
+ DEPLOY_HOST: ${{ secrets.DEV_DEPLOY_HOST }}
+ DEPLOY_USER: ${{ secrets.DEV_DEPLOY_USER }}
+ DEPLOY_PATH: ${{ secrets.DEV_DEPLOY_PATH }}
+ DEPLOY_REF: develop
+ run: task cd:deploy-dev
diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml
new file mode 100644
index 0000000..cd03d2c
--- /dev/null
+++ b/.github/workflows/deploy-prod.yml
@@ -0,0 +1,29 @@
+name: Deploy Prod
+
+on:
+ push:
+ tags:
+ - 'v*'
+
+jobs:
+ deploy-prod:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup Task
+ uses: arduino/setup-task@v2
+
+ - name: Setup SSH agent
+ uses: webfactory/ssh-agent@v0.9.0
+ with:
+ ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
+
+ - name: Deploy to prod host
+ env:
+ DEPLOY_HOST: ${{ secrets.PROD_DEPLOY_HOST }}
+ DEPLOY_USER: ${{ secrets.PROD_DEPLOY_USER }}
+ DEPLOY_PATH: ${{ secrets.PROD_DEPLOY_PATH }}
+ DEPLOY_REF: ${{ github.ref_name }}
+ run: task cd:deploy-prod
diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml
new file mode 100644
index 0000000..88bbd34
--- /dev/null
+++ b/.github/workflows/security-scan.yml
@@ -0,0 +1,63 @@
+name: Security Scan
+
+on:
+ pull_request:
+ push:
+ branches:
+ - main
+ - develop
+
+jobs:
+ security-scan:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup Go
+ uses: actions/setup-go@v5
+ with:
+ go-version-file: backend/go.work
+
+ - name: Setup Node
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+
+ - name: Enable Corepack
+ run: corepack enable
+
+ - name: Install frontend dependencies
+ working-directory: frontend
+ run: yarn install --immutable
+
+ - name: Install Task
+ uses: arduino/setup-task@v2
+
+ - name: Install golangci-lint and gosec
+ run: |
+ go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
+ go install github.com/securego/gosec/v2/cmd/gosec@latest
+ echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH"
+
+ - name: Install Trivy
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y wget gnupg lsb-release
+ wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo gpg --dearmor -o /usr/share/keyrings/trivy.gpg
+ echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/trivy.list
+ sudo apt-get update
+ sudo apt-get install -y trivy
+
+ - name: Run Task security pipeline
+ run: task ci:security-scan
+
+ - name: Upload reports
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: security-scan-reports
+ path: |
+ reports/security
+ reports/tests
+ reports/docker
diff --git a/.gitignore b/.gitignore
index ef333c7..3cf86f3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,6 +18,7 @@ Thumbs.db
.env
.env.*
!.env.example
+!**/.env.prod.example
# Node / frontend
frontend/node_modules/
@@ -46,3 +47,6 @@ pnpm-debug.log*
# Go workspace caches (optional, safe)
**/.cache/
+
+# CI/CD artifacts
+reports/
diff --git a/Makefile b/Makefile
index 03b1e65..2a8bc3a 100644
--- a/Makefile
+++ b/Makefile
@@ -5,6 +5,10 @@ COMPOSE_DIR := infrastructure/dev
COMPOSE_FILE := $(COMPOSE_DIR)/docker-compose.yml
ENV_FILE := $(COMPOSE_DIR)/.env
COMPOSE_CMD := $(COMPOSE) -f $(COMPOSE_FILE) --env-file $(ENV_FILE) --project-directory $(COMPOSE_DIR)
+COMPOSE_PROD_DIR := infrastructure/prod
+COMPOSE_PROD_FILE := $(COMPOSE_PROD_DIR)/docker-compose.yml
+ENV_PROD_FILE := $(COMPOSE_PROD_DIR)/.env.prod
+COMPOSE_PROD_CMD := $(COMPOSE) -f $(COMPOSE_PROD_FILE) --env-file $(ENV_PROD_FILE) --project-directory $(COMPOSE_PROD_DIR)
ifneq ("$(wildcard $(ENV_FILE))","")
include $(ENV_FILE)
@@ -22,8 +26,18 @@ JAEGER_UI_PORT ?= 16686
ZITADEL_ADMIN_USERNAME ?= admin
ZITADEL_ADMIN_PASSWORD ?= AdminPassword123!
GRAFANA_ADMIN_USER ?= admin
+BACKEND_MODULES := \
+ services/admin-service \
+ services/game-session-service \
+ services/gateway-service \
+ services/leaderboard-service \
+ services/question-bank-service \
+ services/user-service \
+ shared
.PHONY: help dev dev-full dev-auth dev-gateway stop clean \
+ infra-build-images infra-up-prod \
+ task-security-scan task-deploy-dev task-deploy-prod \
backend-lint backend-test backend-build \
frontend-dev frontend-lint frontend-test frontend-build \
db-up db-down db-logs db-shell redis-shell \
@@ -40,6 +54,13 @@ help:
@echo " make dev-gateway - Start core infrastructure + gateway ingress (NGINX + gateway service)"
@echo " make stop - Stop all containers"
@echo " make clean - Stop containers and remove volumes"
+ @echo " make infra-build-images - Build all production service images via compose"
+ @echo " make infra-up-prod - Run production compose stack locally (simulation)"
+ @echo ""
+ @echo "Task Workflows:"
+ @echo " make task-security-scan - Run Task CI security pipeline"
+ @echo " make task-deploy-dev - Run Task development deployment pipeline"
+ @echo " make task-deploy-prod - Run Task production deployment pipeline"
@echo ""
@echo "Backend:"
@echo " make backend-lint - Run Go linters"
@@ -109,21 +130,38 @@ clean:
@echo "Stopping containers and removing volumes..."
@$(COMPOSE_CMD) down -v
+infra-build-images:
+ @echo "Building production service images..."
+ @$(COMPOSE_PROD_CMD) build
+
+infra-up-prod:
+ @echo "Starting production compose stack locally..."
+ @$(COMPOSE_PROD_CMD) up -d
+
# =============================================================================
# Backend
# =============================================================================
backend-lint:
@echo "Running Go linters..."
- @cd backend && golangci-lint run ./...
+ @for module in $(BACKEND_MODULES); do \
+ echo "-> $$module"; \
+ (cd backend/$$module && golangci-lint run ./...); \
+ done
backend-test:
@echo "Running Go tests..."
- @cd backend && go test -v -race -cover ./...
+ @for module in $(BACKEND_MODULES); do \
+ echo "-> $$module"; \
+ (cd backend/$$module && go test -v -race -cover ./...); \
+ done
backend-build:
@echo "Building all services..."
- @cd backend && go build ./...
+ @for module in $(BACKEND_MODULES); do \
+ echo "-> $$module"; \
+ (cd backend/$$module && go build ./...); \
+ done
# =============================================================================
# Frontend
@@ -164,6 +202,19 @@ db-shell:
redis-shell:
@docker exec -it knowfoolery-redis redis-cli
+# =============================================================================
+# Task Workflows
+# =============================================================================
+
+task-security-scan:
+ @task ci:security-scan
+
+task-deploy-dev:
+ @task cd:deploy-dev
+
+task-deploy-prod:
+ @task cd:deploy-prod
+
# =============================================================================
# Combined Commands
# =============================================================================
diff --git a/README.md b/README.md
index 61dc833..f0b1299 100644
--- a/README.md
+++ b/README.md
@@ -39,6 +39,49 @@ Know Foolery is a quiz game inspired by the French game "Déconnaissance" (https
- [Security](docs/3_guidelines/security-guidelines.md)
- [Observability](docs/3_guidelines/observability-guidelines.md)
+## Infrastructure
+
+### Directory Layout
+- `infrastructure/dev`: local development compose stack and configs
+- `infrastructure/prod`: production compose stack, nginx, and prometheus config
+- `infrastructure/services`: Dockerfiles for each backend service
+- `tasks`: Go Task CI/CD workflows
+- `.github/workflows`: thin GitHub Actions wrappers that trigger Task workflows
+
+### Production Compose Usage
+1. Copy `infrastructure/prod/.env.prod.example` to `infrastructure/prod/.env.prod` and fill secrets.
+2. Validate config:
+```bash
+docker compose -f infrastructure/prod/docker-compose.yml --env-file infrastructure/prod/.env.prod config
+```
+3. Build and start:
+```bash
+docker compose -f infrastructure/prod/docker-compose.yml --env-file infrastructure/prod/.env.prod up -d --build
+```
+
+### Task Workflows
+- `task ci:security-scan`: lint, tests, docker build validation, gosec, trivy scans
+- `task cd:deploy-dev`: deploy to dev host over SSH + compose build/up + smoke checks
+- `task cd:deploy-prod`: deploy release tag to prod host over SSH + rollback on failure
+
+Make wrappers:
+- `make task-security-scan`
+- `make task-deploy-dev`
+- `make task-deploy-prod`
+- `make infra-build-images`
+- `make infra-up-prod`
+
+### GitHub Actions Secrets
+- Shared: `SSH_PRIVATE_KEY`
+- Dev deploy: `DEV_DEPLOY_HOST`, `DEV_DEPLOY_USER`, `DEV_DEPLOY_PATH`
+- Prod deploy: `PROD_DEPLOY_HOST`, `PROD_DEPLOY_USER`, `PROD_DEPLOY_PATH`
+
+### Deployment Host Prerequisites
+- Linux host with Docker Engine + Docker Compose v2
+- `git` and `curl` installed
+- persistent repository checkout at the configured deploy path
+- populated `infrastructure/prod/.env.prod` on target host
+
### Future Enhancements
#### Planned Features
diff --git a/Taskfile.yml b/Taskfile.yml
new file mode 100644
index 0000000..8908c44
--- /dev/null
+++ b/Taskfile.yml
@@ -0,0 +1,13 @@
+version: '3'
+
+includes:
+ ci:
+ taskfile: ./tasks/security-scan.yml
+ cd:
+ taskfile: ./tasks/deploy-dev.yml
+
+tasks:
+ default:
+ desc: Show available tasks
+ cmds:
+ - task --list-all
diff --git a/backend/services/admin-service/go.mod b/backend/services/admin-service/go.mod
index 29484da..74b5578 100644
--- a/backend/services/admin-service/go.mod
+++ b/backend/services/admin-service/go.mod
@@ -18,7 +18,7 @@ require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
- github.com/gofiber/utils/v2 v2.0.0-beta.4 // indirect
+ github.com/gofiber/utils/v2 v2.0.0-rc.4 // indirect
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
diff --git a/backend/services/admin-service/go.sum b/backend/services/admin-service/go.sum
index 14d9e78..bd9826a 100644
--- a/backend/services/admin-service/go.sum
+++ b/backend/services/admin-service/go.sum
@@ -14,6 +14,8 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
+github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@@ -22,8 +24,8 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofiber/fiber/v3 v3.0.0-beta.3 h1:7Q2I+HsIqnIEEDB+9oe7Gadpakh6ZLhXpTYz/L20vrg=
github.com/gofiber/fiber/v3 v3.0.0-beta.3/go.mod h1:kcMur0Dxqk91R7p4vxEpJfDWZ9u5IfvrtQc8Bvv/JmY=
-github.com/gofiber/utils/v2 v2.0.0-beta.4 h1:1gjbVFFwVwUb9arPcqiB6iEjHBwo7cHsyS41NeIW3co=
-github.com/gofiber/utils/v2 v2.0.0-beta.4/go.mod h1:sdRsPU1FXX6YiDGGxd+q2aPJRMzpsxdzCXo9dz+xtOY=
+github.com/gofiber/utils/v2 v2.0.0-rc.4 h1:CDjwPwtwwj1OTIf6v3iRk+D2wcdjUzwk91Ghu2TMNbE=
+github.com/gofiber/utils/v2 v2.0.0-rc.4/go.mod h1:gXins5o7up+BQFiubmO8aUJc/+Mhd7EKXIiAK5GBomI=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
@@ -68,6 +70,8 @@ github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoG
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
+github.com/shamaton/msgpack/v2 v2.4.0 h1:O5Z08MRmbo0lA9o2xnQ4TXx6teJbPqEurqcCOQ8Oi/4=
+github.com/shamaton/msgpack/v2 v2.4.0/go.mod h1:6khjYnkx73f7VQU7wjcFS9DFjs+59naVWJv1TB7qdOI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@@ -79,6 +83,8 @@ github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8
github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
+github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
+github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms=
diff --git a/backend/services/game-session-service/go.mod b/backend/services/game-session-service/go.mod
index 8333360..9713193 100644
--- a/backend/services/game-session-service/go.mod
+++ b/backend/services/game-session-service/go.mod
@@ -24,7 +24,7 @@ require (
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.25.0 // indirect
- github.com/gofiber/utils/v2 v2.0.0-beta.4 // indirect
+ github.com/gofiber/utils/v2 v2.0.0-rc.4 // indirect
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
diff --git a/backend/services/game-session-service/go.sum b/backend/services/game-session-service/go.sum
index 1cc8700..d31d3a5 100644
--- a/backend/services/game-session-service/go.sum
+++ b/backend/services/game-session-service/go.sum
@@ -24,6 +24,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
+github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
+github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -42,8 +44,8 @@ github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofiber/fiber/v3 v3.0.0-beta.3 h1:7Q2I+HsIqnIEEDB+9oe7Gadpakh6ZLhXpTYz/L20vrg=
github.com/gofiber/fiber/v3 v3.0.0-beta.3/go.mod h1:kcMur0Dxqk91R7p4vxEpJfDWZ9u5IfvrtQc8Bvv/JmY=
-github.com/gofiber/utils/v2 v2.0.0-beta.4 h1:1gjbVFFwVwUb9arPcqiB6iEjHBwo7cHsyS41NeIW3co=
-github.com/gofiber/utils/v2 v2.0.0-beta.4/go.mod h1:sdRsPU1FXX6YiDGGxd+q2aPJRMzpsxdzCXo9dz+xtOY=
+github.com/gofiber/utils/v2 v2.0.0-rc.4 h1:CDjwPwtwwj1OTIf6v3iRk+D2wcdjUzwk91Ghu2TMNbE=
+github.com/gofiber/utils/v2 v2.0.0-rc.4/go.mod h1:gXins5o7up+BQFiubmO8aUJc/+Mhd7EKXIiAK5GBomI=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
@@ -92,6 +94,8 @@ github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93Ge
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
+github.com/shamaton/msgpack/v2 v2.4.0 h1:O5Z08MRmbo0lA9o2xnQ4TXx6teJbPqEurqcCOQ8Oi/4=
+github.com/shamaton/msgpack/v2 v2.4.0/go.mod h1:6khjYnkx73f7VQU7wjcFS9DFjs+59naVWJv1TB7qdOI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@@ -103,6 +107,8 @@ github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8
github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
+github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
+github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
diff --git a/backend/services/gateway-service/go.mod b/backend/services/gateway-service/go.mod
index 0548284..cbaa34d 100644
--- a/backend/services/gateway-service/go.mod
+++ b/backend/services/gateway-service/go.mod
@@ -21,7 +21,7 @@ require (
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
- github.com/gofiber/utils/v2 v2.0.0-beta.4 // indirect
+ github.com/gofiber/utils/v2 v2.0.0-rc.4 // indirect
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7 // indirect
github.com/klauspost/compress v1.17.9 // indirect
diff --git a/backend/services/gateway-service/go.sum b/backend/services/gateway-service/go.sum
index 5ff07eb..b996cf9 100644
--- a/backend/services/gateway-service/go.sum
+++ b/backend/services/gateway-service/go.sum
@@ -23,6 +23,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
+github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
+github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@@ -31,8 +33,8 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofiber/fiber/v3 v3.0.0-beta.3 h1:7Q2I+HsIqnIEEDB+9oe7Gadpakh6ZLhXpTYz/L20vrg=
github.com/gofiber/fiber/v3 v3.0.0-beta.3/go.mod h1:kcMur0Dxqk91R7p4vxEpJfDWZ9u5IfvrtQc8Bvv/JmY=
-github.com/gofiber/utils/v2 v2.0.0-beta.4 h1:1gjbVFFwVwUb9arPcqiB6iEjHBwo7cHsyS41NeIW3co=
-github.com/gofiber/utils/v2 v2.0.0-beta.4/go.mod h1:sdRsPU1FXX6YiDGGxd+q2aPJRMzpsxdzCXo9dz+xtOY=
+github.com/gofiber/utils/v2 v2.0.0-rc.4 h1:CDjwPwtwwj1OTIf6v3iRk+D2wcdjUzwk91Ghu2TMNbE=
+github.com/gofiber/utils/v2 v2.0.0-rc.4/go.mod h1:gXins5o7up+BQFiubmO8aUJc/+Mhd7EKXIiAK5GBomI=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
@@ -77,6 +79,8 @@ github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
+github.com/shamaton/msgpack/v2 v2.4.0 h1:O5Z08MRmbo0lA9o2xnQ4TXx6teJbPqEurqcCOQ8Oi/4=
+github.com/shamaton/msgpack/v2 v2.4.0/go.mod h1:6khjYnkx73f7VQU7wjcFS9DFjs+59naVWJv1TB7qdOI=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
@@ -85,6 +89,8 @@ github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8
github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
+github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
+github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
diff --git a/backend/services/leaderboard-service/go.mod b/backend/services/leaderboard-service/go.mod
index e472f4f..0c49423 100644
--- a/backend/services/leaderboard-service/go.mod
+++ b/backend/services/leaderboard-service/go.mod
@@ -24,7 +24,7 @@ require (
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.25.0 // indirect
- github.com/gofiber/utils/v2 v2.0.0-beta.4 // indirect
+ github.com/gofiber/utils/v2 v2.0.0-rc.4 // indirect
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
diff --git a/backend/services/leaderboard-service/go.sum b/backend/services/leaderboard-service/go.sum
index 1cc8700..d31d3a5 100644
--- a/backend/services/leaderboard-service/go.sum
+++ b/backend/services/leaderboard-service/go.sum
@@ -24,6 +24,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
+github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
+github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -42,8 +44,8 @@ github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofiber/fiber/v3 v3.0.0-beta.3 h1:7Q2I+HsIqnIEEDB+9oe7Gadpakh6ZLhXpTYz/L20vrg=
github.com/gofiber/fiber/v3 v3.0.0-beta.3/go.mod h1:kcMur0Dxqk91R7p4vxEpJfDWZ9u5IfvrtQc8Bvv/JmY=
-github.com/gofiber/utils/v2 v2.0.0-beta.4 h1:1gjbVFFwVwUb9arPcqiB6iEjHBwo7cHsyS41NeIW3co=
-github.com/gofiber/utils/v2 v2.0.0-beta.4/go.mod h1:sdRsPU1FXX6YiDGGxd+q2aPJRMzpsxdzCXo9dz+xtOY=
+github.com/gofiber/utils/v2 v2.0.0-rc.4 h1:CDjwPwtwwj1OTIf6v3iRk+D2wcdjUzwk91Ghu2TMNbE=
+github.com/gofiber/utils/v2 v2.0.0-rc.4/go.mod h1:gXins5o7up+BQFiubmO8aUJc/+Mhd7EKXIiAK5GBomI=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
@@ -92,6 +94,8 @@ github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93Ge
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
+github.com/shamaton/msgpack/v2 v2.4.0 h1:O5Z08MRmbo0lA9o2xnQ4TXx6teJbPqEurqcCOQ8Oi/4=
+github.com/shamaton/msgpack/v2 v2.4.0/go.mod h1:6khjYnkx73f7VQU7wjcFS9DFjs+59naVWJv1TB7qdOI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@@ -103,6 +107,8 @@ github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8
github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
+github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
+github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
diff --git a/backend/services/question-bank-service/go.mod b/backend/services/question-bank-service/go.mod
index 47d4ef1..19ecb7d 100644
--- a/backend/services/question-bank-service/go.mod
+++ b/backend/services/question-bank-service/go.mod
@@ -25,7 +25,7 @@ require (
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.25.0 // indirect
- github.com/gofiber/utils/v2 v2.0.0-beta.4 // indirect
+ github.com/gofiber/utils/v2 v2.0.0-rc.4 // indirect
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
diff --git a/backend/services/question-bank-service/go.sum b/backend/services/question-bank-service/go.sum
index d9556f0..da095cb 100644
--- a/backend/services/question-bank-service/go.sum
+++ b/backend/services/question-bank-service/go.sum
@@ -26,6 +26,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
+github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
+github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -44,8 +46,8 @@ github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofiber/fiber/v3 v3.0.0-beta.3 h1:7Q2I+HsIqnIEEDB+9oe7Gadpakh6ZLhXpTYz/L20vrg=
github.com/gofiber/fiber/v3 v3.0.0-beta.3/go.mod h1:kcMur0Dxqk91R7p4vxEpJfDWZ9u5IfvrtQc8Bvv/JmY=
-github.com/gofiber/utils/v2 v2.0.0-beta.4 h1:1gjbVFFwVwUb9arPcqiB6iEjHBwo7cHsyS41NeIW3co=
-github.com/gofiber/utils/v2 v2.0.0-beta.4/go.mod h1:sdRsPU1FXX6YiDGGxd+q2aPJRMzpsxdzCXo9dz+xtOY=
+github.com/gofiber/utils/v2 v2.0.0-rc.4 h1:CDjwPwtwwj1OTIf6v3iRk+D2wcdjUzwk91Ghu2TMNbE=
+github.com/gofiber/utils/v2 v2.0.0-rc.4/go.mod h1:gXins5o7up+BQFiubmO8aUJc/+Mhd7EKXIiAK5GBomI=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
@@ -94,6 +96,8 @@ github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93Ge
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
+github.com/shamaton/msgpack/v2 v2.4.0 h1:O5Z08MRmbo0lA9o2xnQ4TXx6teJbPqEurqcCOQ8Oi/4=
+github.com/shamaton/msgpack/v2 v2.4.0/go.mod h1:6khjYnkx73f7VQU7wjcFS9DFjs+59naVWJv1TB7qdOI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@@ -105,6 +109,8 @@ github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8
github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
+github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
+github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
diff --git a/backend/services/user-service/go.mod b/backend/services/user-service/go.mod
index c940c23..e5958f3 100644
--- a/backend/services/user-service/go.mod
+++ b/backend/services/user-service/go.mod
@@ -23,7 +23,7 @@ require (
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.25.0 // indirect
- github.com/gofiber/utils/v2 v2.0.0-beta.4 // indirect
+ github.com/gofiber/utils/v2 v2.0.0-rc.4 // indirect
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
diff --git a/backend/services/user-service/go.sum b/backend/services/user-service/go.sum
index 4a51bd3..8959382 100644
--- a/backend/services/user-service/go.sum
+++ b/backend/services/user-service/go.sum
@@ -14,6 +14,8 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
+github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -32,8 +34,8 @@ github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofiber/fiber/v3 v3.0.0-beta.3 h1:7Q2I+HsIqnIEEDB+9oe7Gadpakh6ZLhXpTYz/L20vrg=
github.com/gofiber/fiber/v3 v3.0.0-beta.3/go.mod h1:kcMur0Dxqk91R7p4vxEpJfDWZ9u5IfvrtQc8Bvv/JmY=
-github.com/gofiber/utils/v2 v2.0.0-beta.4 h1:1gjbVFFwVwUb9arPcqiB6iEjHBwo7cHsyS41NeIW3co=
-github.com/gofiber/utils/v2 v2.0.0-beta.4/go.mod h1:sdRsPU1FXX6YiDGGxd+q2aPJRMzpsxdzCXo9dz+xtOY=
+github.com/gofiber/utils/v2 v2.0.0-rc.4 h1:CDjwPwtwwj1OTIf6v3iRk+D2wcdjUzwk91Ghu2TMNbE=
+github.com/gofiber/utils/v2 v2.0.0-rc.4/go.mod h1:gXins5o7up+BQFiubmO8aUJc/+Mhd7EKXIiAK5GBomI=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
@@ -80,6 +82,8 @@ github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoG
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
+github.com/shamaton/msgpack/v2 v2.4.0 h1:O5Z08MRmbo0lA9o2xnQ4TXx6teJbPqEurqcCOQ8Oi/4=
+github.com/shamaton/msgpack/v2 v2.4.0/go.mod h1:6khjYnkx73f7VQU7wjcFS9DFjs+59naVWJv1TB7qdOI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@@ -91,6 +95,8 @@ github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8
github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
+github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
+github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms=
diff --git a/backend/shared/go.mod b/backend/shared/go.mod
index d88306d..593368f 100644
--- a/backend/shared/go.mod
+++ b/backend/shared/go.mod
@@ -34,7 +34,7 @@ require (
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
- github.com/gofiber/utils/v2 v2.0.0-beta.4 // indirect
+ github.com/gofiber/utils/v2 v2.0.0-rc.4 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
diff --git a/backend/shared/go.sum b/backend/shared/go.sum
index 688b25c..1495c84 100644
--- a/backend/shared/go.sum
+++ b/backend/shared/go.sum
@@ -24,6 +24,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
+github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
+github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -42,8 +44,8 @@ github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofiber/fiber/v3 v3.0.0-beta.3 h1:7Q2I+HsIqnIEEDB+9oe7Gadpakh6ZLhXpTYz/L20vrg=
github.com/gofiber/fiber/v3 v3.0.0-beta.3/go.mod h1:kcMur0Dxqk91R7p4vxEpJfDWZ9u5IfvrtQc8Bvv/JmY=
-github.com/gofiber/utils/v2 v2.0.0-beta.4 h1:1gjbVFFwVwUb9arPcqiB6iEjHBwo7cHsyS41NeIW3co=
-github.com/gofiber/utils/v2 v2.0.0-beta.4/go.mod h1:sdRsPU1FXX6YiDGGxd+q2aPJRMzpsxdzCXo9dz+xtOY=
+github.com/gofiber/utils/v2 v2.0.0-rc.4 h1:CDjwPwtwwj1OTIf6v3iRk+D2wcdjUzwk91Ghu2TMNbE=
+github.com/gofiber/utils/v2 v2.0.0-rc.4/go.mod h1:gXins5o7up+BQFiubmO8aUJc/+Mhd7EKXIiAK5GBomI=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
@@ -98,6 +100,8 @@ github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
+github.com/shamaton/msgpack/v2 v2.4.0 h1:O5Z08MRmbo0lA9o2xnQ4TXx6teJbPqEurqcCOQ8Oi/4=
+github.com/shamaton/msgpack/v2 v2.4.0/go.mod h1:6khjYnkx73f7VQU7wjcFS9DFjs+59naVWJv1TB7qdOI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@@ -109,6 +113,8 @@ github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8
github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
+github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
+github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
diff --git a/frontend/apps/web/index.html b/frontend/apps/web/index.html
index 3bcf91c..e9cfd37 100644
--- a/frontend/apps/web/index.html
+++ b/frontend/apps/web/index.html
@@ -1,4 +1,4 @@
-
+
diff --git a/frontend/apps/web/node_modules/.vite/vitest/results.json b/frontend/apps/web/node_modules/.vite/vitest/results.json
index 6266107..bf63381 100644
--- a/frontend/apps/web/node_modules/.vite/vitest/results.json
+++ b/frontend/apps/web/node_modules/.vite/vitest/results.json
@@ -1 +1 @@
-{"version":"1.6.1","results":[[":src/services/validation.test.ts",{"duration":3,"failed":false}],[":src/routes/Results.test.tsx",{"duration":62,"failed":false}],[":src/routes/Leaderboard.test.tsx",{"duration":181,"failed":false}],[":src/routes/Game.test.tsx",{"duration":184,"failed":false}]]}
\ No newline at end of file
+{"version":"1.6.1","results":[[":src/services/validation.test.ts",{"duration":1,"failed":false}],[":src/routes/Results.test.tsx",{"duration":28,"failed":false}],[":src/routes/Leaderboard.test.tsx",{"duration":86,"failed":false}],[":src/routes/Game.test.tsx",{"duration":87,"failed":false}]]}
\ No newline at end of file
diff --git a/frontend/apps/web/src/hooks/useAuth.ts b/frontend/apps/web/src/hooks/useAuth.ts
index 94c9f42..08d880e 100644
--- a/frontend/apps/web/src/hooks/useAuth.ts
+++ b/frontend/apps/web/src/hooks/useAuth.ts
@@ -1,28 +1,33 @@
import { createSignal } from 'solid-js'
const AUTH_TOKEN_KEY = 'kf.auth.token'
+type UseAuthResult = {
+ isAuthenticated: () => boolean
+ signInDemo: () => void
+ signOut: () => void
+}
function readToken(): string | null {
if (typeof window === 'undefined') return null
return window.localStorage.getItem(AUTH_TOKEN_KEY)
}
-export function useAuth() {
+export function useAuth(): UseAuthResult {
const [token, setToken] = createSignal(readToken())
- const signInDemo = () => {
+ const signInDemo = (): void => {
const next = 'demo-token'
window.localStorage.setItem(AUTH_TOKEN_KEY, next)
setToken(next)
}
- const signOut = () => {
+ const signOut = (): void => {
window.localStorage.removeItem(AUTH_TOKEN_KEY)
setToken(null)
}
return {
- isAuthenticated: () => token() != null,
+ isAuthenticated: (): boolean => token() != null,
signInDemo,
signOut,
}
diff --git a/frontend/apps/web/src/hooks/useTimer.ts b/frontend/apps/web/src/hooks/useTimer.ts
index 9cc9530..0a69058 100644
--- a/frontend/apps/web/src/hooks/useTimer.ts
+++ b/frontend/apps/web/src/hooks/useTimer.ts
@@ -1,13 +1,20 @@
-import { createSignal, onCleanup } from 'solid-js'
+import { createSignal, onCleanup, type Accessor } from 'solid-js'
-export function useTimer(durationMs: number) {
+type UseTimerResult = {
+ remainingMs: Accessor
+ isExpired: Accessor
+ start: () => void
+ stop: () => void
+}
+
+export function useTimer(durationMs: number): UseTimerResult {
const [remainingMs, setRemainingMs] = createSignal(durationMs)
const [isExpired, setIsExpired] = createSignal(false)
let t: number | undefined
let startedAt: number | undefined
- const tick = () => {
+ const tick = (): void => {
if (startedAt == null) return
const elapsed = Date.now() - startedAt
const remain = Math.max(0, durationMs - elapsed)
@@ -15,14 +22,14 @@ export function useTimer(durationMs: number) {
if (remain === 0) setIsExpired(true)
}
- const start = () => {
+ const start = (): void => {
if (t != null) return
startedAt = Date.now()
tick()
t = window.setInterval(tick, 250)
}
- const stop = () => {
+ const stop = (): void => {
if (t != null) {
window.clearInterval(t)
t = undefined
diff --git a/frontend/apps/web/src/routes/Game.test.tsx b/frontend/apps/web/src/routes/Game.test.tsx
index f92d281..fb3cb64 100644
--- a/frontend/apps/web/src/routes/Game.test.tsx
+++ b/frontend/apps/web/src/routes/Game.test.tsx
@@ -4,7 +4,7 @@ import { describe, expect, it, vi } from 'vitest'
import GameRoute from './Game'
vi.mock('@solidjs/router', () => ({
- useNavigate: () => vi.fn(),
+ useNavigate: (): ((path: string) => void) => vi.fn(),
}))
describe('GameRoute', () => {
diff --git a/frontend/apps/web/src/routes/Game.tsx b/frontend/apps/web/src/routes/Game.tsx
index 87cdab2..95495c4 100644
--- a/frontend/apps/web/src/routes/Game.tsx
+++ b/frontend/apps/web/src/routes/Game.tsx
@@ -1,5 +1,5 @@
import { useNavigate } from '@solidjs/router'
-import { createEffect, createMemo, createSignal, onMount } from 'solid-js'
+import { createEffect, createMemo, createSignal, onMount, type JSX } from 'solid-js'
import {
AnswerInput,
@@ -35,10 +35,13 @@ function normalizeAnswer(answer: string): string {
return answer.trim().toLowerCase()
}
-async function estimateLeaderboardPosition(score: number, durationSec: number): Promise {
+async function estimateLeaderboardPosition(
+ score: number,
+ durationSec: number
+): Promise {
try {
const rows = await leaderboardClient.top10()
- const sorted = [...rows].sort((a, b) => {
+ const sorted = [...rows].sort((a, b): number => {
if (b.score !== a.score) return b.score - a.score
const durationA = typeof a.durationSec === 'number' ? a.durationSec : Number.MAX_SAFE_INTEGER
const durationB = typeof b.durationSec === 'number' ? b.durationSec : Number.MAX_SAFE_INTEGER
@@ -47,7 +50,8 @@ async function estimateLeaderboardPosition(score: number, durationSec: number):
let rank = 1
for (const row of sorted) {
- const rowDuration = typeof row.durationSec === 'number' ? row.durationSec : Number.MAX_SAFE_INTEGER
+ const rowDuration =
+ typeof row.durationSec === 'number' ? row.durationSec : Number.MAX_SAFE_INTEGER
if (score > row.score) break
if (score === row.score && durationSec < rowDuration) break
rank += 1
@@ -59,7 +63,7 @@ async function estimateLeaderboardPosition(score: number, durationSec: number):
}
}
-export default function GameRoute() {
+export default function GameRoute(): JSX.Element {
const navigate = useNavigate()
const [question] = createSignal(QUESTION)
@@ -74,12 +78,12 @@ export default function GameRoute() {
const startedAt = Date.now()
const { remainingMs, isExpired, start, stop } = useTimer(durationMs)
- onMount(() => start())
+ onMount((): void => start())
- const attemptsLeft = createMemo(() => Math.max(0, 3 - attempts()))
- const answerLocked = createMemo(() => finished() || attemptsLeft() === 0 || isExpired())
+ const attemptsLeft = createMemo((): number => Math.max(0, 3 - attempts()))
+ const answerLocked = createMemo((): boolean => finished() || attemptsLeft() === 0 || isExpired())
- const finalize = async (finalScore: number, answered: number, correct: number) => {
+ const finalize = async (finalScore: number, answered: number, correct: number): Promise => {
if (finished()) return
setFinished(true)
stop()
@@ -106,7 +110,7 @@ export default function GameRoute() {
navigate('/results')
}
- createEffect(() => {
+ createEffect((): void => {
if (isExpired() && !finished()) {
setMessage('Temps écoulé.')
const answered = attempts() > 0 ? 1 : 0
@@ -114,7 +118,7 @@ export default function GameRoute() {
}
})
- const submit = () => {
+ const submit = (): void => {
if (answerLocked()) return
const normalized = normalizeAnswer(answer())
@@ -146,7 +150,7 @@ export default function GameRoute() {
setAnswer('')
}
- const confirmHint = () => {
+ const confirmHint = (): void => {
if (hintUsed() || attempts() > 0 || answerLocked()) return
setHintUsed(true)
setMessage(`Indice: ${question().hint}`)
diff --git a/frontend/apps/web/src/routes/Home.tsx b/frontend/apps/web/src/routes/Home.tsx
index 347d1d1..9745cdd 100644
--- a/frontend/apps/web/src/routes/Home.tsx
+++ b/frontend/apps/web/src/routes/Home.tsx
@@ -1,5 +1,5 @@
import { useNavigate } from '@solidjs/router'
-import { createSignal } from 'solid-js'
+import { createSignal, type JSX } from 'solid-js'
import Box from '@suid/material/Box'
import Button from '@suid/material/Button'
@@ -15,12 +15,12 @@ function readInputValue(event: Event): string {
return (event.target as HTMLInputElement).value
}
-export default function HomeRoute() {
+export default function HomeRoute(): JSX.Element {
const navigate = useNavigate()
const [playerName, setPlayerName] = createSignal('')
const [error, setError] = createSignal(null)
- const start = () => {
+ const start = (): void => {
const name = playerName().trim()
const validationError = validatePlayerName(name)
if (validationError) {
@@ -42,9 +42,7 @@ export default function HomeRoute() {
Bienvenue
-
- Entre ton pseudo et lance une partie.
-
+ Entre ton pseudo et lance une partie.
leaderboardClient.top10())
return (
diff --git a/frontend/apps/web/src/routes/Profile.tsx b/frontend/apps/web/src/routes/Profile.tsx
index 355eb61..66b6377 100644
--- a/frontend/apps/web/src/routes/Profile.tsx
+++ b/frontend/apps/web/src/routes/Profile.tsx
@@ -1,4 +1,4 @@
-import { For, Show, createMemo, createSignal } from 'solid-js'
+import { For, Show, createMemo, createSignal, type JSX } from 'solid-js'
import Box from '@suid/material/Box'
import Button from '@suid/material/Button'
@@ -17,7 +17,7 @@ function readInputValue(event: Event): string {
return (event.target as HTMLInputElement).value
}
-export default function ProfileRoute() {
+export default function ProfileRoute(): JSX.Element {
const { isAuthenticated, signInDemo, signOut } = useAuth()
const [name, setName] = createSignal(localStorage.getItem('kf.playerName') ?? '')
const [showHints, setShowHints] = createSignal(true)
@@ -32,7 +32,7 @@ export default function ProfileRoute() {
return { gamesPlayed, averageScore, bestScore }
})
- const save = () => {
+ const save = (): void => {
localStorage.setItem('kf.playerName', name().trim())
}
@@ -47,7 +47,9 @@ export default function ProfileRoute() {
Profil
- Connexion requise pour accéder au profil joueur.
+
+ Connexion requise pour accéder au profil joueur.
+
@@ -78,13 +80,16 @@ export default function ProfileRoute() {
0}
- fallback={Aucune partie enregistrée.}
+ fallback={
+ Aucune partie enregistrée.
+ }
>
{(item) => (
- Score {item.finalScore} • Réussite {item.successRate}% • Durée {Math.floor(item.durationSec / 60)}m
+ Score {item.finalScore} • Réussite {item.successRate}% • Durée{' '}
+ {Math.floor(item.durationSec / 60)}m
diff --git a/frontend/apps/web/src/routes/Results.test.tsx b/frontend/apps/web/src/routes/Results.test.tsx
index 6cb9b13..e7714b9 100644
--- a/frontend/apps/web/src/routes/Results.test.tsx
+++ b/frontend/apps/web/src/routes/Results.test.tsx
@@ -4,7 +4,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
import ResultsRoute from './Results'
vi.mock('@solidjs/router', () => ({
- useNavigate: () => vi.fn(),
+ useNavigate: (): ((path: string) => void) => vi.fn(),
}))
describe('ResultsRoute', () => {
diff --git a/frontend/apps/web/src/routes/Results.tsx b/frontend/apps/web/src/routes/Results.tsx
index 522b833..f82c5c7 100644
--- a/frontend/apps/web/src/routes/Results.tsx
+++ b/frontend/apps/web/src/routes/Results.tsx
@@ -1,12 +1,12 @@
import { useNavigate } from '@solidjs/router'
-import { createMemo } from 'solid-js'
+import { createMemo, type JSX } from 'solid-js'
import { ResultsCard } from '@knowfoolery/ui-components'
import Box from '@suid/material/Box'
import { loadLastResult } from '../services/session'
-export default function ResultsRoute() {
+export default function ResultsRoute(): JSX.Element {
const navigate = useNavigate()
const result = createMemo(() => loadLastResult())
diff --git a/frontend/apps/web/src/services/validation.test.ts b/frontend/apps/web/src/services/validation.test.ts
index 3d3749a..e00c9ad 100644
--- a/frontend/apps/web/src/services/validation.test.ts
+++ b/frontend/apps/web/src/services/validation.test.ts
@@ -12,6 +12,8 @@ describe('validatePlayerName', () => {
})
it('rejects non alphanumeric characters', () => {
- expect(validatePlayerName('Player@42')).toBe('Le nom doit contenir seulement lettres, chiffres et espaces')
+ expect(validatePlayerName('Player@42')).toBe(
+ 'Le nom doit contenir seulement lettres, chiffres et espaces'
+ )
})
})
diff --git a/frontend/apps/web/src/services/validation.ts b/frontend/apps/web/src/services/validation.ts
index 887624a..3b78e9e 100644
--- a/frontend/apps/web/src/services/validation.ts
+++ b/frontend/apps/web/src/services/validation.ts
@@ -4,6 +4,7 @@ export function validatePlayerName(value: string): string | null {
const name = value.trim()
if (name.length < 2) return 'Le nom doit faire au moins 2 caractères'
if (name.length > 50) return 'Le nom doit faire au plus 50 caractères'
- if (!PLAYER_NAME_REGEX.test(name)) return 'Le nom doit contenir seulement lettres, chiffres et espaces'
+ if (!PLAYER_NAME_REGEX.test(name))
+ return 'Le nom doit contenir seulement lettres, chiffres et espaces'
return null
}
diff --git a/frontend/apps/web/src/styles/global.css b/frontend/apps/web/src/styles/global.css
index 92e5758..0218d70 100644
--- a/frontend/apps/web/src/styles/global.css
+++ b/frontend/apps/web/src/styles/global.css
@@ -1,6 +1,14 @@
:root {
color-scheme: dark;
- font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, 'Apple Color Emoji',
+ font-family:
+ ui-sans-serif,
+ system-ui,
+ -apple-system,
+ Segoe UI,
+ Roboto,
+ Helvetica,
+ Arial,
+ 'Apple Color Emoji',
'Segoe UI Emoji';
}
diff --git a/frontend/shared/ui-components/node_modules/.vite/vitest/results.json b/frontend/shared/ui-components/node_modules/.vite/vitest/results.json
index 929932b..f5df778 100644
--- a/frontend/shared/ui-components/node_modules/.vite/vitest/results.json
+++ b/frontend/shared/ui-components/node_modules/.vite/vitest/results.json
@@ -1 +1 @@
-{"version":"1.6.1","results":[[":src/utils/timer.test.ts",{"duration":7,"failed":false}],[":src/components/AttemptIndicator.test.tsx",{"duration":24,"failed":false}],[":src/components/ResultsCard.test.tsx",{"duration":96,"failed":false}],[":src/components/LeaderboardTable.test.tsx",{"duration":38,"failed":false}],[":src/components/AnswerInput.test.tsx",{"duration":58,"failed":false}],[":src/components/HintButton.test.tsx",{"duration":115,"failed":false}]]}
\ No newline at end of file
+{"version":"1.6.1","results":[[":src/utils/timer.test.ts",{"duration":1,"failed":false}],[":src/components/AttemptIndicator.test.tsx",{"duration":19,"failed":false}],[":src/components/ResultsCard.test.tsx",{"duration":66,"failed":false}],[":src/components/LeaderboardTable.test.tsx",{"duration":28,"failed":false}],[":src/components/AnswerInput.test.tsx",{"duration":36,"failed":false}],[":src/components/HintButton.test.tsx",{"duration":68,"failed":false}]]}
\ No newline at end of file
diff --git a/frontend/shared/ui-components/src/components/AttemptIndicator.tsx b/frontend/shared/ui-components/src/components/AttemptIndicator.tsx
index db1f727..ae682b3 100644
--- a/frontend/shared/ui-components/src/components/AttemptIndicator.tsx
+++ b/frontend/shared/ui-components/src/components/AttemptIndicator.tsx
@@ -12,10 +12,11 @@ export type AttemptIndicatorProps = {
}
const AttemptIndicator: Component = (props) => {
- const attemptsMax = () => Math.max(1, props.attemptsMax ?? 3)
- const used = () => Math.max(0, Math.min(props.attemptsUsed, attemptsMax()))
- const remaining = () => Math.max(0, attemptsMax() - used())
- const formatRemaining = () => props.remainingFormatter?.(remaining()) ?? `${remaining()} restant(s)`
+ const attemptsMax = (): number => Math.max(1, props.attemptsMax ?? 3)
+ const used = (): number => Math.max(0, Math.min(props.attemptsUsed, attemptsMax()))
+ const remaining = (): number => Math.max(0, attemptsMax() - used())
+ const formatRemaining = (): string =>
+ props.remainingFormatter?.(remaining()) ?? `${remaining()} restant(s)`
return (
diff --git a/frontend/shared/ui-components/src/components/HintButton.test.tsx b/frontend/shared/ui-components/src/components/HintButton.test.tsx
index a834b22..0a2d9c9 100644
--- a/frontend/shared/ui-components/src/components/HintButton.test.tsx
+++ b/frontend/shared/ui-components/src/components/HintButton.test.tsx
@@ -16,7 +16,9 @@ describe('HintButton', () => {
await fireEvent.click(screen.getByRole('button', { name: 'Indice (score réduit)' }))
expect(screen.getByText("Confirmer l'indice")).toBeTruthy()
- await fireEvent.click(screen.getByRole('button', { name: 'Oui, utiliser un indice', hidden: true }))
+ await fireEvent.click(
+ screen.getByRole('button', { name: 'Oui, utiliser un indice', hidden: true })
+ )
expect(onConfirm).toHaveBeenCalledTimes(1)
})
})
diff --git a/frontend/shared/ui-components/src/components/HintButton.tsx b/frontend/shared/ui-components/src/components/HintButton.tsx
index ffb22cf..0794a70 100644
--- a/frontend/shared/ui-components/src/components/HintButton.tsx
+++ b/frontend/shared/ui-components/src/components/HintButton.tsx
@@ -21,7 +21,7 @@ export type HintButtonProps = {
const HintButton: Component = (props) => {
const [dialogOpen, setDialogOpen] = createSignal(false)
- const handleClick = () => {
+ const handleClick = (): void => {
if (props.disabled) return
if (props.requiresConfirmation === false) {
@@ -32,7 +32,7 @@ const HintButton: Component = (props) => {
setDialogOpen(true)
}
- const confirm = () => {
+ const confirm = (): void => {
setDialogOpen(false)
props.onConfirm()
}
@@ -44,10 +44,11 @@ const HintButton: Component = (props) => {