chore: test change

This commit is contained in:
calvogenerico 2026-10-12 16:34:29 -03:00
parent 8143ba02b0
commit 0955919a69
No known key found for this signature in database
GPG Key ID: BE83635D98A8D359
28 changed files with 110 additions and 70 deletions

2
.gitignore vendored
View File

@ -1,7 +1,7 @@
node_modules/ node_modules/
dist/ dist/
coverage/ coverage/
backend/bin/ server/bin/
.env .env
.env.* .env.*
!.env.example !.env.example

29
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,29 @@
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS'
when: never
- if: '$CI_PIPELINE_SOURCE == "push"'
stages:
- test
server:
stage: test
# The Debian image includes the C compiler needed by Go's race detector.
image: golang:1.27.2
script:
- cd server
- go vet ./...
- go test -race ./...
webapp:
stage: test
image: node:24
before_script:
- npm install --global pnpm@10.28.2
- cd webapp
- pnpm install --frozen-lockfile
script:
- pnpm check
- pnpm test

View File

@ -1,6 +1,6 @@
# Subalineado # Subalineado
Go API and SolidJS + TypeScript frontend in one repository. No database is required. Go API and SolidJS + TypeScript webapp in one repository. No database is required.
## Start in development ## Start in development
@ -19,7 +19,7 @@ Ctrl+C stops both services; remove their containers with:
task dev:down task dev:down
``` ```
Compose Watch syncs frontend source into Vite for hot reload and rebuilds the Go service on changes. Dependency and Vite configuration changes rebuild the frontend. Go module and compilation caches persist through BuildKit cache mounts. After a broken Go build, fix and save the source to trigger another build. Dockerfile changes require restarting with `--build`. Compose Watch syncs webapp source into Vite for hot reload and rebuilds the Go service on changes. Dependency and Vite configuration changes rebuild the webapp. Go module and compilation caches persist through BuildKit cache mounts. After a broken Go build, fix and save the source to trigger another build. Dockerfile changes require restarting with `--build`.
## Discover and extend commands ## Discover and extend commands
@ -29,21 +29,21 @@ task --list # Same list, explicitly
task --summary dev # Read usage details for development task --summary dev # Read usage details for development
task dev:status # See running services task dev:status # See running services
task dev:logs # Follow their logs task dev:logs # Follow their logs
task install # Install native Go and frontend dependencies task install # Install native Go and webapp dependencies
task check # Go vet, Biome and TypeScript checks task check # Go vet, Biome and TypeScript checks
task test # Go race tests and Vitest tests task test # Go race tests and Vitest tests
task format # Go formatting and safe Biome fixes task format # Go formatting and safe Biome fixes
task build # Build both production Docker images task build # Build both production Docker images
``` ```
`install`, `check`, `test`, and `format` use your native Go/Node/pnpm tools. `dev`, `dev:*`, and `build` use Docker. Individual commands such as `task backend:test` and `task frontend:check` are also listed. Tasks stop when a command fails. `install`, `check`, `test`, and `format` use your native Go/Node/pnpm tools. `dev`, `dev:*`, and `build` use Docker. Individual commands such as `task server:test` and `task webapp:check` are also listed. Tasks stop when a command fails.
All commands live in the root `Taskfile.yml`. Add a named task with `desc` and `cmds`; use `dir` for commands in a service directory and `summary` for detailed usage. Task finds the file from repository subdirectories too. All commands live in the root `Taskfile.yml`. Add a named task with `desc` and `cmds`; use `dir` for commands in a service directory and `summary` for detailed usage. Task finds the file from repository subdirectories too.
```yaml ```yaml
frontend:build: webapp:build:
desc: Build the frontend locally desc: Build the webapp locally
dir: frontend dir: webapp
cmds: cmds:
- pnpm build - pnpm build
``` ```
@ -60,7 +60,7 @@ docker compose -f compose.yaml -f compose.dev.yaml up --build --watch
docker compose up --build -d --wait docker compose up --build -d --wait
``` ```
Open http://localhost:3000. Nginx serves the compiled frontend and proxies `/api/*` and `/health` to Go. Both runtime containers run as non-root users and expose health checks. Ports bind to loopback for local use. Open http://localhost:3000. Nginx serves the compiled webapp and proxies `/api/*` and `/health` to Go. Both runtime containers run as non-root users and expose health checks. Ports bind to loopback for local use.
```sh ```sh
docker compose down docker compose down
@ -73,7 +73,7 @@ Use Node **24**, pnpm **10.28.2**, and Go **1.27.2**. `.tool-versions` pins the
In one terminal: In one terminal:
```sh ```sh
cd backend cd server
go mod download go mod download
go run ./cmd/api go run ./cmd/api
``` ```
@ -81,26 +81,26 @@ go run ./cmd/api
In another: In another:
```sh ```sh
cd frontend cd webapp
pnpm install --frozen-lockfile pnpm install --frozen-lockfile
pnpm dev pnpm dev
``` ```
Native Go development requires restarting `go run` after edits; Compose Watch automates this in the container workflow. Native Go development requires restarting `go run` after edits; Compose Watch automates this in the container workflow.
Backend checks: Server checks:
```sh ```sh
cd backend cd server
go test -race ./... go test -race ./...
go vet ./... go vet ./...
go build -o bin/api ./cmd/api go build -o bin/api ./cmd/api
``` ```
Frontend checks: Webapp checks:
```sh ```sh
cd frontend cd webapp
pnpm check pnpm check
pnpm test pnpm test
pnpm build pnpm build
@ -108,11 +108,20 @@ pnpm build
`pnpm format` applies Biome formatting and safe fixes; `pnpm test:watch` runs Vitest interactively. `pnpm format` applies Biome formatting and safe fixes; `pnpm test:watch` runs Vitest interactively.
## Continuous integration
`.gitlab-ci.yml` runs two jobs in parallel on every push and merge request:
- Server: `go vet ./...` and `go test -race ./...` with Go 1.27.2.
- Webapp: `pnpm check` (Biome and TypeScript) and `pnpm test` (Vitest) with Node 24 and pnpm 10.28.2. Dependencies use the frozen lockfile.
When a branch has an open merge request, its pushes run the merge request pipeline instead of a duplicate branch pipeline. All checks run even for documentation-only changes. A GitLab runner supporting container images (Docker or Kubernetes executor) must be available to the project; no deployment credentials are needed.
## Structure and API ## Structure and API
- `backend/cmd/api`: process startup, HTTP timeouts, signal handling and graceful shutdown. - `server/cmd/api`: process startup, HTTP timeouts, signal handling and graceful shutdown.
- `backend/internal/httpapi`: router, HTTP handlers and endpoint tests. - `server/internal/httpapi`: router, HTTP handlers and endpoint tests.
- `frontend/src`: page, typed API client and component tests. - `webapp/src`: page, typed API client and component tests.
- `Taskfile.yml`: discoverable development, dependency, formatting and verification commands. - `Taskfile.yml`: discoverable development, dependency, formatting and verification commands.
- `compose.yaml`: production images and service dependencies. - `compose.yaml`: production images and service dependencies.
- `compose.dev.yaml`: development overrides and file-watch rules. - `compose.dev.yaml`: development overrides and file-watch rules.
@ -122,7 +131,9 @@ pnpm build
| `GET /health` | `200 {"status":"ok"}` | | `GET /health` | `200 {"status":"ok"}` |
| `GET /api/test` | `200 {"message":"API connection successful"}` | | `GET /api/test` | `200 {"message":"API connection successful"}` |
Responses use `application/json`. Other methods return 405; unknown routes return 404. `HTTP_ADDR` configures the API listener (default `:8080`). Vite reads `API_PROXY_TARGET` (default `http://localhost:8080`); Compose sets it to the backend service. This is a server-side proxy setting, not a browser URL. Responses use `application/json`. Other methods return 405; unknown routes return 404. `HTTP_ADDR` configures the API listener (default `:8080`). Vite reads `API_PROXY_TARGET` (default `http://localhost:8080`); Compose sets it to the server service. This is a server-side proxy setting, not a browser URL.
## Tooling choices ## Tooling choices

View File

@ -14,8 +14,8 @@ tasks:
dev: dev:
desc: Start both services with hot reload desc: Start both services with hot reload
summary: | summary: |
Build and start the API and frontend with Compose Watch. Build and start the API and webapp with Compose Watch.
Frontend: http://localhost:5173; API: http://localhost:8080. Webapp: http://localhost:5173; API: http://localhost:8080.
Ctrl+C stops the services. Run task dev:down to remove containers. Ctrl+C stops the services. Run task dev:down to remove containers.
Override occupied ports with API_PORT=18080 DEV_WEB_PORT=15173 task dev. Override occupied ports with API_PORT=18080 DEV_WEB_PORT=15173 task dev.
Requires Docker Compose 2.32+; native Go, Node and pnpm are unnecessary. Requires Docker Compose 2.32+; native Go, Node and pnpm are unnecessary.
@ -38,22 +38,22 @@ tasks:
- '{{.DEV_COMPOSE}} ps' - '{{.DEV_COMPOSE}} ps'
install: install:
desc: Download native backend and frontend dependencies desc: Download native server and webapp dependencies
cmds: cmds:
- task: backend:install - task: server:install
- task: frontend:install - task: webapp:install
check: check:
desc: Check Go code, frontend linting and TypeScript types desc: Check Go code, webapp linting and TypeScript types
cmds: cmds:
- task: backend:check - task: server:check
- task: frontend:check - task: webapp:check
test: test:
desc: Run backend race tests and frontend component tests desc: Run server race tests and webapp component tests
cmds: cmds:
- task: backend:test - task: server:test
- task: frontend:test - task: webapp:test
build: build:
desc: Build both production Docker images desc: Build both production Docker images
@ -63,53 +63,53 @@ tasks:
format: format:
desc: Format Go code and apply safe Biome fixes desc: Format Go code and apply safe Biome fixes
cmds: cmds:
- task: backend:format - task: server:format
- task: frontend:format - task: webapp:format
backend:install: server:install:
desc: Download Go modules desc: Download Go modules
dir: backend dir: server
cmds: cmds:
- go mod download - go mod download
backend:check: server:check:
desc: Run Go vet desc: Run Go vet
dir: backend dir: server
cmds: cmds:
- go vet ./... - go vet ./...
backend:test: server:test:
desc: Run Go tests with race detection desc: Run Go tests with race detection
dir: backend dir: server
cmds: cmds:
- go test -race ./... - go test -race ./...
backend:format: server:format:
desc: Format backend Go source desc: Format server Go source
dir: backend dir: server
cmds: cmds:
- go fmt ./... - go fmt ./...
frontend:install: webapp:install:
desc: Install frontend dependencies from the lockfile desc: Install webapp dependencies from the lockfile
dir: frontend dir: webapp
cmds: cmds:
- pnpm install --frozen-lockfile - pnpm install --frozen-lockfile
frontend:check: webapp:check:
desc: Run Biome and TypeScript checks desc: Run Biome and TypeScript checks
dir: frontend dir: webapp
cmds: cmds:
- pnpm check - pnpm check
frontend:test: webapp:test:
desc: Run Vitest component tests desc: Run Vitest component tests
dir: frontend dir: webapp
cmds: cmds:
- pnpm test - pnpm test
frontend:format: webapp:format:
desc: Apply Biome formatting and safe fixes desc: Apply Biome formatting and safe fixes
dir: frontend dir: webapp
cmds: cmds:
- pnpm format - pnpm format

View File

@ -1,36 +1,36 @@
services: services:
backend: server:
develop: develop:
watch: watch:
- action: rebuild - action: rebuild
path: ./backend path: ./server
ignore: ignore:
- bin/ - bin/
- "**/*_test.go" - "**/*_test.go"
frontend: webapp:
build: build:
target: dev target: dev
ports: !override ports: !override
- "127.0.0.1:${DEV_WEB_PORT:-5173}:5173" - "127.0.0.1:${DEV_WEB_PORT:-5173}:5173"
environment: environment:
API_PROXY_TARGET: http://backend:8080 API_PROXY_TARGET: http://server:8080
healthcheck: healthcheck:
test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:5173').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"] test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:5173').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
develop: develop:
watch: watch:
- action: sync - action: sync
path: ./frontend/src path: ./webapp/src
target: /app/src target: /app/src
initial_sync: true initial_sync: true
- action: sync - action: sync
path: ./frontend/index.html path: ./webapp/index.html
target: /app/index.html target: /app/index.html
initial_sync: true initial_sync: true
- action: rebuild - action: rebuild
path: ./frontend/package.json path: ./webapp/package.json
- action: rebuild - action: rebuild
path: ./frontend/pnpm-lock.yaml path: ./webapp/pnpm-lock.yaml
- action: rebuild - action: rebuild
path: ./frontend/vite.config.ts path: ./webapp/vite.config.ts
- action: rebuild - action: rebuild
path: ./frontend/tsconfig.json path: ./webapp/tsconfig.json

View File

@ -1,8 +1,8 @@
name: subalineado name: subalineado
services: services:
backend: server:
build: build:
context: ./backend context: ./server
target: runtime target: runtime
ports: ports:
- "127.0.0.1:${API_PORT:-8080}:8080" - "127.0.0.1:${API_PORT:-8080}:8080"
@ -10,13 +10,13 @@ services:
HTTP_ADDR: ":8080" HTTP_ADDR: ":8080"
init: true init: true
stop_grace_period: 15s stop_grace_period: 15s
frontend: webapp:
build: build:
context: ./frontend context: ./webapp
target: runtime target: runtime
ports: ports:
- "127.0.0.1:${WEB_PORT:-3000}:8080" - "127.0.0.1:${WEB_PORT:-3000}:8080"
depends_on: depends_on:
backend: server:
condition: service_healthy condition: service_healthy
init: true init: true

View File

@ -7,7 +7,7 @@ import (
"net/http" "net/http"
"os" "os"
"os/signal" "os/signal"
"subalineado/backend/internal/httpapi" "subalineado/server/internal/httpapi"
"syscall" "syscall"
"time" "time"
) )

View File

@ -1,4 +1,4 @@
module subalineado/backend module subalineado/server
go 1.27.2 go 1.27.2

View File

@ -5,12 +5,12 @@ server {
index index.html; index index.html;
location /api/ { location /api/ {
proxy_pass http://backend:8080; proxy_pass http://server:8080;
proxy_set_header Host $host; proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
} }
location = /health { location = /health {
proxy_pass http://backend:8080; proxy_pass http://server:8080;
} }
location / { location / {
try_files $uri $uri/ /index.html; try_files $uri $uri/ /index.html;

View File

@ -1,5 +1,5 @@
{ {
"name": "subalineado-frontend", "name": "subalineado-webapp",
"private": true, "private": true,
"version": "0.1.0", "version": "0.1.0",
"type": "module", "type": "module",