Skip to content

Claude/cpp ceti social system rq8c98 eod4ds - #11

Merged
CesarManzoCode merged 6 commits into
mainfrom
claude/cpp-ceti-social-system-rq8c98-eod4ds
Sep 2, 2026
Merged

Claude/cpp ceti social system rq8c98 eod4ds#11
CesarManzoCode merged 6 commits into
mainfrom
claude/cpp-ceti-social-system-rq8c98-eod4ds

Conversation

@CesarManzoCode

Copy link
Copy Markdown
Owner

No description provided.

…grafo social canónico

Fase 1:
- AcademicCampus/Program/Offering + catálogo CETI seedeado idempotente
- Perfil académico (offering/semester/group) con invariantes CHECK en Postgres
- Username OAuth provisional de alta entropía (no derivado del email) +
  confirmOAuthUsername one-shot + bypass puntual de cookie cache
- Helper safeInternalRedirect + redirectTo preservado en login/registro
- Fix del bug de actividad: getUserLessonActivity(actorId) separado de
  getFriendsActivityFeed(viewerId) — el perfil de A ya no muestra amigos de A
- Privacidad: perfiles con usernameSetupRequired=true ocultos a terceros

Fase 2:
- Friendship.pairKey canónico + FriendshipPeriod (historia) + índice único
  parcial para "un solo período abierto por par"
- FriendRequestSource + InviteAttribution (cookie firmada first-touch,
  30 días, consumida en alta nueva vía databaseHooks.user.create.after)
- Discovery: 5 buckets exactos vía SQL parametrizado con CTEs, keyset
  pagination firmada, context token firmado por candidato
- Mutual friends normalizado en SQL (sin N+1)
- Scripts de backfill (pairKey + legacy XP) validados contra PostgreSQL
  real, idempotentes

Infraestructura de tests:
- vitest.integration.config.ts + tests/integration/** contra Postgres real
  para invariantes que un fake no puede reproducir fielmente (índice único
  parcial, constraints)
- XP ledger (XpAward) wireado en los tres call-sites de otorgamiento de XP
  existentes (completeStep, submitExercise, submitPracticeExercise);
  UserStreak.totalXp queda como contador materializado

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018XQFppGcovvjRoHZyQa6GF
- SocialEvent + Kudos: hitos (unit_completed, course_completed,
  streak_milestone) emitidos idempotentemente dentro de la misma
  transacción del hecho de dominio (completeStep/submitExercise,
  awardXpAndUpdateStreak)
- checkUnitAndCourseCompletion: detecta primera vez que se completa una
  unidad/curso sin N+1 (una sola lectura de las lecciones publicadas del
  curso)
- Feed fanout-on-read (self + amigos accepted actuales) — un unfriend/block
  hace desaparecer los eventos de esa persona de inmediato, sin borrar nada
- Kudos: no propio, duplicado no-op, sólo remove propio
- UI: pestañas "Descubrir" y "Actividad" en /app/amigos, reutilizando
  componentes existentes (FriendAvatar, Tabs)
- Invite attribution consumida vía databaseHooks.user.create.after
  (sólo alta nueva, nunca login) + cookie first-touch capturada desde
  /invitar/[username]
- ProductEvent nuevos (discovery_impression, discovery_profile_open) con
  props validados por Zod, sin username/id de candidato ni datos académicos
- Tests de integración contra Postgres real: dedupe de milestones,
  desaparición inmediata del feed tras unfriend, doble-click de kudos

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018XQFppGcovvjRoHZyQa6GF
Fase 4:
- Ranking semanal de amigos (self + accepted, TODOS incluidos aunque
  tengan 0 XP) y standings de liga por división, ambos sobre XpAward
  competitivo (legacy_balance excluido)
- League rollover: Serializable + advisory lock global, claim atómico
  open→closing (dos workers concurrentes → sólo uno rueda), formación de
  divisiones balanceadas (divisionCount=max(1,round(N/20))), promoción
  top5/bottom5 (N<10: floor(N/2)), Bronze floor / Diamond ceiling,
  frontera exacta de earnedAt, entrantes midweek, finalXp=0 no se
  pre-asigna
- Bootstrap de la primera season en el PRÓXIMO lunes (nunca a mitad de
  semana) — ninguna season cubre una semana parcial

Fase 5 — Friend Streak:
- createFriendStreakRequest/acceptFriendStreakRequest con
  pg_advisory_xact_lock por usuario (orden canónico) — capacidad ≤3
  activas / ≤3 pendientes salientes revalidada de ambos lados
- refreshFriendStreakDay: actividad server-authoritative (lección
  completada O intento calificado de reto/práctica), updateMany
  condicionado por lastEvaluatedDay (sin locks explícitos, idempotente
  ante reintento/doble refresh), breakOnMiss distingue refresh en vivo
  de HOY vs. el job evaluando AYER
- endFriendStreakForPair: unfriend/block cierra en la misma operación,
  current=0, longest se conserva; reamistad reutiliza el par canónico
- StreakReminder: elegibilidad estricta (sender estudió, recipient no),
  límites (1/día/streak, 3/día/sender, rate limit de endpoint)
- UI: pestaña "Rachas" en /app/amigos (streak cards + banners de
  recordatorio), botón "Iniciar racha" en el perfil de un amigo

26 tests de integración contra PostgreSQL real (constraints, locks,
concurrencia genuina) + 475 tests unitarios, todos verdes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018XQFppGcovvjRoHZyQa6GF
Fase 6 — Friend Quests:
- Matching semanal: candidatos con actividad significativa en 14d Y >=1
  lección la semana previa; edges ordenados por diferencia de ritmo,
  no-repetir-pareja, pairKey; greedy — nunca empareja inactivo con activo
- 1 quest/usuario/semana vía UNIQUE(userId, weekStart); progreso cuenta
  lecciones de AMBOS aunque sean de cursos distintos; target=12 fijo
- Transición active→completed condicional (updateMany) — sólo la llamada
  ganadora emite friend_quest_completed, sin XP reward (v1)

Jobs:
- /api/jobs/social-maintenance — UNA superficie protegida por CRON_SECRET
  (Bearer, formato Vercel Cron), ejecución horaria (vercel.json). Corre
  rollover de liga + entrantes midweek + expiración de streaks pendientes +
  evaluación diaria de streaks + matching/expiración de quests. Cada
  sub-tarea es independiente e idempotente; un fallo no tumba las demás.

UI:
- /app/liga: tier, rank, top3, cercanos (±2), zonas de promoción/descenso,
  clasificación completa bajo demanda
- Nav: Inicio/Práctica/Liga/Amigos/Perfil (mobile + desktop); Logros pasa
  a vivir dentro de Perfil; /app/logros queda como redirect permanente
- Ranking semanal de amigos en /app/amigos
- Identidad académica: editor cascada plantel→carrera→semestre→grupo en
  Perfil, visible en el perfil público (campus/carrera/semestre a
  cualquier autenticado, grupo exacto sólo self/amigo), prompt "Encuentra
  a tus compañeros" en Home (después del ContinuePanel, descartable)
- Contexto social compacto en Home: liga, rachas activas, quest de la
  semana — nunca un dashboard

30 tests de integración + 475 unitarios, todos verdes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018XQFppGcovvjRoHZyQa6GF
…es deshabilitadas)

getPublicProfile ahora corta antes de construir el DTO cuando el viewer
está bloqueado por el dueño del perfil: devuelve null (→ 404), en vez de
un perfil completo con el botón de amistad deshabilitado. Esto es lo que
pide <privacy> del contrato ("Blocked-by-target: notFound y exclusión
total") — la versión anterior filtraba nombre/avatar/bio/stats al
bloqueado, sólo le escondía el botón de agregar.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018XQFppGcovvjRoHZyQa6GF
Vercel's current plan doesn't support hourly cron frequency. Remove the
crons entry from vercel.json and add a dedicated GitHub Actions workflow
(schedule + workflow_dispatch) that makes an authenticated HTTPS request
to /api/jobs/social-maintenance, which still owns all the maintenance
logic.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013dA2QiVhmuKxQsAmyZwhbt
@CesarManzoCode
CesarManzoCode merged commit dbca3a7 into main Sep 2, 2026
3 checks passed
@vercel

vercel Bot commented Sep 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
cpp-ceti Ready Ready Preview Sep 2, 2026 1:14am UTC

@CesarManzoCode
CesarManzoCode deleted the claude/cpp-ceti-social-system-rq8c98-eod4ds branch September 5, 2026 00:57
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