chore: test change
This commit is contained in:
parent
8143ba02b0
commit
0955919a69
2
.gitignore
vendored
2
.gitignore
vendored
@ -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
29
.gitlab-ci.yml
Normal 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
|
||||||
47
README.md
47
README.md
@ -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
|
||||||
|
|
||||||
|
|||||||
62
Taskfile.yml
62
Taskfile.yml
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
10
compose.yaml
10
compose.yaml
@ -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
|
||||||
|
|||||||
@ -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"
|
||||||
)
|
)
|
||||||
@ -1,4 +1,4 @@
|
|||||||
module subalineado/backend
|
module subalineado/server
|
||||||
|
|
||||||
go 1.27.2
|
go 1.27.2
|
||||||
|
|
||||||
@ -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;
|
||||||
@ -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",
|
||||||
Loading…
x
Reference in New Issue
Block a user