Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/BrandonCVale/SISTEMA-HABITOS/llms.txt

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

Hábito. stores all of its data in three SQLAlchemy ORM models: Usuario, Habito, and RegistroHabito. Each model maps directly to a SQLite table via Flask-SQLAlchemy’s db.Model base class, and uses the modern Mapped / mapped_column annotation syntax introduced in SQLAlchemy 2.0. The three tables form a simple cascade: one user owns many habits, and each habit owns many daily completion records. All models live under app/models/.

Usuario — table usuarios

The Usuario model represents a registered user of the application. It combines SQLAlchemy’s db.Model with Flask-Login’s UserMixin, so every Usuario instance is immediately usable as a Flask-Login principal without any extra wiring.
Usuario inherits from UserMixin (Flask-Login). This automatically provides the is_authenticated, is_active, is_anonymous, and get_id() methods that Flask-Login requires to manage the session cookie.

Columns

id
int
required
Primary key. Auto-incremented by the database on every INSERT. Never set this manually.
correo
str(120)
required
The user’s email address. Declared unique=True, nullable=False, and index=True. The index speeds up the login lookup performed by UsuarioRepository.obtener_usuario_por_correo().
contrasena
str(128)
required
The bcrypt hash of the user’s password. The plain-text password is never stored. UsuarioRepository.crear_usuario() calls bcrypt.hashpw() before writing to this column.
nombre_usuario
str(50)
required
A unique display name chosen at registration. Declared unique=True and nullable=False. Violating either the correo or nombre_usuario uniqueness constraint raises SQLAlchemy’s IntegrityError.
fecha_registro
datetime
Timestamp of account creation. Defaults to datetime.now (Python-side, evaluated at insert time). Not exposed to the user in the current UI.

Relationship

AttributeTargetConfig
habitosList[Habito]back_populates="dueno", cascade="all, delete-orphan"
The cascade="all, delete-orphan" setting means that deleting a Usuario will automatically delete all of their Habito rows — and, transitively, all RegistroHabito rows that belong to those habits.

Source

class Usuario(db.Model, UserMixin):
    __tablename__ = 'usuarios'

    id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
    correo: Mapped[str] = mapped_column(String(120), unique=True, nullable=False, index=True)
    contrasena: Mapped[str] = mapped_column(String(128), nullable=False)
    nombre_usuario: Mapped[str] = mapped_column(String(50), unique=True, nullable=False)
    fecha_registro: Mapped[datetime] = mapped_column(DateTime, default=datetime.now)

    habitos: Mapped[List["Habito"]] = relationship("Habito",
                                                   back_populates="dueno",
                                                   cascade="all, delete-orphan")

Habito — table habitos

The Habito model represents a single trackable habit belonging to a user. It carries both structural data (which days to perform the habit, what time of day) and running statistics (current streak, best streak). The dias_semana field is stored as a comma-separated string of day-letter codes.

Columns

id
int
required
Primary key. Auto-incremented by the database.
usuario_id
int
required
Foreign key referencing usuarios.id. Not null. Every habit must belong to exactly one user.
nombre
str(100)
required
Short name for the habit (e.g. "Leer", "Correr"). Not null.
descripcion
Text
Optional longer description of the habit. nullable=True — omit or pass None if not needed.
dias_semana
str(20)
required
Comma-separated day-letter codes indicating which days of the week the habit is scheduled. Valid letters are L (lunes/Monday), M (martes/Tuesday), X (miércoles/Wednesday), J (jueves/Thursday), V (viernes/Friday), S (sábado/Saturday), D (domingo/Sunday). Example value: "L,M,X,J,V".
fecha_creacion
datetime
Timestamp of when the habit was created. Defaults to datetime.now at insert time.
activo
bool
Whether the habit is currently active. Defaults to True. Inactive habits are hidden from the dashboard but preserved in the database, allowing users to “pause” a habit without losing history.
racha_actual
int
The current consecutive-days streak. Defaults to 0. Incremented by HabitoRepository.marcar_completado_hoy() when a completion is marked, and decremented (floor 0) when a completion is unmarked.
mejor_racha
int
The all-time best streak for this habit. Defaults to 0. Updated by marcar_completado_hoy() whenever racha_actual exceeds the previous record.
horario
str(20)
Optional suggested time-of-day slot. Typical values: "Mañana", "Tarde", "Noche". nullable=True.

Relationships

AttributeTargetConfig
duenoUsuarioback_populates="habitos"
registrosList[RegistroHabito]back_populates="habito", cascade="all, delete-orphan"

Source

class Habito(db.Model):
    __tablename__ = 'habitos'

    id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
    usuario_id: Mapped[int] = mapped_column(ForeignKey("usuarios.id"), nullable=False)
    nombre: Mapped[str] = mapped_column(String(100), nullable=False)
    descripcion: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    dias_semana: Mapped[str] = mapped_column(String(20), nullable=False)
    fecha_creacion: Mapped[datetime] = mapped_column(DateTime, default=datetime.now)
    activo: Mapped[bool] = mapped_column(Boolean, default=True)
    racha_actual: Mapped[int] = mapped_column(Integer, default=0)
    mejor_racha: Mapped[int] = mapped_column(Integer, default=0)
    horario: Mapped[Optional[str]] = mapped_column(String(20), nullable=True)

    dueno: Mapped["Usuario"] = relationship("Usuario", back_populates="habitos")
    registros: Mapped[List["RegistroHabito"]] = relationship("RegistroHabito",
                                                             back_populates="habito",
                                                             cascade="all, delete-orphan")

RegistroHabito — table registro_habitos

RegistroHabito is the daily completion log. Each row represents one day for one habit, and the table-level UniqueConstraint enforces that the same habit cannot be marked complete more than once on the same calendar date. The fecha column uses SQLAlchemy’s Date type (date only — no time component) to keep the constraint deterministic regardless of the time zone or clock when the request arrives.
The unique constraint uq_habito_fecha_diaria on (habito_id, fecha) is the database-level guarantee that prevents duplicate completions. HabitoRepository.marcar_completado_hoy() additionally queries for an existing record before inserting, implementing a toggle (mark/unmark) at the application layer.

Columns

id
int
required
Primary key. Auto-incremented.
habito_id
int
required
Foreign key referencing habitos.id. Not null.
fecha
Date
required
The calendar date (year, month, day — no time) to which this record belongs. Defaults to date.today() at insert time.
completado
bool
Whether the habit was completed on fecha. Defaults to False. In practice, the current codebase only inserts rows when completado=True and deletes them to unmark, but the column exists to support future partial-completion states.

Table Constraint

__table_args__ = (
    UniqueConstraint('habito_id', 'fecha', name='uq_habito_fecha_diaria'),
)
This constraint is named uq_habito_fecha_diaria and prevents any habit from accumulating more than one completion record per day at the database level, independently of application logic.

Relationship

AttributeTargetConfig
habitoHabitoback_populates="registros"

Source

class RegistroHabito(db.Model):
    __tablename__ = 'registro_habitos'

    __table_args__ = (
        UniqueConstraint('habito_id', 'fecha', name='uq_habito_fecha_diaria'),
    )

    id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
    habito_id: Mapped[int] = mapped_column(ForeignKey("habitos.id"), nullable=False)
    fecha: Mapped[date] = mapped_column(Date, nullable=False, default=date.today)
    completado: Mapped[bool] = mapped_column(Boolean, default=False)

    habito: Mapped["Habito"] = relationship("Habito", back_populates="registros")

Entity-Relationship Summary

The three tables form a strict cascade hierarchy. The arrows below show foreign-key direction (child → parent).
┌─────────────────────────────────────────────────────────────────┐
│                         SCHEMA OVERVIEW                         │
├──────────────────┬──────────────────┬───────────────────────────┤
│   usuarios       │   habitos        │   registro_habitos        │
├──────────────────┼──────────────────┼───────────────────────────┤
│ PK  id           │ PK  id           │ PK  id                    │
│     correo       │ FK  usuario_id ──┼──► usuarios.id            │
│     contrasena   │     nombre       │ FK  habito_id ────────────┼──► habitos.id
│     nombre_usua  │     descripcion  │     fecha  (Date)         │
│     fecha_regis  │     dias_semana  │     completado            │
│                  │     fecha_creac  │                           │
│                  │     activo       │ UNIQUE (habito_id, fecha)  │
│                  │     racha_actual │   → uq_habito_fecha_diaria│
│                  │     mejor_racha  │                           │
│                  │     horario      │                           │
└──────────────────┴──────────────────┴───────────────────────────┘

Cascade deletes:
  Usuario  ──(delete-orphan)──►  Habito  ──(delete-orphan)──►  RegistroHabito
RelationshipTypeCascade
UsuarioHabitoOne-to-manyall, delete-orphan
HabitoRegistroHabitoOne-to-manyall, delete-orphan

Build docs developers (and LLMs) love