Compare commits

..

83 Commits

Author SHA1 Message Date
Ronny fde9d7799c docs: add Supabase credential migration guide
Build & Deploy Tippspiel / build (push) Successful in 40s
Documents the JWT-to-sb_secret key migration, deployment touchpoints
(local .env, Portainer Stack 115, Gitea workflow), and the fresh-clone
.env setup needed after machine migration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-01 00:42:38 +02:00
Ronny a521f5656c chore: suppress markdownlint warnings in spec docs
Build & Deploy Tippspiel / build (push) Successful in 40s
2026-04-12 19:39:53 +02:00
Ronny aa0c065bd6 fix: show pending tips in profile, count all tips not just evaluated
- Profile tip history now shows all tips (not just evaluated)
- Pending tips display  badge in blue instead of hiding
- Fun Facts "Tipps abgegeben" counts all tips (from tips API)
- Added .badgePending CSS style

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 18:42:26 +02:00
Ronny 786b3586be fix: CSP allows Google Fonts for Material Symbols icons 2026-04-12 18:13:44 +02:00
Ronny edf33fa932 feat: premium achievement badges with Material Symbols icons
Backend:
- New /api/achievements endpoint calculating 6 badges:
  Scharfschütze, Serien-Tipper, Tabellenführer, Frühtipper,
  Globetrotter, Diamant
- Each with progress tracking (current/target)

Frontend:
- AchievementBadge component with Stitch-inspired design
- Material Symbols Outlined font (filled icons)
- Unlocked: colored icon with glow + drop-shadow, rank label
- Locked: grayscale, lock overlay, progress bar
- ProfilePage: real badges replacing emoji placeholders
- Progress bar showing X/6 collected
- Mobile: 2-col grid, Desktop: 6-col grid

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 18:09:25 +02:00
Ronny d370558174 feat: logo links to home/dashboard 2026-04-12 17:34:00 +02:00
Ronny 132ea4f7d0 feat: desktop layout optimization
Dashboard: 2-column layout (hero left 60%, stats+nudges right 40%)
Spielplan: 2-column grid for match cards on desktop
Profile: wider max-width (900px), 6-column achievement grid
Header: Admin link back in desktop nav, max-width 1200px
All via CSS media queries (min-width: 768px), no HTML restructuring.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 17:26:20 +02:00
Ronny 1be1cdba2f feat: local country flags replacing team crests
48 country flags downloaded from flagcdn.com (320px PNG, ~55KB total)
stored in frontend/public/flags/{iso-code}.png.

New utility getFlagUrl() maps team names to local flag files.
Applied to MatchCard, DashboardPage, and TipModal.
Falls back to original crest URL if no mapping exists (e.g. TBD).

No external API calls at runtime — all flags served statically.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 16:31:24 +02:00
Ronny 2414fc04d9 feat: three-way theme toggle — Dark / Light / System
Cycles: Sun (→ Light) → Monitor (→ System) → Moon (→ Dark)
System mode follows OS prefers-color-scheme and updates live.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 16:17:57 +02:00
Ronny ab09b92050 style: more spacing between Tippspiel and subtitle 2026-04-12 16:14:03 +02:00
Ronny 1addb3940d style: 'FIFA World Cup 2026' as golden subtitle under 'Tippspiel' 2026-04-12 16:11:01 +02:00
Ronny c2195aa02f style: Lucide TrendingUp/Down icons for rank change arrows 2026-04-12 16:07:02 +02:00
Ronny d38f650261 fix: move useEffect before early returns (React hooks rule violation) 2026-04-12 16:02:42 +02:00
Ronny fe777a2bab feat: achievement badge placeholders on profile page (Phase 2 prep)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 15:57:32 +02:00
Ronny 1999ef8a21 feat: rank change arrow (↑/↓) in dashboard stats tile
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 15:56:59 +02:00
Ronny 9c19188a7e feat: WM 2026 trophy SVG without text in header
Extracted trophy graphic from unofficial logo SVG, removed
"FIFA WORLD CUP", "2026", and country names text.
Works in both dark and light mode (colored on transparent).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 15:39:33 +02:00
Ronny 9b78c4a46c feat: FIFA WM 2026 unofficial logo in header (PNG)
Unofficial logo works in both dark and light mode (colored on transparent).
Official and white variants also included as alternatives.
Removed broken SVG files (Cloudflare blocked downloads).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 15:32:48 +02:00
Ronny f88f2ac6bc feat: replace trophy emoji with official FIFA WM 2026 logo
White SVG logo for dark mode, colored SVG for light mode.
Logo switches automatically based on theme.
Sourced from football-logos.cc (SVG, ~4.5KB each).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 15:20:49 +02:00
Ronny f8a6d12db1 style: comprehensive Light Mode overrides
Dashboard:
- Hero card: white glass (rgba 255,255,255,0.75) instead of dark glass
- Reduced shadows (no more extreme 40px shadow)
- LED digits: dark gold (#9A6500) with subtle shadow
- Countdown/tip badges: dark gold on light background
- Flag boxes: lighter shadows, no dark glow aura

MatchCards:
- LED time: dark gold for contrast on light bg
- Flag boxes: lighter shadows

BottomNav:
- White background with subtle top border
- Inactive tabs: darker for readability

Global:
- text-muted: 0.45 opacity (was 0.35) — better readability
- text-secondary: 0.65 (was 0.60)
- Gold: #B8740A (darker for light bg contrast)
- shadow-card: much lighter (was too heavy)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 15:11:57 +02:00
Ronny 048bf15a5e feat: move Admin to bottom nav, remove from header 2026-04-12 15:02:58 +02:00
Ronny 07f6a8ae13 style: card polish — badge spacing, no separator line, wider tip row
- Badges: more margin below (10px), better text centering (line-height:1)
- Removed border-top separator between flags and tip area
- Tipped row: full width to align with flag edges
- Reduced card padding for compactness

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 14:53:34 +02:00
Ronny a7485da0e9 style: dashboard uses parent padding — same width as Spielplan 2026-04-12 14:36:44 +02:00
Ronny d1189d5d6e style: fix badge centering over flags, plain theme toggle icon
- badgeRow now uses same gap (10px) as matchRow for exact alignment
- Theme toggle: removed button box, plain icon like admin gear
- Both icons use text-secondary color, consistent style

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 14:29:52 +02:00
Ronny d44927ec23 style: badges as row above flags, centered over each team
Badge row uses same flex proportions as match row (flex:1 | spacer | flex:1)
so left badge centers over left flag, right badge over right flag.
Full team names restored (no more truncation from 5-column layout).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 14:18:22 +02:00
Ronny 799239dcc1 style: badges centered to flags, wider dashboard, mobile header actions
MatchCard:
- Badges (group, countdown, LIVE, BEENDET) now vertically centered
  to flag height, positioned left/right of the teams
- Removed separate topRow — all in one matchBlock flex layout

Dashboard:
- max-width increased to 800px (matches spielplan width)

Header:
- Theme toggle + admin link moved to headerActions (always visible)
- Theme toggle icon in gold color (was too dark in dark mode)
- Admin link brighter (text-secondary instead of text-muted)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 13:55:00 +02:00
Ronny 0e1675fe90 style: dashboard LED smaller, TipModal flags fullbleed + subtle picker buttons
- Dashboard: LED digits 20px (was 26px) — less crowded between flags
- MatchCard: topRow margins for better badge alignment
- TipModal: flags now object-fit:cover (fullbleed)
- TipModal: picker buttons less glossy — reduced shine from 55% to 12%,
  smaller shadow, subtler hover effect

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 13:37:57 +02:00
Ronny 44199b0a90 style: unified flag+time design across Dashboard and Spielplan
Dashboard:
- Flags aligned to top (flex-start) — consistent height regardless of name length
- LED time centered to flag height (64px)

Match Cards:
- Flags fullbleed (object-fit: cover), larger (56px), glassmorphism shine
- LED kickoff time replaces dash separator between flags
- Score appears at same position when Live/Finished
- Removed separate kickoffRow — cards are more compact
- scoreBox height matches flag height for vertical centering

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 13:22:13 +02:00
Ronny 91ea1f4dc3 style: hero card curvature shine, smaller fullbleed flags, tighter LED
- Hero: added glossy ::before shine gradient (top 45%) for curvature/Wölbung
- Flags: 64px, object-fit:cover (flag fills entire box), glassmorphism shine
- LED: slightly smaller (26px), tighter digit spacing (18px), stronger glow
- Backdrop blur increased to 24px

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 13:09:05 +02:00
Ronny 27f93f76f9 fix: LED digits fixed 20px width for uniform spacing 2026-04-12 12:46:05 +02:00
Ronny 75d69191fa fix: LED digits individually spaced — fixes '2 1:00' gap in DSEG7 font 2026-04-12 12:42:47 +02:00
Ronny b2ca2c733a style: stronger glow, bigger LED, fix vertical alignment, tighter spacing 2026-04-12 12:39:23 +02:00
Ronny c6c167abb3 style: remove hero border, LED time between flags like Design 2
- Removed visible blue border on hero card (now near-invisible white/6%)
- LED kickoff time moved between the two flags (replacing VS text)
- Layout: flag — LED time — flag centered vertically

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 12:35:38 +02:00
Ronny 8503592c7b style: match Stitch glassmorphism — backdrop-blur, flag glow auras, deeper shadows
Hero card now uses glassmorphism (rgba + backdrop-blur) from Stitch design.
Each flag has individual blur-glow aura behind it.
Rounded corners increased to 2rem. Shadow depth increased.
Stats tiles and nudges also refined with rounder corners.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 12:08:29 +02:00
Ronny 23116a847a style: premium Dashboard redesign inspired by Stitch mockups
Hero Card:
- Dramatic gradient background (navy → deep blue)
- Radial glow effect behind team flags (stadium atmosphere)
- LED kickoff time with golden glow
- Larger flag icons (72px) as app-icon style boxes
- Countdown as golden badge with pulsing dot
- Bigger CTA button with gradient and shadow

Bottom Nav:
- Filled/solid SVG icons (home, soccer ball, trophy, person)
  instead of Lucide outline icons — more premium feel

Nudges:
- Icon + text layout with hover animation
- Better spacing and visual hierarchy

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 11:56:29 +02:00
Ronny 8b7b31826a feat: stronger visual scoring differentiation + streak fix
- Exakt cards: gold glow border, gold banner, trophy emoji, larger animated badge
- Tendency: green accent (was blue), clearer differentiation from Exakt
- Falsch: muted gray, reduced opacity — clearly "lost"
- Profile tip history: solid gold/green/gray badges with distinct borders
- Streak: remove utc_date <= NOW() filter so dev-finished matches count; handle PostgreSQL boolean serialization

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 09:31:15 +02:00
Ronny 1eaec75901 style: BEENDET badge right-aligned, bigger score, score aligned to flag center
- BEENDET as subtle badge on the right (same position as LIVE/countdown)
- Score: 26px default, 32px for live matches
- Score vertically centered to flag height (52px), not flag+name

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 09:11:36 +02:00
Ronny 0f70a1913c style: LIVE badge right-aligned, bigger live score, remove redundant tip
- LIVE: pulsing red badge with dot, right-aligned in header (replaces countdown position)
- Live score: 28px instead of 22px for better visibility
- Removed duplicate tip display under live score (tip only shown in footer)
- BEENDET status stays left in header

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 09:00:55 +02:00
Ronny e9143d6ebe fix: countdown badge back in header row (right-aligned), fix LED spacing
- Countdown badge in header: Gruppe A ... in 60 Tagen (right side)
- Urgent countdown also in header: Gruppe A ... Noch 9 Min!
- Removed separate countdownRow (was misplaced below kickoff)
- Reduced DSEG7 letter-spacing to fix "2 1:00" gap issue

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 23:22:11 +02:00
Ronny 92f847c075 style: countdown badge left-aligned, separate from header
Countdown badge now in its own row, left-aligned to match
the left edge of the flags. Removed from header top row.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 23:16:17 +02:00
Ronny 9cd55f8e28 style: stronger LED glow on kickoff time (4-layer text-shadow) 2026-04-11 23:10:35 +02:00
Ronny 3a1d99a92f style: reduce LED kickoff size, center vertically between header and flags 2026-04-11 23:07:54 +02:00
Ronny b7068ea2b0 style: real LED segment display font for kickoff time
- Added DSEG7 font (stadium scoreboard segment display)
- Kickoff time centered in card, no box, just glowing LED digits
- Gold color with double text-shadow glow for authentic look

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 22:56:56 +02:00
Ronny 6be9bcdc1b style: stadium scoreboard kickoff display in card header
Kickoff time styled as LED scoreboard: monospace font, dark background,
gold text with glow effect. Placed in card header next to group badge.
Cards are more compact without the separate kickoff row.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 22:50:12 +02:00
Ronny 137e14b3d1 fix: kickoff time centered without 'Uhr', unified countdown badge, DevPanel close button
- Kickoff: centered "21:00" above flags (no 'Uhr' suffix)
- Countdown: always rendered as badge (was unstyled span for <60min)
- DevPanel: added close button (✕) in panel header for reliable closing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 22:46:53 +02:00
Ronny e1b9f03d60 style: move kickoff time to card header, better date header spacing
- Kickoff time now in header row: "Gruppe A · 04:00 Uhr · in 61 Tagen"
  instead of centered between flags (avoids visual misalignment)
- Date timeline headers: more top padding for balanced spacing
  between cards

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 22:37:25 +02:00
Ronny d39ec7a579 style: Spielplan — glassmorphism stats card, timeline date headers
- Stats: glass card with 2/104 progress + Punkte/Exakt/Offen details
- Date sections: timeline divider with centered label + lines
  instead of accordion (no more broken border-radius)
- Past matches: simple toggle button, separate from timeline
- Match list: clean vertical flow without section containers

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 22:27:58 +02:00
Ronny a7ce8141a3 style: redesign Spielplan — date grouping, compact stats, less glossy
- Replace 3 large stat tiles with compact "2 von 104 getippt" line
- Remove phase dropdown (not useful for daily tipping)
- Group matches by actual date (Mi, 11. Juni / Do, 12. Juni)
  instead of generic "Demnächst"
- First 3 date sections open by default
- Reduce TipModal flag glossy to match MatchCard flags
- Past matches in own collapsed section

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 22:09:38 +02:00
Ronny 4fe4d45270 style: align group badge left in card header 2026-04-11 21:59:44 +02:00
Ronny 6a40d71634 style: Match-Cards — names below flags, less glossy, cleaner header
- Team names centered below flags (vertical layout)
- Reduced flag box glossy effect (20% shine vs 55%)
- Removed "Terminiert" status from header (only show Live/Beendet)
- Dash separator instead of colon for upcoming matches
- Flex layout instead of grid for better centering

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 21:44:42 +02:00
Ronny 8bc00f12aa style: redesign Match-Cards — balanced layout, better tipped state
- Move kickoff time above teams row instead of between flags
- Center separator: slim ":" instead of 100px time block
- Use shortName for teams (prevents overflow on mobile)
- Tipped state: clean green bar with icon, label, score, edit hint
  instead of scattered checkmark + underline link

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 21:29:18 +02:00
Ronny 5af41a8a2c fix: accuracy 1000% bug, Spiele nav icon, light mode polish
- Backend: parseInt for leaderboard values from PostgreSQL
  (string concatenation "1"+"0"="10" caused 1000% accuracy)
- BottomNav: Swords icon instead of emoji for Spiele tab
- Light mode: stronger card shadows and shine gradient

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 21:05:23 +02:00
Ronny e10aeadb6b fix: accuracy display, Spiele nav icon, light mode card polish
- Trefferquote: accuracy already displayed correctly as raw value (no fix needed, was already `{stats.accuracy}%`)
- BottomNav: replace  emoji with Lucide Swords icon for Spiele tab (emoji rendered as gear on some systems); remove unused .emojiIcon CSS class
- Light mode: stronger card shadows (0 4px 20px + 0 1px 4px) and brighter card shine (0.85)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 21:03:40 +02:00
Ronny 676ed9c1b3 fix: improve tipping user journey
- Dashboard "Jetzt tippen" opens TipModal directly instead of
  navigating to /spiele (no more dead-end spielplan)
- After tipping, dashboard updates to show "Dein Tipp: X:Y ✓"
- Spielplan auto-opens all sections when only 1-2 exist
  (no more collapsed "Demnächst" as only section)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 20:51:36 +02:00
Ronny 57bae63b68 chore: cleanup — remove compiled .js files and .superpowers artifacts
Added frontend/src/**/*.js and .superpowers/ to .gitignore.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 20:43:42 +02:00
Ronny 7bb35ecf65 fix: simplify CI pipeline YAML to avoid parsing errors
Removed env: block and complex inline heredocs.
Compose file written to temp file instead of inline Python string.
2026-04-11 20:38:10 +02:00
Ronny addff8f0cc ci: switch to Gitea Container Registry for reliable deploys
Previous pipeline built images locally via Portainer Docker API,
but Docker layer caching produced identical images. Now:
- Build with nocache=1
- Push to Gitea registry (git.home.rm-warpstation.de)
- Compose uses image: from registry instead of build:
- Redeploy with pullImage: true forces fresh container

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 20:18:34 +02:00
Ronny dd65f7c4fe fix: StatsRing NaN with no data, Toast showing repeatedly, timer stability
- StatsRing: compute all without || 1 fallback, guard segments/legend behind hasData, use seg.count in legend to avoid NaN
- useRankChange: skip toast if already shown this session via sessionStorage
- Toast: use ref for onDismiss to prevent timer reset on every render

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 19:54:32 +02:00
Ronny 77ee3f9a45 fix: restore glassmorphism card effects on new components
Apply global .card class to Dashboard, Profile, ConfettiReveal, and
Toast components for consistent glossy card appearance.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 19:45:54 +02:00
Ronny 7b19f3db98 feat: Phase 1 — Engagement & UX-Polish
Dashboard als Startseite, Bottom Nav, Smart Sections,
zustandsbasierte Match-Cards, Konfetti-Reveal, Streak-Tracker,
Rich Profile, Tipp-Animation, Rang-Toast.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 19:17:19 +02:00
Ronny f1b4b63324 style: CSS polish, light mode verification, build fixes
- Add --primary-rgb, --transition-fast, --transition-normal CSS tokens to :root
- Add --primary-rgb override in [data-theme="light"] section
- Fix TS error: remove unused devUser prop from Route elements in App.tsx (API patching via window._devUser makes props redundant)
- Fix TS error: remove unused 'api' import from DevPanel.tsx

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 19:16:13 +02:00
Ronny 2dc55f29db feat: rich profile page with stats ring, tip history, fun stats
Donut chart showing exact/tendency/wrong distribution.
Scrollable tip history with point badges.
Fun stats: favorite tip, home win percentage.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 19:14:41 +02:00
Ronny a304ceeff5 feat: rank change toast + streak milestone icons
Toast notification on rank change (up/down).
Streak display with milestones: 🔥 at 3, 🔥🔥 at 10,  at 20.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 19:12:02 +02:00
Ronny f6ab2c719d feat: Punkte-Reveal with confetti animation
Shows animated reveal overlay for unseen match results.
Exact match (3pts) triggers confetti explosion.
Each reveal shown only once (localStorage tracking).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 19:10:22 +02:00
Ronny 89046a2e29 feat: tip confirmation animation with haptic feedback
Success overlay with animated checkmark and 'Dein Tipp ist drin! 🎯'
message. Haptic vibration on mobile. Auto-closes after 1.2s.

- Add showSuccess state to TipModal
- Trigger vibration feedback on successful submit
- Display success overlay with popIn animation for checkmark
- Auto-close modal after success animation completes
- Add CSS animations (fadeIn, popIn) to TipModal.module.css

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 19:08:39 +02:00
Ronny 1ed64078b4 feat: zustandsbasierte Match-Cards (open/tipped/live/finished/missed)
Each card state has distinct visual treatment:
- Open: standard with countdown timer when <1h
- Tipped: green accent with tip display
- Live: pulsing red dot
- Finished: points badge (gold/green/gray)
- Missed: grayed out

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 19:07:21 +02:00
Ronny 9a9b85a269 feat: smart sections in Spielplan (Heute/Morgen/Woche/Vergangen)
Matches grouped by time relevance with collapsible accordion.
Heute and Morgen open by default. Stage filter simplified to dropdown.
2026-04-11 19:05:09 +02:00
Ronny d27881c1c2 feat: add Dashboard as new startseite
Hero card with next match + countdown, stats tiles (rank, points, streak),
and contextual nudges. Replaces match list as landing page.
2026-04-11 19:02:53 +02:00
Ronny b10f0f6ad4 feat: add /api/dashboard endpoint with hero match, stats, streak, nudges
Returns next tippable match (hero), user rank/points from leaderboard,
consecutive-tip streak, and up to 3 contextual nudges in one request.
Mounts at /api/dashboard; adds getDashboard() + DashboardData type to
the frontend API client.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 19:01:01 +02:00
Ronny cb095126ef feat: add bottom navigation bar (mobile-first)
Fixed bottom nav with Home/Spiele/Rangliste/Profil tabs.
Desktop keeps header nav. Admin hidden behind gear icon.
Main content padded to avoid overlap with bottom nav.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 18:59:00 +02:00
Ronny 4f148811f0 refactor: simplify TipModal — remove Expertenblick and redundant header
Strips all insight/agent state, fetchInsight() SSE function, audio playback
logic, and the insightWrapper JSX block that called /api/agent/* routes.
Also removes the matchHeader/groupBadge and kickoffBlock from the modal
(info already visible on the match card). Cleans all corresponding CSS.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 18:56:48 +02:00
Ronny 62aeda1395 refactor: remove KI-Agent chat widget and backend route 2026-04-11 18:54:50 +02:00
Ronny 69585cfac1 docs: Phase 1 implementation plan — 14 tasks
Step-by-step plan covering:
- Cleanup (remove AgentChat, simplify TipModal)
- Bottom Nav, Dashboard, Smart Sections
- Match Card states, animations, confetti
- Streak tracker, rank toasts, rich profile

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 18:34:24 +02:00
Ronny ea5b7b19fa docs: Phase 1 Design-Spec — Engagement & UX-Polish
Umfassendes Design-Dokument für das App-Redesign:
- Dashboard als neue Startseite (Hero + Stats + Nudges)
- Bottom Navigation Bar (Mobile-First)
- Smart Sections im Spielplan
- 5 emotionale Momente (Konfetti, Countdown, Streak etc.)
- Zustandsbasierte Match-Cards
- Reiches Profil mit Stats-Ring und Tipp-Historie
- Cleanup: KI-Agent entfernen, Modal verschlanken

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 18:26:32 +02:00
Ronny e0462c5ba4 ci: trigger rebuild for devUser fix
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 17:16:08 +02:00
Ronny 7bbbe01a03 fix: devUser-Parameter an alle API-Calls weiterleiten
Im Dev-Modus wurde der devUser Query-Parameter aus der Browser-URL
nicht an die Backend-API-Calls weitergegeben. Dadurch liefen alle
Requests immer als devUser=1 (Ronny), unabhängig vom gewählten User.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 17:03:11 +02:00
Ronny 7c9b7344aa fix: Health-Check vereinfacht – kein DB-Query mehr bei /health
Verhindert unnötige SELECT 1 Abfragen gegen Supabase alle 30s.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 16:45:39 +02:00
Ronny e0c4beadb1 style: Lucide Icons für Theme-Toggle + stärkerer Glossy-Effekt auf Flag-Boxen
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 14:09:36 +02:00
Ronny 7dac1befe7 style: stärkerer Glossy-Effekt auf Flag-Boxen im Light Mode
Glanz-Overlay auf 55% angehoben, inset-Highlight und Border ergänzt
für MatchCard flagBox, TipModal flagLarge und pickerBtn.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 14:02:21 +02:00
Ronny 01d7c10719 chore: add Claude Code config and local docs to .gitignore
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 14:00:27 +02:00
Ronny f56ecb724b feat: Light Mode mit Theme-Toggle
Fügt vollständigen Light Mode hinzu – umschaltbar per ☀️/🌙-Button
im Header, Auswahl wird in localStorage persistiert.

- index.css: Light-Mode-Variablen unter [data-theme="light"], neue Tokens --border-subtle, --shadow-card, --card-shine
- App.tsx: Theme-State + useEffect setzt data-theme auf <html>
- App.module.css: Toggle-Button gestylt, Header-Background auf CSS-Var umgestellt
- Komponenten-CSS: Hardcodierte rgba-Werte auf CSS-Variablen migriert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 12:50:04 +02:00
Ronny 2127ebceeb ci: Credentials aus Workflow entfernen, Portainer-Config dynamisch lesen
Statt Credentials im Workflow hardcoden:
- Compose-File und Env-Vars werden zur Laufzeit aus Portainer gelesen
- Einziges Secret im Workflow: PORTAINER_TOKEN
- Keine sensiblen Daten mehr in git-versionierten Dateien

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 13:41:19 +02:00
Ronny d7cd558caf ci: curl via apk installieren (Alpine runner hat kein curl)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 11:48:35 +02:00
Ronny 94be5620a6 fix: Gitea CI/CD und Blank-Page-Fehler behoben
- Helmet CSP: upgrade-insecure-requests und HSTS für HTTP-Deployments deaktiviert
  (war die Ursache der leeren Seite - Browser versuchte JS über HTTPS zu laden)
- Backend: statische Dateien werden jetzt in allen NODE_ENV-Modi serviert
- Frontend: IS_DEV erkennt auch VITE_TEST_MODE=true (Build-Zeit Variable)
- Dockerfile: VITE_TEST_MODE=true beim Vite-Build, NODE_ENV=development
- docker-compose.yml: NODE_ENV=development, CORS_ORIGIN=*
- Gitea Workflow: Auth-Token für git clone, Build via Portainer API statt lokaler Docker CLI

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 11:46:56 +02:00
+104
View File
@@ -0,0 +1,104 @@
# Supabase Credential Migration — Deployment Notes
## Hintergrund
Das Tippspiel-Repo hatte versehentlich Secrets im Git-History (alter `.gitea/workflows/build.yml`). Im Zuge der Bereinigung wurden:
- **DB-Passwort** rotiert
- **Service Role Key** vom Legacy-JWT-Format auf das neue Supabase-Schlüsselformat migriert
Die alten Werte sind ungültig — Deployments mit alter Konfiguration funktionieren nicht mehr.
## Supabase Key-System: was sich geändert hat
Supabase hat das API-Key-System umgestellt:
| Alt (Legacy, JWT) | Neu |
|---|---|
| `anon` (Browser/Public) | `sb_publishable_...` |
| `service_role` (Backend) | `sb_secret_...` |
**Wichtige Unterschiede:**
- Legacy-Keys sind JWTs (lange Strings beginnend mit `eyJ...`), neue Keys sind Tokens beginnend mit `sb_secret_...` bzw. `sb_publishable_...`
- Legacy-Keys können nur als Gruppe rotiert werden (per JWT-Secret-Reset, invalidiert alle User-Sessions)
- Neue Keys sind **einzeln** rotierbar
- Das Supabase-SDK akzeptiert beide Formate — **kein Code-Change nötig**, nur die Env-Variable austauschen
**Wir nutzen jetzt den neuen `sb_secret_...`-Key** unter dem Variablennamen `SUPABASE_SERVICE_ROLE_KEY`.
## Betroffene Variablen
| Variable | Wo zu finden |
|---|---|
| `DATABASE_URL` | Supabase Dashboard → Project Settings → Database → Connection string (**Transaction Pooler**, Port 6543) |
| `SUPABASE_URL` | Supabase Dashboard → Project Settings → API (unverändert) |
| `SUPABASE_SERVICE_ROLE_KEY` | Supabase Dashboard → Project Settings → API Keys → **Secret keys** Tab → `sb_secret_...` |
> **Wichtig:** Bei `DATABASE_URL` den **Transaction Pooler** (Port 6543, Host `aws-0-eu-west-1.pooler.supabase.com`, User `postgres.<project-ref>`) verwenden — **nicht** Direct Connection (Port 5432, Host `db.<project-ref>.supabase.co`). Direct Connection läuft nur über IPv6 und scheitert in vielen Umgebungen mit `ENOTFOUND`.
Korrektes URL-Format (Pooler):
```text
postgresql://postgres.<project-ref>:<password>@aws-0-eu-west-1.pooler.supabase.com:6543/postgres
```
## Deployment-Stellen
Die Variablen müssen an **drei Stellen** synchron gehalten werden:
### 1. Lokales Dev-Environment
Datei: `backend/.env` (gitignored, nicht im Repo).
**Wichtig bei frischem Clone / Maschinenwechsel:** `backend/.env` ist **bewusst** nicht in Git — Secrets gehören niemals ins Repo. Stattdessen liegt `backend/.env.example` als Template mit Platzhaltern bei. Auf jeder neuen Maschine einmalig:
```bash
cd backend
cp .env.example .env
# dann .env öffnen und Platzhalter durch echte Werte ersetzen
```
**Mindestens benötigte Werte für lauffähiges Dev-Setup:**
```bash
DATABASE_URL=postgresql://postgres.<project-ref>:<password>@aws-0-eu-west-1.pooler.supabase.com:6543/postgres
SUPABASE_URL=https://<project-ref>.supabase.co
SUPABASE_SERVICE_ROLE_KEY=sb_secret_...
FOOTBALL_API_KEY=...
```
`ANTHROPIC_API_KEY` und `ELEVENLABS_API_KEY` aus `.env.example` werden aktuell **nicht** benötigt (Features wurden entfernt).
**Empfehlung:** Werte in einem Passwort-Manager (1Password, Bitwarden o.ä.) hinterlegen, damit sie beim nächsten Umzug sofort zur Hand sind. **Niemals** per E-Mail/Slack/Chat verschicken.
### 2. Portainer Stack `wm2026-tippspiel` (Stack 115)
Portainer UI → Stack → **Environment variables** → Werte ersetzen → **Update the stack**
> **Häufiger Fehler:** Beim Pasten **nicht** den Variablennamen mitkopieren. Ins Value-Feld kommt nur der reine Wert, **nicht** `DATABASE_URL=postgresql://...`. Sonst entsteht eine doppelte Präfix-Verschachtelung und der Container kann keine DB-Verbindung aufbauen.
### 3. CI/CD Workflow (`.gitea/workflows/build.yml`)
Der Workflow holt die Env-Vars **dynamisch aus der Portainer Stack-Konfig** (Schritt 2). Im Repo selbst stehen **keine** Secrets, sondern nur Referenzen wie `${{ secrets.PORTAINER_TOKEN }}` und `${{ secrets.DEPLOY_TOKEN }}`. Diese beiden Gitea-Secrets bleiben unverändert.
## Migration-Checklist für neue Umgebung
- [ ] Aktuelles DB-Passwort aus Supabase abrufen (oder neu setzen unter Project Settings → Database)
- [ ] Aktuellen `sb_secret_...`-Key aus Supabase Dashboard kopieren (API Keys → Secret keys)
- [ ] Connection String aus Pooler-Tab kopieren, `[YOUR-PASSWORD]` ersetzen
- [ ] In Ziel-Stack die drei Variablen setzen: `DATABASE_URL`, `SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY`
- [ ] Stack redeployen
- [ ] Smoke-Test: `curl http://<host>:<port>/api/matches` → soll JSON mit `matches`-Array liefern (kein 500)
- [ ] Falls 500: Container-Logs prüfen auf `ENOTFOUND` (→ Direct Connection statt Pooler) oder `28P01 invalid_password` (→ Passwort falsch oder Pooler-Cache braucht ~30s)
## Code-relevante Stellen
- DB-Pool wird konfiguriert in `backend/src/db/client.ts` — liest `DATABASE_URL`
- SSL ist nur in `NODE_ENV=production` aktiv, mit `rejectUnauthorized: false`
- Pool-Settings: max 10 Verbindungen, 5s Connection-Timeout, 30s Idle-Timeout
## Referenzen
- Supabase API Keys Doku: <https://supabase.com/docs/guides/getting-started/api-keys>
- Supabase Connection Pooler: <https://supabase.com/docs/guides/database/connecting-to-postgres#connection-pooler>