Skip to content

Sprint 01: bug fixes + suite TDD de integración (69 tests)#4

Merged
odiador merged 7 commits into
mainfrom
feat/sprint-01-bug-fixes
May 24, 2026
Merged

Sprint 01: bug fixes + suite TDD de integración (69 tests)#4
odiador merged 7 commits into
mainfrom
feat/sprint-01-bug-fixes

Conversation

@anju2246
Copy link
Copy Markdown
Owner

Summary

Sprint 01 cierra 8 bugs detectados por verificación end-to-end del Sprint 00 contra la BD de Supabase real, y establece una suite de 69 tests automatizada (22 unit + 47 integration) que valida lógica pura y flujos completos contra el proyecto Supabase del equipo.

Bugs cerrados (productivos)

ID Bug Fix
F-01 print() activos en Modules/Core/Utils/NotificationService.swift, Modules/Data/Local/LocalStore.swift, Modules/Core/Wrappers/OTPServiceProtocol.swift Envueltos en #if DEBUG ... #endif
F-03 awardPointsTo del moderator al verificar ejercicio no actualiza points del autor (RLS rechaza UPDATE silencioso) Migration 002: policy Moderators update any profile
F-04 exercises.votes_count siempre 0 al votar (no había trigger) Migration 003: trigger bump_votes_count (SECURITY DEFINER)
F-05 Notificación al autor cuando alguien comenta nunca se inserta (bug profundo del cliente Swift + RLS combo) Trigger SQL trg_comment_notify en public.comments que la crea server-side
F-06 select("*, author:profiles(*)") ambiguo después de añadir FK verified_by — feed Explore devolvía error PGRST201 en producción Embed explícito profiles!exercises_author_id_fkey en 6 sitios de SupabaseExerciseRepository.swift
F-07 joinDuel lanzaba PGRST116 porque la policy exigía ser ya player1/player2 antes de unirse Migration 004: split en Players update active duels + Anyone joins waiting duels
F-09 deleteAccount no borraba la fila de profiles (no había policy DELETE) Migration 005: policy Users delete own profile
F-10 Realtime de notifications nunca entregaba callbacks UUID en filter pasado a lowercased() + JSONDecoder con dateDecodingStrategy custom para timestamps ISO8601 con fracciones de segundo

Extra

  • Bug del duelo bot: DuelLobbyView.startBotDuel() creaba el DuelViewModel pero nunca invocaba vm.startBotDuel(category:), dejando el VM en phase=.lobby y la pantalla aparentemente en blanco. Ahora dispara el countdown → questions correctamente.

Migraciones SQL aplicadas

Las migraciones 002..005 ya están aplicadas en la BD remota vía Management API. supabase_schema.sql está actualizado para reflejar el estado declarativo. 001_disable_rls.sql queda como referencia histórica — no se aplicó (preferimos policies específicas).

Si recreás el proyecto desde cero, basta correr supabase_schema.sql para tener el schema con todas las policies + el trigger trg_comment_notify.

Test plan

  • tuist generate --no-open && xcodebuild test -workspace dailymath.xcworkspace -scheme dailymath -destination 'id=<iPhone17Pro-26.2>'69/69 PASS en ~2.5min
  • Build standalone: xcodebuild build ...BUILD SUCCEEDED
  • App lanzada en iPhone 17 Pro Simulator → renderiza UI inicial correcta (logo, tarjetas, botones)
  • Bug del duelo bot reproducido + corregido en vivo
  • Probar manualmente: signup/login, moderar pendientes, crear ejercicio, votar, comentar, flashcard quiz, agilidad, perfil, settings

Notas operativas para reviewer

  • TestSecrets.swift contiene service_role y personal access token y queda gitignored — cada dev configura el suyo localmente.
  • Los tests de integración corren contra el proyecto Supabase de producción con prefijos test_<uuid>@dailymath.test y limpieza en tearDown (decisión documentada del Sprint 00).
  • El simulator usado fue iPhone 17 Pro / iOS 26.2 (UDID CD85FB23-...). Usar xcodebuild directo, no tuist xcodebuild (workaround documentado en F-02 del Sprint 00).

🤖 Generated with Claude Code

anju2246 and others added 7 commits May 18, 2026 12:16
Resuelve 8 bugs detectados por verificación end-to-end del Sprint 00 contra
la BD de Supabase real, más establece una suite de tests automatizada
(69 tests, 11 suites, ~2.5min) que valida lógica pura + integración.

Bugs cerrados:
- F-01: print() en producción → envueltos en #if DEBUG (3 archivos)
- F-03: +10 puntos al verificar bloqueados por RLS → migration 002
  (policy "Moderators update any profile" en public.profiles)
- F-04: votes_count no se incrementa → migration 003
  (trigger SQL bump_votes_count con SECURITY DEFINER)
- F-05: notif de comentario no se inserta → trigger SQL
  trg_comment_notify en public.comments (SECURITY DEFINER)
- F-06: select("*, author:profiles(*)") ambiguo después de
  añadir FK verified_by → embed explícito
  profiles!exercises_author_id_fkey en SupabaseExerciseRepository
- F-07: joinDuel falla por policy → migration 004
  (split "Players update active duels" + "Anyone joins waiting duels")
- F-09: deleteAccount no borra profile → migration 005
  (policy "Users delete own profile")
- F-10: realtime de notifications no entrega callbacks →
  UUID lowercase en filter + JSONDecoder ISO8601 custom para timestamps
  con fracciones de segundo.

Bonus: arreglado bug donde DuelLobbyView.startBotDuel creaba el
DuelViewModel pero nunca invocaba vm.startBotDuel(category:), dejando
el VM en phase=.lobby y la pantalla aparentemente "en blanco".

Migraciones SQL aplicadas en la BD remota (Docs/migrations/{002..005}.sql)
y reflejadas en supabase_schema.sql.

Tests:
- 22 unit (SM-2, UserLevel, ChessPiece)
- 47 integration (Auth, Exercise, Community, UserProfile, Duel, Realtime)
- TestSupabase / TestUserFactory / ResultExt como infraestructura
- TestSecrets.swift permanece local (gitignored) con service_role + PAT
- Inject AppState.authService into DuelViewModel for bot duels (was using
  separate local AuthService via DependencyContainer, so points never
  reached the SupabaseAuthService that ProfileView observes).
- Award reputation in finishDuel (+20 win, +5 loss/tie).
- Add duelWon/duelLost/tournamentWon constants.
- Make DuelViewModel Identifiable for fullScreenCover(item:).
- ActiveDuelView: @ObservedObject + dark color scheme so text is visible.
- DuelResultView: 'Volver' button uses dmPrimary background + white text.
…lution

Multiplayer:
- Add subscribeToDuel/fetchDuel to DuelRepository (Supabase + Local).
- DuelLobbyView: creator now enters a waiting room with realtime sub
  to the duels row. When opponent joins (status=active, player2_id set)
  both clients launch ActiveDuelView in sync.
- DuelViewModel: subscribe to duels row in vs-player mode so we detect
  remote finish (status=finished, winner_id) and mirror server scores
  to recover from missed question events.

Chess piece overhaul:
- Switch from lead-based to absolute progression so a tied correct
  doesn't downgrade you.
- Track per-question answer times. Award piece-progress only to the
  correct AND faster answer (tie awards both). Slower correct answer
  still counts in raw myScore but skips piece evolution.
- updateChessPieces() runs once per question in advanceQuestion, not
  on each submit — kills the evolve/downgrade flicker.
…ency filter

- createPrivateDuel now sets lobbyMode=.matchmaking immediately so UI
  shows the spinner instead of freezing on main menu during network call.
- findWaitingDuel filters created_at > now-60s to avoid joining stale
  abandoned duels from test users.
…y UI

Scoring (Kahoot-style):
- myScore += timeRemaining when answering correctly (0–15 pts per question).
- Bot: pts = 15 - floor(botDelay). Realtime: pts = 15 - floor(opTimeMs/1000).
- Tie is now near-impossible (requires identical ms-precision timing).
- Added myCorrectCount/opponentCorrectCount separate from pts score.

Result screen:
- New 'EMPATE' state with blue badge and 'equal.circle.fill' icon.
- Stats row: Correctas | Pts velocidad | Reputación ganada.
- Subtitle adapts to win/tie/loss.

Active duel UI:
- Header shows '(Tú)' badge next to your name, green label.
- Header shows pts score live during duel.
- Piece board shows player name under each piece.
Scoring:
- myScore += max(0, 15000 - elapsedMs) per correct answer.
- Bot: pts = max(0, 15000 - botDelay*1000).
- Realtime: pts = max(0, 15000 - opponentTimeMs).
- Max 15000 pts/question × 10 = 150000 total. Ties now nearly impossible.

Display fix:
- DuelResultView subtitle now uses myCorrectCount (count of correct
  answers) instead of myScore (which is now ms-based pts). The 'Resolviste
  N ejercicios' text no longer shows 1 when 10 were correct.
…tion

- Updated test cases to replace `piece(for:)` with `piece(forCorrect:)` for consistency in lead evaluations.
- Ensured that all lead scenarios (negative, zero, positive) correctly utilize the new method.
- Maintained the integrity of the tests while improving clarity and accuracy in lead handling.
@odiador odiador merged commit df8ee5d into main May 24, 2026
0 of 2 checks passed
@odiador odiador deleted the feat/sprint-01-bug-fixes branch May 24, 2026 23:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants