Commit Graph

595 Commits

Author SHA1 Message Date
schalli 2fa5193fd0 docs(phase-08): update tracking after wave 1
Tessera CI/CD / Lint & Type Check (push) Successful in 46s
Tessera CI/CD / Tests (push) Has been cancelled
Tessera CI/CD / Build & Publish Images (push) Has been cancelled
2026-07-01 10:03:21 +02:00
schalli 8574218ae6 merge(08-01): widget registry foundation + Calculator widget 2026-07-01 10:02:43 +02:00
schalli 5e8b2c2c39 docs(08-01): complete widget registry foundation + Calculator plan summary
- 3/3 tasks executed (RED/GREEN/verify)
- 16 tests added and passing (67 total web suite)
- SUMMARY.md created with self-check PASSED
2026-07-01 10:01:15 +02:00
schalli 63ec93bd35 feat(08-01): registry foundation for 4 new widget types + Calculator widget (GREEN)
- widget-registry.tsx: extend WidgetType union with calculator/favorites/link/stopwatch
- widget-registry.tsx: add WIDGET_CONSTRAINTS entries with per-widget grid constraints (DASH-11)
- widget-registry.tsx: add SVG icons (CalculatorIcon, FavoritesIcon, LinkIcon, StopwatchIcon)
- widget-registry.tsx: add WIDGET_REGISTRY entries and wire functions for all 4 new types
- calculator-widget.tsx: full arithmetic implementation ported from personal-dashboard
  (parseDisplay, formatNumber, calculate, keyboard handler with stopPropagation)
- widget-catalog-modal.tsx: extend WIDGET_TYPES to include all 8 types
- create-widget.dto.ts: extend @IsIn to accept 8 widget types (T-08-01 mitigated)
- page.tsx: import CalculatorWidget and call wireCalculatorWidget()
- de.json / en.json: add i18n keys for calculator, favorites, link, stopwatch
- All 16 tests passing (GREEN)
2026-07-01 09:57:44 +02:00
schalli b751ae7453 test(08-01): add failing tests for Calculator widget and registry constraints (RED)
- calculator-widget.test.tsx: 5 behaviour tests (render, arithmetic, div/0, keyboard, decimal)
- widget-registry.test.tsx: DASH-11 structure check for all 8 widget types including new Phase-8 types
- Both suites fail (RED baseline) — implementation does not exist yet
2026-07-01 09:54:22 +02:00
schalli b885c767fb docs(08): create phase 8 plan — 4 widget slices (Calculator, Stoppuhr, Favorites, Link) 2026-07-01 09:10:19 +02:00
schalli 29636bd2b1 docs(08): create phase plan (4 widget vertical slices) 2026-07-01 09:03:54 +02:00
schalli dc7b291d28 docs(08): research phase dashboard-widgets-vollimplementierung 2026-07-01 08:53:53 +02:00
schalli 3b0ac41f59 docs(state): record phase 8 context session 2026-07-01 08:33:00 +02:00
schalli 53fb106e39 docs(08): capture phase context 2026-07-01 08:32:54 +02:00
schalli 88db54fa7d fix(account-settings): clear stale pw error on input + live header avatar update
Tessera CI/CD / Lint & Type Check (push) Successful in 44s
Tessera CI/CD / Tests (push) Successful in 37s
Tessera CI/CD / Build & Publish Images (push) Successful in 1m34s
- Password form errors (wrong pw, mismatch) now clear on first keystroke
  in any password field instead of persisting until next submit.
- Avatar upload now bumps avatarVersion in auth store and sets hasAvatar=true,
  so the header avatar switches to the uploaded image immediately without reload.
- Header img src uses ?v={avatarVersion} as cache-buster to force browser to
  fetch the new avatar when version increments.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 15:29:21 +02:00
schalli 85cd17452c refactor(admin): move SMTP settings from user settings to admin area
Tessera CI/CD / Lint & Type Check (push) Successful in 39s
Tessera CI/CD / Tests (push) Successful in 37s
Tessera CI/CD / Build & Publish Images (push) Successful in 3m28s
SMTP configuration is an admin concern, not a per-user setting. Removed
it from the settings sidebar and relocated to /admin/smtp with a link in
the admin sidebar.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 14:47:44 +02:00
schalli fe4e64a0ad docs(quick-260630-gbh): User Settings: Passwort ändern (nur non-LDAP) + Profilbild setzen
Tessera CI/CD / Lint & Type Check (push) Successful in 49s
Tessera CI/CD / Tests (push) Successful in 42s
Tessera CI/CD / Build & Publish Images (push) Successful in 1m42s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 12:04:20 +02:00
schalli 86654a466b merge(quick-260630-gbh): User Settings — Passwort ändern (non-LDAP) + Profilbild 2026-06-30 12:03:37 +02:00
schalli 5ae498fd88 feat(quick-260630-gbh-01): header avatar display with initial fallback
- AuthUser store: add optional hasAvatar? field
- Header: populate hasAvatar from fetchCurrentUser() result
- Header avatar button: shows <img src='/api-proxy/users/me/avatar'> when hasAvatar=true with onError fallback to initial span
- Plain <img> tag used (same-origin /api-proxy rewrite, no next/image remote config needed)
2026-06-30 12:02:02 +02:00
schalli 4482a8ce78 feat(quick-260630-gbh-01): account settings page — avatar upload + conditional password form
- AuthUser interface: add isLocalUser? + hasAvatar? fields
- uploadAvatarAction: server action forwarding file to POST /users/me/avatar
- AccountSettingsForm: avatar preview with initial fallback + upload; password form only for local users; LDAP notice
- /settings/general/account page mirroring smtp page structure
- SettingsSidebar: Konto link above SMTP link
- de.json + en.json: categoryAccount + account.* keys
2026-06-30 12:00:40 +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 04b37f54f6 docs(260630-gbh): pre-dispatch plan for User Settings: Passwort ändern (nur non-LDAP) + Profilbild setzen 2026-06-30 11:49:12 +02:00
schalli dcba4b9977 fix(dkv): search msgfolderroot for EWS subfolder resolution
Tessera CI/CD / Lint & Type Check (push) Successful in 43s
Tessera CI/CD / Tests (push) Successful in 47s
Tessera CI/CD / Build & Publish Images (push) Successful in 24s
FindFolder was searching only under inbox DistinguishedFolderId, missing
folders at mailbox root level. Now searches msgfolderroot (full mailbox)
so custom folders like DKV are found regardless of placement.

Also adds HTTP status check and debug logging for FindFolder responses.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 10:23:30 +02:00
schalli 30eb40c184 feat(dkv): Exchange subfolder support via EWS FindFolder
Tessera CI/CD / Lint & Type Check (push) Successful in 40s
Tessera CI/CD / Tests (push) Successful in 39s
Tessera CI/CD / Build & Publish Images (push) Successful in 22s
Custom folder names (e.g. "DKV" or "INBOX/DKV") now resolved by calling
EWS FindFolder deep-search under inbox. Well-known names still map to
DistinguishedFolderId directly. Falls back to inbox with a warning log
when the subfolder cannot be found.

IMAP already supported subfolder paths natively via ImapFlow.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 10:04:24 +02:00
schalli b5bf3ed8c0 fix(dkv): return username in GET /dkv/config response
Tessera CI/CD / Lint & Type Check (push) Successful in 40s
Tessera CI/CD / Tests (push) Successful in 37s
Tessera CI/CD / Build & Publish Images (push) Successful in 22s
loadConfig used CONFIG_SAFE_SELECT which excludes encryptedInboxCreds entirely,
so username was never returned to the frontend — form always showed empty username.

Added getConfigForApi() which loads the safe config + decrypts encryptedInboxCreds
to extract username (never password) and adds hasPassword boolean. Controller
getConfig now calls getConfigForApi instead of loadConfig.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 09:58:59 +02:00
schalli a44e40f101 fix(dkv): correct invoice date extraction; add Exchange IsRead filter + mark-as-read
Tessera CI/CD / Lint & Type Check (push) Successful in 44s
Tessera CI/CD / Tests (push) Successful in 44s
Tessera CI/CD / Build & Publish Images (push) Successful in 21s
Date fix: previous regex matched payment-due date ("10 Tage nach Rechnungsdatum...
10.04.2026") instead of actual Rechnungsdatum. New approach anchors on the
invoice number line (DD/DDDDDDDDD/DDD) and takes the date on the next line,
which is always the actual Rechnungsdatum in DKV PDFs.

Exchange dedup: FindItem now filters IsRead=false (combined with sender filter
via <t:And>), so already-processed emails are skipped automatically.
After downloading attachments, UpdateItem marks the message as read
(using ItemId + ChangeKey from GetItem response), mirroring IMAP \Seen behavior.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 09:47:17 +02:00
schalli 66ffad149e fix(dkv): extract invoice number/date from PDF, rename export files to RG-DKV format
Tessera CI/CD / Lint & Type Check (push) Successful in 41s
Tessera CI/CD / Tests (push) Successful in 38s
Tessera CI/CD / Build & Publish Images (push) Successful in 23s
- Parser now extracts Rechnungsnummer (DD/DDDDDDDDD/DDD) and Rechnungsdatum
  from PDF text, so filename doesn't rely on email subject
- Export filename changed from DKV_YYYY-MM_... to RG-DKV-{nr}-{YYMMDD}.xlsx
  e.g. RG-DKV-26-650869002-002-260331.xlsx
- Subject fallback now also matches slash-separated invoice numbers (26/NNN/NNN)
- writeAndPrune simplified to accept baseName instead of separate fields
- Validation regex and prune prefix updated to match new RG-DKV- pattern

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 09:39:51 +02:00
schalli 5c1aa03270 fix(dkv): handle EV charging rows and service rows in single-tx tab parser
Tessera CI/CD / Lint & Type Check (push) Successful in 40s
Tessera CI/CD / Tests (push) Successful in 37s
Tessera CI/CD / Build & Publish Images (push) Successful in 21s
Analyzed Invoice-4302486921-26_650869002_000.pdf text structure. Three cases:

1. FUEL (fields[4] = numeric tx-nr): km+product merged in fields[5], unit in
   fields[6]. Already working; no change.

2. EV CHARGING (fields contains "DDDD KWH" or "DDDD MIN" unit): column layout
   shifts — no km field, station+ort sometimes merged in fields[1]. Detected by
   regex on unit field; kwhIdx drives relative offset for menge/netto/brutto.
   Ort extracted from fields[2] (kwhIdx>=5) or fields[1] (kwhIdx=4, compact).
   Kilometerstand = 0 (EV chargers don't record odometer).

3. SERVICE ROWS (e.g. "DKV Analytics Premiu"): appear inside a VEHICLE: block but
   fields[4] is non-numeric (product description, not a transaction number). These
   were being parsed as fake vehicle transactions producing wrong ort/km values.
   Now filtered out (return null).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 09:20:12 +02:00
schalli a759e816a0 fix(dkv): fix Kennzeichen matching and NaN/invalid km values in Excel export
Tessera CI/CD / Lint & Type Check (push) Successful in 43s
Tessera CI/CD / Tests (push) Successful in 38s
Tessera CI/CD / Build & Publish Images (push) Successful in 23s
Three issues fixed:

1. Kennzeichen normalization: DKV PDF extracts plates without hyphens
   ("GP JL 740E" vs CSV-imported "GP-JL 740E"). Added _normalizeKennzeichen()
   which strips hyphens, spaces, and dots before lookup — resolves vehicle
   master match failure that caused Marke/Modell/Fahrer to appear empty.

2. Empty-string NaN: parser used ?? '0' which doesn't catch empty strings,
   causing parseDE('') = NaN. Changed to || '0' for km, menge, and totals.

3. Invalid km values: EV charging rows from DKV have misaligned columns —
   km position contains a decimal price (e.g. 18.64 EUR or kWh). Added
   sanity check: non-integer km values are written as null (empty cell)
   instead of a misleading decimal. ExportRow.kilometerstand is now number|null.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 09:12:13 +02:00
schalli c9328f60b7 fix(api): create /app/user-files with nestjs ownership in Dockerfile
Tessera CI/CD / Lint & Type Check (push) Successful in 39s
Tessera CI/CD / Tests (push) Successful in 39s
Tessera CI/CD / Build & Publish Images (push) Successful in 1m36s
Directory must exist before nestjs user takes over — otherwise DkvExportService
cannot write xlsx export files and throws EACCES on first inbox processing run.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 08:44:21 +02:00
schalli ccfd3f21cf fix(dkv): fix EWS attachment ID extraction — FileAttachment has no Id attribute
Tessera CI/CD / Lint & Type Check (push) Successful in 44s
Tessera CI/CD / Tests (push) Successful in 37s
Tessera CI/CD / Build & Publish Images (push) Successful in 28s
extractAttrs(block, 't:FileAttachment', 'Id') always returned empty array
because the attachment Id lives in a child <t:AttachmentId Id="..."/>, not
on the <t:FileAttachment> tag itself. This caused all Exchange inbox checks
to silently find zero PDF attachments and report "no matching emails".

Fixed by iterating FileAttachment blocks individually and extracting
t:AttachmentId/@Id from within each block. Also added filename (.pdf)
as fallback when ContentType is application/octet-stream.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 08:41:17 +02:00
schalli 9efa3bab1d fix(dkv): fix inbox processing pipeline — orphan tenant, MIME detection, UNSEEN filter
Tessera CI/CD / Lint & Type Check (push) Successful in 42s
Tessera CI/CD / Tests (push) Successful in 39s
Tessera CI/CD / Build & Publish Images (push) Successful in 1m37s
- Fix orphaned DkvModuleConfig: tenantId pointed to deleted tenant, updated to Default tenant
- DKV controller: return 404 instead of HTTP 200 null when no config exists
- IMAP provider: also detect PDFs sent as application/octet-stream (check filename extension)
- IMAP provider: add seen:false filter so already-processed emails are skipped on re-poll
- IMAP provider: mark email as \Seen after successful PDF download to prevent reprocessing
- Frontend dkv-api: handle 404 from fetchConfig as "not yet configured" (returns null)
- InboxConfigForm: show warning banner when config not yet saved in DB
- InboxConfigForm: add "Jetzt prüfen" button to manually trigger POST /dkv/check-now

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 08:31:36 +02:00
schalli 9a652ea440 chore(web): remove debug logging from changePasswordAction
Tessera CI/CD / Lint & Type Check (push) Successful in 43s
Tessera CI/CD / Tests (push) Successful in 53s
Tessera CI/CD / Build & Publish Images (push) Successful in 1m50s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 07:30:39 +02:00
schalli 40c4876a19 fix(web): move redirect() outside try/catch in changePasswordAction
Tessera CI/CD / Lint & Type Check (push) Successful in 40s
Tessera CI/CD / Tests (push) Successful in 40s
Tessera CI/CD / Build & Publish Images (push) Successful in 1m27s
redirect() throws NEXT_REDIRECT internally — inside catch it was swallowed
and returned networkError. Extract cookie data in try/catch, then set
cookie and redirect() after the block so the throw propagates correctly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 07:25:57 +02:00
schalli f4ece4890d fix(web): redirect from server action after password change
Tessera CI/CD / Lint & Type Check (push) Successful in 44s
Tessera CI/CD / Tests (push) Successful in 40s
Tessera CI/CD / Build & Publish Images (push) Successful in 1m19s
client-side router.push races with Set-Cookie processing. redirect() in the
server action sends cookie + redirect in one response — browser applies the
new JWT before navigating, so middleware sees mustChangePassword=false.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 07:20:14 +02:00
schalli 195354cd7a debug(web): log set-cookie header value from API change-password response
Tessera CI/CD / Lint & Type Check (push) Successful in 44s
Tessera CI/CD / Tests (push) Successful in 38s
Tessera CI/CD / Build & Publish Images (push) Successful in 1m18s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 07:12:45 +02:00
schalli f96a0db769 fix(web): forward new session cookie after password change
Tessera CI/CD / Lint & Type Check (push) Successful in 39s
Tessera CI/CD / Tests (push) Successful in 35s
Tessera CI/CD / Build & Publish Images (push) Successful in 1m21s
After changePassword the API issues a new JWT with mustChangePassword=false.
The server action now reads Set-Cookie from the API response and sets it
in the browser so the middleware sees the updated flag and allows /dashboard.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 16:47:55 +02:00
schalli c8210a2abc debug(web): add logging to changePasswordAction to diagnose Verbindungsfehler
Tessera CI/CD / Lint & Type Check (push) Successful in 42s
Tessera CI/CD / Tests (push) Successful in 36s
Tessera CI/CD / Build & Publish Images (push) Successful in 1m22s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 16:38:48 +02:00
schalli a8cd528f5a fix(prod): default TESSERA_FORCE_CHANGE to false
Tessera CI/CD / Lint & Type Check (push) Successful in 43s
Tessera CI/CD / Tests (push) Successful in 37s
Tessera CI/CD / Build & Publish Images (push) Successful in 7s
Admin should not be forced to change password on every fresh deploy.
Opt-in via TESSERA_FORCE_CHANGE=true in .env if needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 16:34:10 +02:00
schalli 5779f0f6c9 fix(api): reissue JWT with mustChangePassword=false after password change
Tessera CI/CD / Lint & Type Check (push) Successful in 39s
Tessera CI/CD / Tests (push) Successful in 36s
Tessera CI/CD / Build & Publish Images (push) Successful in 23s
After a successful password change the old cookie still contained
mustChangePassword=true, causing the middleware to redirect back to
/change-password. Now changePassword issues a fresh session cookie.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 16:09:36 +02:00
schalli b28ee472c5 fix(api): use user.id instead of user.sub in changePassword controller
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 21s
JWT strategy maps payload.sub to user.id — user.sub was always undefined,
causing Prisma findUnique to fail with id: undefined validation error.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 16:02:38 +02:00
schalli 46ba8868c7 fix(web): change password via server action instead of client-side fetch
Tessera CI/CD / Lint & Type Check (push) Successful in 40s
Tessera CI/CD / Tests (push) Successful in 36s
Tessera CI/CD / Build & Publish Images (push) Successful in 1m23s
Client-side fetch to NEXT_PUBLIC_API_URL was unreachable in production.
Replace with a server action that uses API_INTERNAL_URL (http://api:3001)
server-to-server — no browser connectivity required.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 15:54:29 +02:00
schalli 6020021370 fix(web): use http://api:3001 as default rewrite destination
Tessera CI/CD / Lint & Type Check (push) Successful in 43s
Tessera CI/CD / Tests (push) Successful in 37s
Tessera CI/CD / Build & Publish Images (push) Successful in 1m24s
next.config rewrites() runs at build time — API_INTERNAL_URL is not set
in CI, so the previous localhost:3001 fallback was baked into the bundle.
Default to http://api:3001 which is always correct in Docker network.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 15:42:44 +02:00
schalli c42ab5dc6f fix(web): proxy client API calls through Next.js to fix production connectivity
Tessera CI/CD / Lint & Type Check (push) Successful in 44s
Tessera CI/CD / Tests (push) Successful in 36s
Tessera CI/CD / Build & Publish Images (push) Successful in 1m33s
NEXT_PUBLIC_API_URL was undefined at build time, causing client bundles to
fall back to http://localhost:3001 — unreachable from the browser in prod.

- Add /api-proxy rewrite in next.config.ts (forwards to API_INTERNAL_URL at runtime)
- Bake NEXT_PUBLIC_API_URL=/api-proxy at build time in Dockerfile
- Fix api.ts to prefer API_INTERNAL_URL for server-side calls
- Fix docker-compose.prod.yml: set NEXT_PUBLIC_API_URL=http://api:3001 for runtime server-side code

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 15:36:06 +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 27c3abf3df fix(deploy): correct prisma binary path in API startup
Tessera CI/CD / Lint & Type Check (push) Successful in 44s
Tessera CI/CD / Tests (push) Successful in 39s
Tessera CI/CD / Build & Publish Images (push) Successful in 3m40s
pnpm puts package binaries in apps/api/node_modules/.bin/, not root.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 15:08:07 +02:00
schalli e26fbd720e fix(deploy): embed prisma migrate deploy in API startup
Tessera CI/CD / Lint & Type Check (push) Successful in 45s
Tessera CI/CD / Tests (push) Successful in 42s
Tessera CI/CD / Build & Publish Images (push) Successful in 3m52s
- Move prisma to runtime dependencies so it's available in prod image
- API runs migrate deploy before starting (handles fresh installs + updates)
- Remove separate migrate service from prod compose

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 14:50:42 +02:00
schalli 14e6e8401f chore: clarify SMTP env vars as optional bootstrap fallback
Tessera CI/CD / Lint & Type Check (push) Successful in 42s
Tessera CI/CD / Tests (push) Successful in 40s
Tessera CI/CD / Build & Publish Images (push) Successful in 6s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 14:42:33 +02:00
schalli aefd79ad75 chore: add prod deploy files — migration service + env example
Tessera CI/CD / Lint & Type Check (push) Successful in 43s
Tessera CI/CD / Tests (push) Successful in 39s
Tessera CI/CD / Build & Publish Images (push) Successful in 6s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 14:38:18 +02:00
schalli 7a9e620db7 ci: push images via localhost:3002 to bypass NPM proxy
Tessera CI/CD / Lint & Type Check (push) Successful in 47s
Tessera CI/CD / Tests (push) Successful in 40s
Tessera CI/CD / Build & Publish Images (push) Successful in 11s
Switches docker login/push to use Gitea's direct port instead of routing
through Nginx Proxy Manager, which was dropping large blob uploads.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 14:27:42 +02:00
schalli 8a02203efc ci: trigger publish after proxy_request_buffering fix
Tessera CI/CD / Lint & Type Check (push) Successful in 41s
Tessera CI/CD / Tests (push) Successful in 37s
Tessera CI/CD / Build & Publish Images (push) Failing after 5m36s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 12:53:09 +02:00
schalli 35c81c4439 chore: replace Traefik with Nginx Proxy Manager in stack docs
Tessera CI/CD / Lint & Type Check (push) Successful in 43s
Tessera CI/CD / Tests (push) Successful in 38s
Tessera CI/CD / Build & Publish Images (push) Failing after 5m27s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 11:54:12 +02:00
schalli 78a1f9bf49 ci: trigger publish after Gitea blob-upload timeout fix
Tessera CI/CD / Lint & Type Check (push) Successful in 44s
Tessera CI/CD / Tests (push) Successful in 39s
Tessera CI/CD / Build & Publish Images (push) Failing after 5m6s
2026-06-29 11:42:34 +02:00
schalli c6a6b3a4bc chore: update session state and resume note
Tessera CI/CD / Lint & Type Check (push) Successful in 40s
Tessera CI/CD / Tests (push) Successful in 37s
Tessera CI/CD / Build & Publish Images (push) Failing after 5m6s
2026-06-29 11:15:21 +02:00