Ir al contenido
← Todos los artículos

13 oct 2026
5 min de lectura

  • Open Source
  • NestJS
  • MongoDB
  • Next.js
  • Security
  • Community

SOS Academy ayuda a principiantes a aprender trabajando en proyectos open source reales, con un mentor. Por qué funciona la idea, lo que construí para su plataforma y lo que aprendí.

El proyecto

En una frase: Shinobi Open Source Academy («SOS Academy») es una comunidad gratuita que ayuda a los desarrolladores principiantes a aprender trabajando en software open source real, con un mentor a su lado.

Mucha gente aprende a programar con vídeos y tutoriales y luego choca con un muro: conoce lo básico, pero nunca ha trabajado en un proyecto real con revisiones de código reales. Las empresas piden experiencia; los principiantes no pueden conseguirla. SOS Academy ofrece un camino: los aprendices se unen a grupos pequeños («squads») guiados por un desarrollador con experiencia, eligen tareas reales de proyectos open source reales en GitHub y reciben acompañamiento hasta que su trabajo se acepta.

La plataforma web de la academia — el sitio, el panel de administración, el blog y el panel de los aprendices — es también open source, y es ahí donde contribuí.

Qué lo hace innovador

  • Trabajo real en lugar de ejercicios. Los aprendices resuelven problemas reales en proyectos reales: su trabajo acaba en software que la gente usa — y en su perfil público.
  • Un mentor que te sigue de verdad. Con grupos pequeños, un mentor ve el progreso real de cada aprendiz.
  • Progreso seguido automáticamente. Cuando el trabajo de un aprendiz se envía, se revisa o se acepta en GitHub, la plataforma se actualiza sola.
  • Los aprendices también pueden mejorar la plataforma. Es open source: contribuir a la academia ya es una primera contribución real.

En resumen: mi contribución y lo que aprendí

Mi parte: construí funcionalidades de la plataforma: los grupos de mentoría (quién guía a quién, con un límite de plazas que se respeta incluso cuando mucha gente se inscribe en el mismo segundo), el seguimiento de la tarea de cada aprendiz desde «reservada» hasta «aceptada», actualizado automáticamente desde GitHub, y varias correcciones de seguridad — entre ellas un sistema de inicio de sesión que podía aceptar claves antiguas y páginas de gestión de usuarios abiertas a cualquiera. La primera parte está aceptada; el resto está en revisión, con dos partes ya aprobadas.

Lo que me llevo: cuando mucha gente actúa en el mismo momento, las reglas debe aplicarlas el propio sistema, no la esperanza de que las peticiones lleguen de una en una. Y construir para una comunidad es hablar, dividir el trabajo en pasos y escuchar a los revisores.


El resto del artículo entra en los detalles técnicos, para desarrolladores.

Por dentro

Un monorepo TypeScript — API NestJS + MongoDB, apps Next.js (sitio, administración, blog, portal de aprendices), una librería compartida, desplegado con Docker y Vercel.

En detalle: lo que aporté

Mi contribución en cifras: 14 pull requests. El modelo Squad está fusionado; las demás siguen abiertas, dos de ellas ya aprobadas. A diferencia de otros proyectos, aquí se trata sobre todo de funcionalidades nuevas más que de correcciones.

Los squads

La primera PR (#221, fusionada) define el modelo Squad: un mentor, una comunidad, miembros y una capacidad, con reglas como «un mentor tiene que ser realmente mentor» y «un mentor no puede ser miembro de su propio squad». Las siguientes añaden los endpoints de administración y la página que muestra a un mentor los miembros de su squad.

Lo interesante es la concurrencia. La capacidad se comprueba dentro de la propia actualización: tres personas que se unen a la vez a un squad de una plaza dan exactamente un éxito. «Un solo squad activo por aprendiz» lo garantiza un índice único parcial — sin el filtro parcial, cada squad vacío chocaría con todos los demás.

El ciclo de vida de un issue como máquina de estados

Cada issue pasa por estados — reservado, en curso, PR abierta, cambios solicitados, fusionado… — declarados en una sola tabla de transiciones. Cada cambio es un compare-and-set que también escribe su entrada en el historial:

findOneAndUpdate(
  { _id: id, status: current },
  { $set: { status: next }, $push: { statusHistory: entry } },
)

Cinco personas reclamando el mismo issue a la vez: gana exactamente una y las demás reciben un 409 claro. Después, un trabajo de sincronización lee la timeline de GitHub de cada issue, encuentra la pull request abierta por la persona asignada y hace avanzar el issue. Para pasar de «en curso» a «fusionado», busca un camino en el grafo de transiciones (en anchura): incluso los saltos que provoca la sincronización pasan por pasos legales y registrados. Respeta los límites de la API de GitHub y no hace nada cuando nada ha cambiado.

Autenticación y seguridad

  • /auth/refresh fallaba siempre: el parser de cookies no estaba registrado. Al corregirlo apareció algo sutil — bcrypt solo lee los primeros 72 bytes, y los tokens de refresco de un usuario comparten sus primeros 72 bytes: se habrían aceptado tokens antiguos. Ahora se hashean con SHA-256.
  • Las rutas de gestión de usuarios, incluida DELETE /users/:id, estaban abiertas a cualquiera. Ahora exigen una sesión de administrador o el propio usuario, y un usuario no puede cambiar su propio rol.
  • pnpm audit pasó de 232 avisos (5 críticos) a 5 moderados, y la auditoría en CI ya puede bloquear de verdad un build.

Lecciones técnicas

  • Dejar que la base de datos haga cumplir las reglas. Comprobar la capacidad en el servicio y luego actualizar deja un hueco por el que pueden colarse dos peticiones. Una actualización condicional o un índice lo cierran para siempre.
  • Una máquina de estados hace imposibles los estados ilegales. Una sola tabla de transiciones respondió preguntas que, si no, estarían repartidas en ifs — y hizo fácil razonar sobre la sincronización con GitHub.
  • Conocer los límites de tu criptografía. bcrypt es la herramienta correcta para contraseñas y la equivocada para tokens largos con prefijos idénticos. El bug solo apareció porque había corregido el anterior.
  • La deuda de seguridad se esconde en las rutas «internas». Endpoints de gestión de usuarios abiertos son de esas cosas que nadie nota, hasta que alguien lo hace.
  • Contribuir a una comunidad no es solo corregir bugs. Las funcionalidades me exigieron discutir el alcance, apilar PR que dependen unas de otras y responder a revisores como CREDO23, cuya observación sobre la herencia de roles hizo que el guard fuera correcto.