chore: remove nxg-fix-cors.md, add docker-swagger-fix.md plan
This commit is contained in:
@@ -0,0 +1,146 @@
|
|||||||
|
# Docker Build Fix — Swagger docs.go Not Found
|
||||||
|
|
||||||
|
## TL;DR
|
||||||
|
|
||||||
|
> **Quick Summary**: The Swagger-generated file `docs/docs.go` is `.gitignore`-d, so Docker build fails with `no required module provides package .../docs`. Fix: add `swag init` step in the Dockerfile builder stage so docs are generated during build before compilation.
|
||||||
|
>
|
||||||
|
> **Deliverables**:
|
||||||
|
> - Dockerfile updated with `swag init` before `go build`
|
||||||
|
> - Docker build succeeds without error
|
||||||
|
>
|
||||||
|
> **Estimated Effort**: Trivial (single-line addition)
|
||||||
|
> **Parallel Execution**: N/A (single task)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
### Original Request
|
||||||
|
Docker build fails with:
|
||||||
|
```
|
||||||
|
main.go:17:2: no required module provides package git.datadunia.com/nexusguard/nexus-server-core/docs
|
||||||
|
```
|
||||||
|
|
||||||
|
Root cause: `apps/server-core/.gitignore` (lines 40-43) ignores `docs/docs.go`, `docs/swagger.json`, `docs/swagger.yaml`. These files were generated locally by `swag init` but are gitignored. When `docker build` runs `COPY . .`, these files are not included, so the Go compilation fails because `main.go` has `_ "git.datadunia.com/nexusguard/nexus-server-core/docs"`.
|
||||||
|
|
||||||
|
### Metis Analysis
|
||||||
|
- Must pin swag CLI version to match `go.mod`: `v1.16.6`
|
||||||
|
- Must keep `.gitignore` as-is (generated files should not be tracked)
|
||||||
|
- No other files cause similar issues — audit confirmed
|
||||||
|
- Build tag approach is unnecessary complexity
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Work Objectives
|
||||||
|
|
||||||
|
### Core Objective
|
||||||
|
Make Docker build succeed with Swagger docs generated during build process.
|
||||||
|
|
||||||
|
### Must Have
|
||||||
|
- [ ] `apps/server-core/Dockerfile` runs `swag init` before `go build`
|
||||||
|
- [ ] `swag init` uses pinned CLI version matching `go.mod` (`v1.16.6`)
|
||||||
|
- [ ] `docker compose build server-core` passes
|
||||||
|
|
||||||
|
### Must NOT Have
|
||||||
|
- Do NOT remove swagger files from `.gitignore`
|
||||||
|
- Do NOT restructure `main.go` with build tags
|
||||||
|
- Do NOT modify Makefile or any other files
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Execution Strategy
|
||||||
|
|
||||||
|
Single task, no waves needed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TODOs
|
||||||
|
|
||||||
|
- [ ] 1. Fix Dockerfile — Add `swag init` in builder stage
|
||||||
|
|
||||||
|
**What to do**:
|
||||||
|
- Edit `apps/server-core/Dockerfile`
|
||||||
|
- Between `COPY . .` and `RUN CGO_ENABLED=0 go build -o /app/server-core .`, add:
|
||||||
|
```dockerfile
|
||||||
|
RUN go install github.com/swaggo/swag/cmd/swag@v1.16.6 && swag init -g main.go --parseDependency --parseInternal
|
||||||
|
```
|
||||||
|
- This runs `swag` CLI pinned to v1.16.6 (matching `go.mod`), generates `docs/docs.go`, then Go compliation finds the package.
|
||||||
|
|
||||||
|
**Final Dockerfile should look like:**
|
||||||
|
```dockerfile
|
||||||
|
# Stage 1: Builder
|
||||||
|
FROM golang:1.25-alpine AS builder
|
||||||
|
WORKDIR /app
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
COPY . .
|
||||||
|
RUN go install github.com/swaggo/swag/cmd/swag@v1.16.6 && swag init -g main.go --parseDependency --parseInternal
|
||||||
|
RUN CGO_ENABLED=0 go build -o /app/server-core .
|
||||||
|
```
|
||||||
|
|
||||||
|
**Recommended Agent Profile**:
|
||||||
|
- **Category**: `quick`
|
||||||
|
- **Skills**: `[]`
|
||||||
|
|
||||||
|
**Parallelization**: Single task
|
||||||
|
|
||||||
|
**References**:
|
||||||
|
- `apps/server-core/Dockerfile` — Current Dockerfile (multi-stage, golang:1.25-alpine)
|
||||||
|
- `apps/server-core/.gitignore:40-43` — Lines that gitignore swagger output
|
||||||
|
- `apps/server-core/main.go:17` — Import of `_ "docs"` package
|
||||||
|
|
||||||
|
**Acceptance Criteria**:
|
||||||
|
- [ ] `docker build -f apps/server-core/Dockerfile -t test-fix apps/server-core` succeeds (exit 0)
|
||||||
|
- [ ] Swagger route `/swagger/index.html` works when container runs
|
||||||
|
|
||||||
|
**QA Scenarios**:
|
||||||
|
|
||||||
|
```
|
||||||
|
Scenario: Docker build succeeds with swagger docs generated
|
||||||
|
Tool: Bash
|
||||||
|
Preconditions: Docker is installed, at project root
|
||||||
|
Steps:
|
||||||
|
1. docker build -f apps/server-core/Dockerfile -t nexusguard-server-core apps/server-core
|
||||||
|
2. echo "Exit: $?"
|
||||||
|
Expected Result: Build completes without errors (exit 0)
|
||||||
|
Failure Indicators: Error about missing docs package
|
||||||
|
Evidence: .sisyphus/evidence/task-1-docker-build-success.txt
|
||||||
|
|
||||||
|
Scenario: Make not installed — fallback works
|
||||||
|
Tool: Bash
|
||||||
|
Preconditions: make is NOT installed (simulate with `which make || true`)
|
||||||
|
Steps:
|
||||||
|
1. docker compose build server-core
|
||||||
|
2. docker compose up -d
|
||||||
|
Expected Result: Services start without requiring `make`
|
||||||
|
Failure Indicators: `make: command not found` blocks deployment
|
||||||
|
Evidence: .sisyphus/evidence/task-1-direct-docker-compose.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Final Verification
|
||||||
|
|
||||||
|
- [ ] F1. **Verify Docker Build** — Run `docker build` and confirm exit 0
|
||||||
|
- [ ] F2. **Verify Swagger** — Start container, `curl http://localhost:8080/swagger/index.html` returns 200
|
||||||
|
- [ ] F3. **Verify Clean Environment** — Simulate fresh clone + build
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Commit Strategy
|
||||||
|
|
||||||
|
- **1**: `fix(server-core): generate swagger docs in Docker build step`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Success Criteria
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Fix: Docker build
|
||||||
|
docker build -f apps/server-core/Dockerfile -t nexusguard-server-core apps/server-core
|
||||||
|
# Expected: Build successful, exit 0
|
||||||
|
|
||||||
|
# Verify no more make dependency
|
||||||
|
docker compose build server-core && docker compose up -d
|
||||||
|
# Expected: Services start
|
||||||
|
```
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
# Plan: Fix CORS Configuration
|
|
||||||
|
|
||||||
**Scope**: Trivial — 3 files, ~20 lines
|
|
||||||
**Goal**: Ensure server-core CORS properly accepts requests from frontend origins, configurable via `CORS_ALLOWED_ORIGINS` env var, documented in `.env.example`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Context
|
|
||||||
|
|
||||||
Current CORS config in `main.go:114-130`:
|
|
||||||
- Uses `CORS_ALLOWED_ORIGINS` env var (defaults to `*`)
|
|
||||||
- Has BOTH `AllowOrigins` AND `AllowOriginFunc` — redundant
|
|
||||||
- `strings.Contains(corsOrigins, origin)` is weak (substring match: `"example.com"` matches `"notexample.com"`)
|
|
||||||
- `AllowCredentials: true` is needed for JWT `Authorization` header
|
|
||||||
- `CORS_ALLOWED_ORIGINS` is NOT documented in any `.env.example` file
|
|
||||||
- `SHARE_LINK_TTL` (from Phase 5.0) also missing from `.env.example`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Task 1: Fix CORS config in `main.go`
|
|
||||||
- [x] **File**: `apps/server-core/main.go` lines 114-130
|
|
||||||
|
|
||||||
**Replace** the current CORS block with:
|
|
||||||
|
|
||||||
```go
|
|
||||||
// CORS Configuration
|
|
||||||
corsOrigins := os.Getenv("CORS_ALLOWED_ORIGINS")
|
|
||||||
if corsOrigins == "" {
|
|
||||||
corsOrigins = "*"
|
|
||||||
}
|
|
||||||
|
|
||||||
corsConfig := cors.Config{
|
|
||||||
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"},
|
|
||||||
AllowHeaders: []string{"Origin", "Content-Length", "Content-Type", "Authorization", "X-Admin-Key", "X-Device-Token"},
|
|
||||||
ExposeHeaders: []string{"Content-Length"},
|
|
||||||
AllowCredentials: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
if corsOrigins == "*" {
|
|
||||||
// Wildcard: allow all origins but use AllowOriginFunc so the response
|
|
||||||
// header echoes the actual origin (required when AllowCredentials=true).
|
|
||||||
corsConfig.AllowOriginFunc = func(origin string) bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Explicit list: split by comma, trim spaces, exact match only.
|
|
||||||
origins := strings.Split(corsOrigins, ",")
|
|
||||||
for i := range origins {
|
|
||||||
origins[i] = strings.TrimSpace(origins[i])
|
|
||||||
}
|
|
||||||
corsConfig.AllowOrigins = origins
|
|
||||||
}
|
|
||||||
|
|
||||||
r.Use(cors.New(corsConfig))
|
|
||||||
```
|
|
||||||
|
|
||||||
**Key changes**:
|
|
||||||
1. Remove simultaneous `AllowOrigins` + `AllowOriginFunc` (pick one based on `*` vs explicit)
|
|
||||||
2. When `*`: use `AllowOriginFunc` returning `true` → gin-contrib/cors echoes the requesting origin (compatible with `AllowCredentials: true`)
|
|
||||||
3. When explicit: use `AllowOrigins` with trimmed values, exact match (no more `strings.Contains` substring bug)
|
|
||||||
|
|
||||||
**Verify**: `go build ./...` passes
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Task 2: Add `CORS_ALLOWED_ORIGINS` to root `.env.example`
|
|
||||||
- [x] **File**: `.env.example`
|
|
||||||
|
|
||||||
**Add** after `VITE_API_BASE_URL` line (section 5):
|
|
||||||
|
|
||||||
```env
|
|
||||||
# 7. CORS Configuration
|
|
||||||
# Comma-separated list of allowed origins for the API.
|
|
||||||
# Use '*' to allow all origins (NOT recommended for production).
|
|
||||||
# Example: https://dash.yourdomain.com,https://admin.yourdomain.com
|
|
||||||
CORS_ALLOWED_ORIGINS=http://localhost:5173
|
|
||||||
|
|
||||||
# 8. Share Link Configuration
|
|
||||||
# TTL for peer config share links (Go duration format)
|
|
||||||
SHARE_LINK_TTL=24h
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Task 3: Add `CORS_ALLOWED_ORIGINS` to server-core `.env.example`
|
|
||||||
- [x] **File**: `apps/server-core/.env.example`
|
|
||||||
|
|
||||||
**Add** at the end:
|
|
||||||
|
|
||||||
```env
|
|
||||||
# CORS
|
|
||||||
# Comma-separated allowed origins. '*' = allow all (not recommended for production)
|
|
||||||
CORS_ALLOWED_ORIGINS=http://localhost:5173
|
|
||||||
|
|
||||||
# Share Link TTL (Go duration format)
|
|
||||||
SHARE_LINK_TTL=24h
|
|
||||||
```
|
|
||||||
|
|
||||||
**Verify**: all `.env.example` files contain `CORS_ALLOWED_ORIGINS`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Final Verification Wave
|
|
||||||
|
|
||||||
- [x] `go build ./...` passes in `apps/server-core/`
|
|
||||||
- [x] `CORS_ALLOWED_ORIGINS` present in root `.env.example`
|
|
||||||
- [x] `CORS_ALLOWED_ORIGINS` present in `apps/server-core/.env.example`
|
|
||||||
- [x] No other files reference `CORS_ALLOWED_ORIGINS` that need updating
|
|
||||||
Reference in New Issue
Block a user