fix(monitor): pick conflict-free host ports (8432/5432/4432/6432/3432); JWT keygen-on-boot, healthcheck path, baseline migration; ignore frontend/.pnpm-store; pre-commit excludes

This commit is contained in:
CarterPerez-dev 2026-05-01 20:13:00 -04:00
parent ecaacc48fa
commit 92202b1c16
11 changed files with 107 additions and 14 deletions

View File

@ -164,12 +164,22 @@ repos:
rev: v6.0.0
hooks:
- id: check-yaml
exclude: (\.pnpm-store|node_modules)/
- id: check-json
exclude: (\.pnpm-store|node_modules)/
- id: check-toml
exclude: (\.pnpm-store|node_modules)/
- id: check-ast
exclude: (\.pnpm-store|node_modules|\.venv)/
- id: check-symlinks
exclude: (\.pnpm-store|node_modules)/
- id: end-of-file-fixer
exclude: (\.pnpm-store|node_modules)/
- id: trailing-whitespace
exclude: (\.pnpm-store|node_modules)/
- id: check-illegal-windows-names
exclude: (\.pnpm-store|node_modules)/
- id: check-executables-have-shebangs
exclude: (\.pnpm-store|node_modules)/
- id: check-shebang-scripts-are-executable
exclude: (\.pnpm-store|node_modules)/

View File

@ -2,13 +2,13 @@
# .env.example
APP_NAME=monitor
PUBLIC_URL=http://localhost:8430
PUBLIC_URL=http://localhost:8432
NGINX_HOST_PORT=8430
BACKEND_HOST_PORT=5430
FRONTEND_HOST_PORT=3430
POSTGRES_HOST_PORT=5431
REDIS_HOST_PORT=6430
NGINX_HOST_PORT=8432
BACKEND_HOST_PORT=5432
FRONTEND_HOST_PORT=3432
POSTGRES_HOST_PORT=4432
REDIS_HOST_PORT=6432
POSTGRES_USER=monitor
POSTGRES_PASSWORD=changeme

View File

@ -14,5 +14,6 @@ backend/keys/
frontend/dist/
frontend/node_modules/
frontend/.vite/
frontend/.pnpm-store/
docs/

View File

@ -10,6 +10,7 @@ import (
"log/slog"
"os"
"os/signal"
"path/filepath"
"syscall"
"time"
@ -97,6 +98,10 @@ func run(configPath string) error {
"pool_size", cfg.Redis.PoolSize,
)
if err := ensureJWTKeys(cfg.JWT, logger); err != nil {
return err
}
jwtManager, err := auth.NewJWTManager(cfg.JWT)
if err != nil {
return err
@ -237,6 +242,31 @@ func run(configPath string) error {
return nil
}
func ensureJWTKeys(cfg config.JWTConfig, logger *slog.Logger) error {
if _, err := os.Stat(cfg.PrivateKeyPath); err == nil {
return nil
} else if !errors.Is(err, os.ErrNotExist) {
return err
}
if dir := filepath.Dir(cfg.PrivateKeyPath); dir != "" && dir != "." {
if err := os.MkdirAll(dir, 0o700); err != nil {
return err
}
}
if dir := filepath.Dir(cfg.PublicKeyPath); dir != "" && dir != "." {
if err := os.MkdirAll(dir, 0o700); err != nil {
return err
}
}
logger.Warn("JWT keys missing, generating",
"private", cfg.PrivateKeyPath,
"public", cfg.PublicKeyPath,
)
return auth.GenerateKeyPair(cfg.PrivateKeyPath, cfg.PublicKeyPath)
}
func setupLogger(cfg config.LogConfig) *slog.Logger {
var handler slog.Handler

View File

@ -0,0 +1,52 @@
-- ©AngelaMos | 2026
-- 00000_template_baseline.sql
-- +goose Up
-- +goose StatementBegin
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
-- +goose StatementEnd
-- +goose StatementBegin
CREATE TABLE users (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
email text NOT NULL UNIQUE,
password_hash text NOT NULL,
name text NOT NULL DEFAULT '',
role text NOT NULL DEFAULT 'user',
tier text NOT NULL DEFAULT 'free',
token_version integer NOT NULL DEFAULT 0,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
deleted_at timestamptz
);
CREATE INDEX idx_users_email ON users (email) WHERE deleted_at IS NULL;
CREATE INDEX idx_users_role ON users (role) WHERE deleted_at IS NULL;
CREATE INDEX idx_users_created ON users (created_at DESC);
-- +goose StatementEnd
-- +goose StatementBegin
CREATE TABLE refresh_tokens (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
token_hash text NOT NULL UNIQUE,
family_id uuid NOT NULL,
expires_at timestamptz NOT NULL,
created_at timestamptz NOT NULL DEFAULT now(),
is_used boolean NOT NULL DEFAULT false,
used_at timestamptz,
revoked_at timestamptz,
replaced_by_id uuid,
user_agent text NOT NULL DEFAULT '',
ip_address text NOT NULL DEFAULT ''
);
CREATE INDEX idx_refresh_tokens_user ON refresh_tokens (user_id);
CREATE INDEX idx_refresh_tokens_family ON refresh_tokens (family_id);
CREATE INDEX idx_refresh_tokens_expires ON refresh_tokens (expires_at);
CREATE INDEX idx_refresh_tokens_hash ON refresh_tokens (token_hash);
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
DROP TABLE IF EXISTS refresh_tokens;
DROP TABLE IF EXISTS users;
-- +goose StatementEnd

View File

@ -10,7 +10,7 @@ services:
dockerfile: conf/docker/prod/vite.docker
container_name: ${APP_NAME:-monitor}-nginx
ports:
- "${NGINX_HOST_PORT:-8430}:80"
- "${NGINX_HOST_PORT:-8432}:80"
depends_on:
backend:
condition: service_healthy

View File

@ -11,4 +11,4 @@ ENV NODE_ENV=development
EXPOSE 5173
CMD ["pnpm", "dev", "--host", "0.0.0.0"]
CMD ["sh", "-c", "pnpm install && pnpm dev --host 0.0.0.0"]

View File

@ -8,7 +8,7 @@ services:
image: nginx:1.27-alpine
container_name: ${APP_NAME:-monitor}-nginx-dev
ports:
- "${NGINX_HOST_PORT:-8430}:80"
- "${NGINX_HOST_PORT:-8432}:80"
volumes:
- ./conf/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./conf/nginx/dev.nginx:/etc/nginx/conf.d/default.conf:ro
@ -28,7 +28,7 @@ services:
dockerfile: conf/docker/dev/go.docker
container_name: ${APP_NAME:-monitor}-backend-dev
ports:
- "${BACKEND_HOST_PORT:-5430}:8080"
- "${BACKEND_HOST_PORT:-5432}:8080"
volumes:
- ./backend:/app
- go-mod-cache:/go/pkg/mod
@ -46,7 +46,7 @@ services:
networks:
- backend
healthcheck:
test: ["CMD-SHELL", "wget -q -O- http://localhost:8080/api/v1/healthz || exit 1"]
test: ["CMD-SHELL", "wget -q -O- http://localhost:8080/healthz || exit 1"]
interval: 10s
timeout: 5s
retries: 5
@ -59,7 +59,7 @@ services:
dockerfile: conf/docker/dev/vite.docker
container_name: ${APP_NAME:-monitor}-frontend-dev
ports:
- "${FRONTEND_HOST_PORT:-3430}:5173"
- "${FRONTEND_HOST_PORT:-3432}:5173"
volumes:
- ./frontend:/app
- frontend-node-modules:/app/node_modules
@ -73,7 +73,7 @@ services:
image: postgres:17-alpine
container_name: ${APP_NAME:-monitor}-postgres-dev
ports:
- "${POSTGRES_HOST_PORT:-5431}:5432"
- "${POSTGRES_HOST_PORT:-4432}:5432"
environment:
POSTGRES_USER: ${POSTGRES_USER:-monitor}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-monitor}
@ -94,7 +94,7 @@ services:
image: redis:7-alpine
container_name: ${APP_NAME:-monitor}-redis-dev
ports:
- "${REDIS_HOST_PORT:-6430}:6379"
- "${REDIS_HOST_PORT:-6432}:6379"
command: redis-server --appendonly yes
volumes:
- redisdata-dev:/data