Commit graph

30 commits

Author SHA1 Message Date
Thomas Reitz
c40d768827 fix: redesign handset icon as solid silhouette with filled crescent handle
Replace disconnected rectangles+stroke with seamless shape:
earpiece and mouthpiece blocks connected by filled crescent arc

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 12:22:04 +01:00
Thomas Reitz
0c195dc3a9 fix: separate handset icon (landline) and smartphone icon (mobile) in PDF export
- Landline phone: classic telephone handset with earpiece, mouthpiece and curved connector
- Mobile phone: smartphone outline with display and home button

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 12:17:47 +01:00
Thomas Reitz
82af9cb1f0 fix: improve PDF contact icons - smartphone, envelope and map pin shapes
Replaced rough vector shapes with proper recognizable icons:
- Phone: smartphone outline with display area and home button
- Email: envelope with cleaner V-flap proportions
- Location: smooth teardrop map pin using bezier curves

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 12:14:32 +01:00
Thomas Reitz
4d5aa84ac9 fix: improve PDF export - vector icons, wider section lines, address line break, simplified language levels
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 12:06:37 +01:00
Thomas Reitz
2e5a697224 feat: add PDF and Word export for expert profile
Professional CV-style document generation using pdfkit (PDF) and docx (Word).
Two-column layout with avatar, contact info, languages on the left and work
experience timeline on the right. Skills rendered as chips. Accent color
configurable (default teal #009688) for later admin customization.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 11:56:22 +01:00
Thomas Reitz
a275cf83e1 feat: move input forms into section headers for Skills, Languages and Experience
Input fields now appear inline next to the section title, matching the
layout pattern used by Projects, Certifications and Attachments sections.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 10:47:31 +01:00
Thomas Reitz
c7992040a3 feat: display Skills and Languages sections side by side in expert profile
Uses CSS Grid two-column layout with responsive fallback to single column on mobile.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 10:36:52 +01:00
Thomas Reitz
b326081c54 feat: implement expert profile with skills, experience, languages, projects, certifications and attachments
Full-stack implementation of the Expert Profile tab with 6 sections:
- Skills (tag/chip UI with add/remove)
- Experience (area, years, optional level)
- Languages (language + proficiency level)
- Project History (modal form with dates, role, tasks, company details)
- Certifications (modal form with title, issuer, website, year)
- Attachments (file upload/download as Base64, max 10MB)

Backend: 15 API endpoints, 8 DTOs, full CRUD service with ownership verification.
Frontend: Reusable Modal component (React Portal), ExpertProfileTab orchestrator, 8 section components.
Database: 6 new tables (expert_profiles, expert_experiences, expert_languages, expert_projects, expert_certifications, expert_attachments).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 10:23:47 +01:00
Thomas Reitz
5d3958cd74 feat: restructure profile page with new layout, contact fields, and 2FA relocation
- Add phone, mobile, street, postalCode, city fields to User model (Prisma + migration)
- Extend UpdateUserDto with validated contact/address fields
- Update UsersService (findById, update, updateProfile) for new fields
- Rename tab "Persönliche Informationen" to "Profil"
- New layout: avatar left column, form right column with fieldset groups
- Move 2FA section from always-visible into "Passwort ändern" tab
- Add orange 2FA warning badge next to page title (clickable → password tab)
- Add responsive CSS for mobile breakpoint

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 09:03:15 +01:00
Thomas Reitz
c8703ef3e0 feat: add profile page tabs and fix German umlauts throughout app
- Add tab navigation to profile page (Persönliche Informationen, Experten Profil, Passwort ändern)
- Experten Profil tab as placeholder for future content
- 2FA section remains always visible below tabs
- Fix all German umlauts (ae→ä, oe→ö, ue→ü, ss→ß) in frontend and backend
- Fix validation messages, error messages, comments, and UI text

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 07:56:55 +01:00
Thomas Reitz
b5ec4e13b7 fix: resolve TypeScript compilation errors in core service
- Add twoFactorEnabled to LoginResponse user type
- Replace useBodyParser with express json() middleware for body limit

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 07:00:17 +01:00
Thomas Reitz
6fa86714db feat: add profile picture upload, sidebar hint, and fix 2FA bugs
- Bug fix: include twoFactorEnabled in login response so ProfilePage
  shows correct 2FA status after login (not always "Aktivieren")
- Bug fix: restructure 2FA enable/disable handlers to separate API call
  from state updates, preventing false error messages on success
- New: avatar field in User model (Base64 data-URL in PostgreSQL TEXT)
- New: UserAvatar component with initials fallback
- New: client-side image resize to 200x200px before upload
- New: avatar upload/remove on ProfilePage with preview
- New: avatar display + "Zum Profil" hint in sidebar
- Increase JSON body size limit to 1mb for avatar uploads

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 06:51:27 +01:00
Thomas Reitz
ffb618ee65 fix: make refreshToken optional in LoginResponse for 2FA flow
The 2FA challenge response does not include a refreshToken (token is only
issued after successful 2FA verification). Making the field optional fixes
the TS2741 compilation error that prevented the core service from starting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 21:13:31 +01:00
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