Commit graph

17 commits

Author SHA1 Message Date
Thomas Reitz
1643db0e7b fix: set refresh token (not access token) in HttpOnly cookie
The login endpoint was incorrectly storing the access token in the
refresh_token cookie. This caused silent refresh to fail after page
reload since the short-lived access token couldn't be used for refresh.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 20:49:41 +01:00
Thomas Reitz
779d90ca43 feat: add user profile page with 2FA management and password change
Backend:
- POST /auth/2fa/setup - generate TOTP secret + QR code (temp Redis storage)
- POST /auth/2fa/enable - verify TOTP code and activate 2FA
- POST /auth/2fa/disable - deactivate 2FA (requires password)
- PATCH /users/me - update own profile (firstName, lastName)
- POST /users/me/change-password - change own password

Frontend:
- New ProfilePage with 3 sections: personal info, password, 2FA
- QR code display for Authenticator app setup
- Clickable user info in sidebar navigates to /profile
- AuthContext extended with twoFactorEnabled + refreshUser

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 20:24:44 +01:00
Thomas Reitz
bd00ea5e50 fix: convert query params to numbers for pagination
@Query() decorator always returns strings. Using Number() conversion
with fallback to defaults (page=1, limit=20) to prevent NaN errors
in Prisma findMany skip/take calculations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 18:21:17 +01:00
Thomas Reitz
4d5d5bac88 fix: use wget-based healthcheck for Traefik
The `traefik healthcheck` CLI command doesn't reliably detect the
ping configuration. Using wget against the /ping endpoint instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 18:11:32 +01:00
Thomas Reitz
f337851bb9 fix: enable Traefik ping for healthcheck
The `traefik healthcheck` command requires `--ping=true` to be set.
Without it, the healthcheck always fails even though Traefik works fine.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 18:07:06 +01:00
Thomas Reitz
5f567445be fix: use wget instead of curl for healthchecks in Alpine containers
Alpine images don't include curl. wget is available by default.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 17:43:37 +01:00
Thomas Reitz
2059fa69d9 fix: add @Type(() => Number) for numeric env var conversion
Environment variables are strings from process.env. Explicit
Type decorators ensure class-transformer converts them to numbers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 16:46:06 +01:00
Thomas Reitz
5214d5e0f7 fix: resolve TypeScript compilation errors
- Fix cookieParser import (default import instead of namespace)
- Cast tenant settings to Prisma.InputJsonValue for type safety

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 16:44:45 +01:00
Thomas Reitz
b2ef16eb28 fix: add bcrypt native module rebuild to Dockerfile
bcrypt requires native compilation which was skipped by
--ignore-scripts. Added python3/make/g++ and npm rebuild bcrypt.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 16:42:06 +01:00
Thomas Reitz
8660966c9e fix: correct PgBouncer port to 5432 (image default)
The edoburu/pgbouncer image listens on port 5432 internally,
not 6432. Updated healthcheck and DATABASE_URL accordingly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 16:38:47 +01:00
Thomas Reitz
5412ae137a feat: adapt codebase for IP-based HTTP deployment on 172.20.10.59
Switch from hostname+HTTPS (insight-dev.xinion.lan) to IP+HTTP
(172.20.10.59) for alpha/dev deployment without DNS.

Key changes:
- Cookie secure/sameSite flags environment-conditional (fixes HTTP auth)
- docker-compose.yml: remove HTTPS, update host rules, reduce PG memory
- Traefik: disable TLS, update CORS/CSP for HTTP
- Add Prisma init migration (7 tables) and admin seed script
- Generate package-lock.json for npm ci in Docker builds
- Update all documentation for IP-based access

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 16:21:45 +01:00
Thomas Reitz
10f291cdda feat: implement Sprint 1 Alpha - full stack with Docker, NestJS, React
Docker Infrastructure:
- docker-compose.yml with Traefik 3, PostgreSQL 16, PgBouncer, Redis 7, step-ca
- docker-compose.observability.yml with Prometheus, Grafana, Loki, Tempo, Promtail
- Traefik dynamic config (TLS, security headers, CORS, compression)
- PostgreSQL init script (uuid-ossp, pgcrypto, pg_trgm extensions)
- Grafana auto-provisioned datasources (Prometheus, Loki, Tempo)

NestJS Core-Service:
- Auth module: Login (email/password), TOTP 2FA, JWT RS256, token refresh/revocation
- Users module: CRUD, bcrypt cost 12, pagination, role-based access
- Tenants module: CRUD, member management, slug validation
- Prisma schemas: core (Users, AuthProviders, Tenants, Modules, AuditLog)
                  tenant (Contacts, Activities - CRM reference for Sprint 2)
- TenantPrismaService: Dynamic per-tenant DB connections with caching
- RedisService: Token blocklist, refresh token families, generic cache
- Global JwtAuthGuard with @Public() decorator, RolesGuard, GlobalExceptionFilter
- Health endpoint with DB + Redis status checks
- Swagger API documentation (dev only)
- Multi-stage Dockerfile (dev + production)

React Frontend:
- Vite 6 + React 18 + TypeScript strict
- AuthContext with silent refresh (access token in memory, NOT localStorage)
- Login page with TOTP 2FA support
- App shell with sidebar navigation
- Admin pages: Users + Tenants management tables
- API client with automatic token refresh interceptor
- Multi-stage Dockerfile (dev + nginx production)

CI/CD Pipelines:
- ci.yml: Lint, type-check, test, build on all branches
- deploy.yml: Docker build, push to Forgejo registry, SSH deploy

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 15:33:36 +01:00
Thomas Reitz
34129401a3 docs: update ACCESS.md with server IPs and Forgejo setup completion
- Add insight-dev-01 server IP: 172.20.10.59
- Add Git server (GAIA-GIT) details: 172.20.10.11
- Replace all IP placeholders with actual values
- Update Summarize.md with Forgejo configuration status

Server setup completed on git.xinion.lan:
- Docker Engine 29.3 installed
- Forgejo Actions + Container Registry enabled
- Runner v6.3.1 registered and running
- 5 repository secrets configured
- Branch protection on main + develop

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 11:36:16 +01:00
Thomas Reitz
b3516c5fdd docs: add Forgejo CI/CD setup guide for Git server configuration
Step-by-step instructions for:
- Enabling Forgejo Actions and Container Registry
- Installing and registering a Forgejo Runner
- Configuring repository secrets for deployment
- Setting up branch protection rules
- Testing the Container Registry

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 10:36:22 +01:00
Thomas Reitz
0e052b001c chore: add CI/CD SSH key and update ACCESS.md with both keys
- Generate separate Ed25519 key for Forgejo Actions CI/CD pipeline
- Document both keys with clear purpose separation:
  deploy_ed25519 = server access (manual/Claude)
  cicd_ed25519   = automated deployments (Forgejo Actions)
- Add key placement matrix (which key goes where)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 10:34:01 +01:00
Thomas Reitz
5f54bde55e chore: project initialization with infrastructure definition and structure
- Generate SSH deployment key (Ed25519) for server access
- Define complete server infrastructure (ProxmoxVE VM, Docker, networking)
- Create ACCESS.md with all connection details and SSH instructions
- Create INFRASTRUCTURE.md with VM setup guide and service architecture
- Set up project directory structure per briefing specification
- Add .env.example with all required environment variables
- Add .gitignore for Node.js/Docker/TypeScript project
- Create comprehensive README.md for developer onboarding
- Add Summarize.md changelog
- Include concept and briefing documents

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 10:22:55 +01:00
e4c72dec21 Initial commit 2026-03-07 12:06:32 +00:00