Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/jtapieromalambo-ctrl/Signia/llms.txt

Use this file to discover all available pages before exploring further.

Signia uses a custom user model that extends Django’s AbstractUser with fields specific to accessibility: a unique email address used for login, a disability profile that drives automatic routing, and an email verification status tied to a one-time password flow. Every feature in the app — translation history, sign recognition, and admin access — is gated on this authentication layer.

Custom User Model

usuarios.Usuario extends AbstractUser and adds the following fields:
class Usuario(AbstractUser):
    email              = models.EmailField(unique=True)
    discapacidad       = models.CharField(
                             max_length=10,
                             choices=[('ninguna','Ninguna'),('sordo','Sordo'),('mudo','Mudo')],
                             default='ninguna'
                         )
    email_verificado          = models.BooleanField(default=False)
    acepto_terminos           = models.BooleanField(default=False)
    fecha_aceptacion_terminos = models.DateTimeField(null=True, blank=True)
    discapacidad_seleccionada = models.BooleanField(default=False)
The username field is kept but its built-in UnicodeUsernameValidator is removed, allowing spaces and special characters in display names. Email uniqueness is enforced at the model level and validated again in RegistroForm.clean_email().

Registration Flow

1

Fill in the registration form at /registro/

Users provide a username, unique email address, password (confirmed twice), and an initial disability selection. The RegistroForm is a UserCreationForm subclass that adds the discapacidad radio field with human-readable labels:
  • No tengo discapacidad
  • Soy sordo (quiero texto → señas)
  • Soy mudo (quiero señas → texto)
2

Accept the Terms and Conditions

Registration is blocked unless the acepto_terminos checkbox is ticked. The view sets user.acepto_terminos = True and records fecha_aceptacion_terminos = timezone.now() before saving the new account.
3

OTP sent via email

Immediately after the account is created, enviar_otp(user) generates a 6-digit numeric code via CodigoOTP.generar(), stores it in the database (marking any previous unused OTPs for that user as used), and sends it to the user’s email address using EmailMultiAlternatives with an HTML template.
4

Verify the code at /verificar-otp/

The user enters the 6-digit code. The view looks up the most recent unused CodigoOTP for the session email and calls otp.esta_vigente(), which checks both the usado flag and a 10-minute expiry window:
def esta_vigente(self):
    return not self.usado and timezone.now() < self.creado_en + timedelta(minutes=10)
On success, email_verificado is set to True, the user is logged in, and a welcome email is sent.
5

Select disability profile

After email verification the session flag show_disability_modal triggers a disability selection modal (or dedicated page at /seleccionar-discapacidad/). The user confirms or changes their accessibility profile. discapacidad_seleccionada is set to True once the choice is saved.
6

Redirected based on disability

redirigir_por_discapacidad() inspects user.discapacidad and sends the user to the appropriate feature:
def redirigir_por_discapacidad(user):
    if user.discapacidad in ['sordo', 'mudo']:
        return redirect('reconocimiento')
    else:
        return redirect('traduccion')

Login

The login form at / (served by the home view) accepts a username and password via a form field named username. Django’s authenticate() is called with those credentials. On success the user is logged in with backend='django.contrib.auth.backends.ModelBackend'.First-time logins trigger the disability selection modal via the session flag show_disability_modal.

Password Recovery

1

Request a reset code at /recuperar/

The user enters their registered email address. If the email matches a Usuario record, a 6-digit numeric code is generated, stored in the session (request.session['reset_codigo']), and emailed to the user. The code is valid for 10 minutes.
2

Enter the code at /verificar-codigo/

The user enters the code from their email. If it matches request.session['reset_codigo'], the session key reset_verificado is set to True and the user is forwarded to the password reset form.
3

Set a new password at /nueva-password/

The user enters and confirms a new password (minimum 8 characters). On success, usuario.set_password() is called, the reset session keys are deleted, a confirmation email is sent, and the user is redirected to the login page.

Profile Management

Authenticated users can manage their account at the following URLs:
URLViewDescription
/perfil/perfilView profile information (username, email, disability)
/perfil/editar/editar_perfilUpdate username via EditarPerfilForm
/perfil/password/cambiar_passwordChange password with current-password verification
/perfil/eliminar/eliminar_cuentaPermanently delete the account and all associated data
Password changes call update_session_auth_hash(request, user) to keep the current session valid after the credential update. A confirmation email is sent to the user’s address after a successful change. Account deletion (eliminar_cuenta) logs the user out and calls user.delete(), which cascades to all related EntradaHistorial records via Django’s on_delete=CASCADE.

Disability Routing

After every login event — whether via email/password or OAuth — redirigir_por_discapacidad() routes the user to the correct feature based on their discapacidad field:
discapacidad valueDestinationReason
ninguna/traductor/Hearing/speaking users translate text or audio to signs
sordo/reconocimiento/Deaf users sign to the camera; output is transcribed to text
mudo/reconocimiento/Non-speaking users sign to the camera; output is transcribed to text
superuser/admin-videos/Admins manage vocabulary, train models, and review contact messages
Superusers (is_superuser=True) bypass disability selection entirely and are redirected straight to the /admin-videos/ panel on login. The redirigir_por_discapacidad() function is not called for them; the check if user.is_superuser: return redirect('panel_admin_videos') runs first in both the index and home views.

Translation and Recognition History

Every completed translation and sign recognition event is recorded as an EntradaHistorial entry:
class EntradaHistorial(models.Model):
    usuario   = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    tipo      = models.CharField(max_length=20, choices=[
                    ('traduccion',     'Traducción texto → señas'),
                    ('reconocimiento', 'Reconocimiento señas → texto'),
                ])
    contenido = models.TextField()   # The translated text or recognized sign
    fecha     = models.DateTimeField(auto_now_add=True)
The history view at /historial/ is paginated at 15 entries per page and supports filtering by entry type:
GET /historial/?tipo=traduccion
GET /historial/?tipo=reconocimiento
Individual entries can be deleted via POST /historial/eliminar/<id>/. The entire history can be cleared with POST /historial/clear/. Staff members can clear another user’s history via POST /historial/clear/<user_id>/.

Session Configuration

Sessions in Signia are configured for short-lived, secure access:
SESSION_COOKIE_AGE    = 1200   # 20 minutes of inactivity
SESSION_SAVE_EVERY_REQUEST = True   # Reset the timer on each request
SESSION_EXPIRE_AT_BROWSER_CLOSE = True  # Also expires when browser closes
A session ends when the browser is closed or after 20 minutes of inactivity, whichever comes first. SESSION_SAVE_EVERY_REQUEST = True ensures the 20-minute window resets on every page load, so active users are never logged out mid-session. The requiere_email_verificado decorator can be applied to any view to enforce that the user has completed OTP verification before accessing protected content:
@requiere_email_verificado
def my_protected_view(request):
    ...

Build docs developers (and LLMs) love