Commit Graph

15 Commits

Author SHA1 Message Date
schalli 4aef69bd83 fix(db): make accentColor migration idempotent with IF NOT EXISTS
Tessera CI/CD / Lint & Type Check (push) Successful in 43s
Tessera CI/CD / Tests (push) Successful in 48s
Tessera CI/CD / Build & Publish Images (push) Successful in 4m1s
Column already existed in production DB — migration failed with 42701.
Hotfixed via psql UPDATE on _prisma_migrations; migration SQL updated
to prevent recurrence on fresh deploys.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-02 10:47:00 +02:00
schalli 7da1c19b31 fix(db): add migration for User.accentColor column
Tessera CI/CD / Lint & Type Check (push) Successful in 45s
Tessera CI/CD / Tests (push) Successful in 44s
Tessera CI/CD / Build & Publish Images (push) Successful in 24s
Column was added to schema but migration was missing, causing
PrismaClientKnownRequestError P2022 on prod API startup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-02 10:25:43 +02:00
schalli 42daa87e5e feat(calendar): add domain field and test-connection button to Exchange sources
- Prisma: domain String? added to CalendarSource model (db push applied)
- DTOs: domain in CreateCalendarSourceDto, UpdateCalendarSourceDto, new TestCalendarSourceConfigDto
- Service: domain in SOURCE_SAFE_SELECT, addSource, updateSource; new testConnectionFromConfig method
- Controller: POST /calendar/sources/test-config (before :id routes to avoid collision)
- ExchangeProvider: domain in all source interfaces; passed as 3rd arg to EWS WebCredentials
- Frontend: domain in CalendarSource/CreateSourcePayload/UpdateSourcePayload; testSourceConfig API fn
- Form: domain field (Exchange-only), "Test connection" button with idle/loading/success/error states
- i18n: de+en keys for formFieldDomain, formFieldDomainHint, formTestConnection, formTesting, formTestSuccess, formTestFailed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-01 13:15:13 +02:00
schalli eebceb298d fix(08): apply code review findings (CR-01, CR-02, WR-01–05, IN-01)
- CR-01: fix SSRF bypass — isPrivateIpv6 now delegates ::ffff:<ipv4> to
  isPrivateIpv4, covering 172.16-31.x and 169.254.x ranges
- CR-02: add ParseUUIDPipe to GET /favorites widgetId param + service guard
  so missing widgetId returns 400 instead of leaking all user favorites
- WR-01: link-widget — replace raw 'link.error' key with t('link.error') (4 sites)
- WR-02: favorites-widget — fix load-path error to use t('favorites.error')
- WR-03: widget-catalog-modal — move aria-hidden from outer wrapper to backdrop
- WR-04: calculator — remove duplicate M button (MR clone); MC/MR/M+/M−/MS remain
- WR-05: schema — add FavoriteLink→WidgetInstance FK with onDelete:Cascade
- IN-01: create-widget.dto.ts — update comment from four to eight supported types

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-01 11:03:16 +02:00
schalli 758d246e98 feat(08-03): FavoriteLink schema + FavoritesModule (CRUD + SSRF icon discovery)
- Add FavoriteLink Prisma model (userId/tenantId/widgetId scope, iconUrl nullable, position)
- IconDiscoveryService: port SSRF-protected icon discovery with redirect: 'manual',
  private IP / blocked-hostname checks, 4000ms timeout, 200k HTML cap (T-08-05)
- FavoritesService: list/create/update/remove all scoped by userId (T-08-06 / Pitfall 3)
- FavoritesController: GET /favorites?widgetId, POST, PATCH :id, DELETE :id
- FavoritesModule registered in AppModule
- tsc --noEmit passes for @tessera/api
2026-07-01 10:25:52 +02:00
schalli 0fba45d2c2 feat(quick-260630-gbh-01): avatar storage endpoints + enriched /auth/me
- Add avatarPath String? column to User model (migration: add_user_avatar)
- POST /users/me/avatar: 2MB limit, image/png/jpeg/webp allowlist, writes to user-files/avatars/{userId}.{ext}
- GET /users/me/avatar: streams avatar with Cache-Control: no-store
- AuthService.getMe(): returns isLocalUser + hasAvatar without leaking passwordHash/ldapDn
- AuthController GET /auth/me: now returns enriched profile via getMe()
2026-06-30 11:57:33 +02:00
schalli 24868ec1b8 chore(db): add migration for all tables missing from history
Tessera CI/CD / Lint & Type Check (push) Successful in 41s
Tessera CI/CD / Tests (push) Successful in 39s
Tessera CI/CD / Build & Publish Images (push) Successful in 28s
Captures DashboardLayout, WidgetInstance, SearchProvider, CalendarSource,
DkvModuleConfig, DkvVehicleMaster, DkvInvoiceHistory, SmtpConfig.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 15:17:27 +02:00
schalli 01ff137f43 fix(07): UAT fixes — SMTP test email, DKV routing, Exchange domain field
Tessera CI/CD / Lint & Type Check (push) Waiting to run
Tessera CI/CD / Tests (push) Blocked by required conditions
Tessera CI/CD / Build & Deploy (push) Blocked by required conditions
- SMTP: add test-to field, send real email via sendMail() instead of verify()
- SMTP: fix no_auth warning shown as error for open-relay servers
- DKV: register dkv-fleet in MODULE_REGISTRY (fixes "Modul nicht gefunden")
- DKV: add dynamic [category]/[moduleSlug]/settings + vehicles sub-routes
- DKV: settings/vehicles links use useParams for consistent URLs
- DKV: add gear icon settings link to module main page
- DKV: rename module to "DKV-Rechnung" in seed + translations
- DKV: add optional domain field for Exchange (WebCredentials 3rd arg)
- DKV: hide IMAP-only fields (Port/Verschlüsselung/Ordner) when Exchange selected
- DKV: hide Exchange-only field (Domain) when IMAP selected
- Prisma: add domain column to DkvModuleConfig

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 21:58:26 +02:00
schalli c4b39ccd1b feat(07-01): install DKV deps, add Prisma models, wire ScheduleModule + crypto export
Tessera CI/CD / Build & Deploy (push) Blocked by required conditions
Tessera CI/CD / Lint & Type Check (push) Successful in 37s
Tessera CI/CD / Tests (push) Waiting to run
- pnpm add imapflow@^1.4.3, pdf-parse@^2.4.5, xlsx@^0.18.5 to @tessera/api
- Append DkvModuleConfig, DkvVehicleMaster, DkvInvoiceHistory, SmtpConfig models to schema.prisma (15 models total)
- Add ScheduleModule.forRoot() to AppModule imports (prerequisite for DkvSchedulerService)
- Export CalendarCryptoService from CalendarModule (needed by DkvModule + SettingsModule)
- Create apps/api/src/dkv/dkv.types.ts with DkvVehicleBlock, DkvTransaction, InboxConfig, InboxEmail, InboxAttachment, ExportRow interfaces
2026-06-26 19:25:42 +02:00
schalli 9ec6313f4d feat(05-03): calendar backend — model, crypto, source CRUD module
- Add CalendarSource Prisma model with encrypted credentials (AES-256-GCM)
- Create CalendarCryptoService with encrypt/decrypt using CALENDAR_ENCRYPTION_KEY
- Create CalendarController with source CRUD endpoints (GET/POST/PATCH/DELETE)
- Create CalendarService with ownership checks and SSRF URL validation
- Add DTOs with https-only URL validation and class-validator decorators
- Register CalendarModule in AppModule
- Install tsdav, node-ical, ews-javascript-api, @microsoft/microsoft-graph-client
- Stub provider files for Task 2 compilation
2026-06-24 15:09:03 +02:00
schalli 38dcfdfa6d feat(05-02): add SearchProvider backend with model, CRUD, and defaults
- Prisma model SearchProvider with userId/tenantId scoping
- Three default providers (Google/Bing/DuckDuckGo) as constants, always returned without DB seed
- GET/POST/DELETE search-providers endpoints on DashboardController
- Ownership verification on delete (T-05-07), default providers cannot be deleted
- CreateSearchProviderDto with class-validator: urlTemplate must contain {query} (T-05-08)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 11:34:45 +02:00
schalli 950eebbc15 feat(05-01): dashboard backend — Prisma models, CRUD API, module wiring
- Add DashboardLayout and WidgetInstance Prisma models with userId/tenantId scoping
- Create DashboardController with 6 endpoints (layout CRUD + widget CRUD)
- Create DashboardService with ownership verification on all widget mutations (T-05-01)
- Add SaveLayoutDto, CreateWidgetDto, UpdateWidgetConfigDto with class-validator
- Register DashboardModule in app.module.ts imports

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 11:14:03 +02:00
schalli 8c24c1e267 feat(03-01): add Module SDK package and Prisma module registry schema
- Create @tessera/module-sdk with TesseraModule, ModuleRoute, ModuleManifest, ModuleCategory types
- Add Module and TenantModuleActivation Prisma models with tenant-scoped unique constraint
- Apply migration add-module-registry to PostgreSQL
- Framework-agnostic ComponentType for lazy-loaded module UIs
2026-06-19 12:33:55 +02:00
schalli d0b36c8f22 feat(02-01): Prisma schema expansion, RLS migration, and PrismaModule
- Add User, Role enum, PasswordResetToken, LdapConfig, LdapFieldMapping models
- Expand Tenant model with isActive, users relation, ldapConfig relation
- Create RLS migration with tenant isolation policies on all tenant-scoped tables
- Create PrismaModule (global), PrismaService, and forTenant extension
- Add JWT_SECRET, TESSERA_ADMIN_*, TESSERA_FORCE_CHANGE env vars to docker-compose
- Install @nestjs/jwt, @nestjs/passport, passport, argon2, class-validator deps
2026-06-18 13:22:38 +02:00
schalli 04c78b4bdc feat(01-01): NestJS API with health endpoint and Prisma schema
- NestJS app with ConfigModule and HealthModule
- GET /health endpoint returning {status, timestamp} using HealthResponse type
- Prisma schema with PostgreSQL datasource and Tenant model (multi-tenancy foundation)
- Multi-stage Dockerfile with non-root nestjs user, monorepo root as build context
- Workspace dependency on @tessera/shared for shared types
- Type-check passes successfully
2026-06-18 10:04:08 +02:00