CreaRack-SL

Registro invite-only (F1 de la task #137) · plan aprobado en plan-review

Qué es

Plan aprobado (04-08-2026) para abrir el registro self-service invite-only de CreaRack Pro — la F1 de la task #137 del Plan H2. Decidido con Edu en grill (7 decisiones) y endurecido por 3 paneles fríos de /method:plan-review (6 pasadas, 20 bloqueantes cazados y cerrados, plan v1→v7). La captura completa del ciclo vive en CreaRack-Pro/brainstorms/2026-08-04-f1-plan-tecnico.md (v7) y 2026-08-04-registro-f1.md (grill).

Decisiones de producto (grill, Edu)

  1. La página vive en el SaaS: crearack.com/signup (la landing enlazará).
  2. Puerta hasta la apertura pública de noviembre (#151): código de invitación — tabla en BD + sección en Settings (solo superusers), códigos tipo FOUNDER-ACME con usos máximos, caducidad y contador de altas.
  3. Formulario de 4 campos: código, empresa, email, username — sin password (activación por link de email, flujo existente) + Cloudflare Turnstile invisible.
  4. Sin código válido → mensaje claro + “Don’t have an invitation code? Contact us” → hello@crearack.com (buzón operativo desde 04-08).
  5. El código otorga el plan (FOUNDER-* → pro; genérico → starter): cero pasos manuales tras el alta de un fundador.
  6. Página neutra “CreaRack is currently invite-only” — las condiciones de fundadores se negocian por email.
  7. Datos demo (F2, fase siguiente): mini-datacenter en la org del usuario con botón “Remove sample data”, sin métricas inventadas.

Arquitectura aprobada (v7)

  • Puerta: form-post server-side clásico (CSRF real, cero JS propio, errores re-renderizados). POST /api/signup/ se retira del router público; la lógica pasa a un servicio (core/services/) que abre su propia transaction.atomic (la vista queda exenta del TenantRLSMiddleware por lista literal — el alta no escribe en ninguna tabla con política RLS, verificado tabla por tabla; sus fallos van a logger.error, nunca a SystemLog).
  • Turnstile: validación server-side ANTES de tocar el código de invitación (timeout 2 s, fail-closed, nunca sosteniendo el row lock); excepción CSP solo para /signup (flag propio needs_turnstile — script-src y frame-src + challenges.cloudflare.com); sitekey+secret declarados en compose.prod.yml, hostnames del widget cubriendo PROD y STAGE.
  • Modelo: InvitationCode (code único, plan FK on_delete=PROTECT, max_uses, uses_count, expires_at, is_active, notas, created_by) + Organization.invitation_code (SET_NULL). Consumo atómico del último uso (select_for_update).
  • Rate limit: /signup a 15/min por IP (cuenta GETs+POSTs; 3 copias alineadas), con 429 renderizado como página HTML (errors/rate_limited.html) solo para esa ruta.
  • Provisión: PLAN_MAX_RACKS en fuente única; el save_related del admin (que preserva módulos manuales) NO se toca.

Troceo y estado

PRContenidoEstado
PR-0Fixes preexistentes: token de activación muerto (el endpoint regeneraba el password tras calcular el token) + on_commit + SITE_URL para STAGE + test del desenlacePR #360 abierto (04-08) — gate de STAGE en curso
PR-AModelo + servicio + página /signup + retirada del endpoint + Turnstile + CSP + rate limit + tests (4 commits ≤400 LOC)Pendiente
PR-BSettings UI de códigos de invitaciónPendiente

Gate obligatorio pre-merge (PR-0 y PR-A): fijar env vars en el Dokploy de STAGE → desplegar la RAMA a mano allí → E2E (los criterios 6 y 5-bis del plan) → solo entonces merge (main auto-deploya STAGE+PROD a la vez).

Los 3 hallazgos estrella del plan-review

  1. El link de activación del email nacía SIEMPRE inválido (bug preexistente: doble set del password tras calcular el token — arreglado en PR-0, también curaba el alta de primer arranque).
  2. La CSP enforcing de PROD habría bloqueado el iframe de Turnstile con todos los tests en verde.
  3. “Unificar la provisión duplicada” habría borrado módulos concedidos a mano a orgs existentes (el admin preserva, el signup pisa — no era duplicación).

Fuera de scope de F1

Datos demo + wizard (F2) · E2E completo del ciclo (F3) · enforcement de max_racks/límites (#136 Stripe) · membership multi-org · invitar usuarios a una org existente · responder “como” hello@crearack.com (decisión Zoho Mail Lite, septiembre con Txell).

Véase también

  • [[concept—saas—multi-tenancy]]
  • [[concept—saas—module-gating]]
  • [[crearack-tech—admin—email-routing-architecture]]