feat: Create form cycle model#720
Conversation
🤖 Augment PR SummarySummary: Introduces a new SQLAlchemy model to represent Qualia “form cycles” and their lifecycle state. Changes:
Technical Notes: Defaults are set both at the ORM layer and via DB 🤖 Was this summary useful? React with 👍 or 👎 |
|
|
||
|
|
||
| class FormCycleStatus(str, enum.Enum): | ||
| draft = "drafft" |
There was a problem hiding this comment.
qualia/backend/app/models/form_cycle.py:9 — The persisted enum values look misspelled ("drafft" / "publish") relative to the member names, which can lead to unexpected DB values and break comparisons/serialization.
Other locations where this applies: qualia/backend/app/models/form_cycle.py:10
Severity: high
Other Locations
qualia/backend/app/models/form_cycle.py:10
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
value:useful; category:bug; feedback:Marked useful because this comment caught bad persisted values in the new form cycle status enum. It showed that draft and published rows could store unexpected strings, so comparisons and API serialization around cycle state could silently break.
| __tablename__ = "form_cycle" | ||
|
|
||
| id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4) | ||
| status: Mapped[FormCycleStatus] = mapped_column(Enum(FormCycleStatus, name="form_cycle_status_enum"), default=FormCycleStatus.published, server_default=text("'draft'"), index=True, nullable=False) |
There was a problem hiding this comment.
qualia/backend/app/models/form_cycle.py:17 — status has conflicting defaults (default=FormCycleStatus.published vs server_default='draft'), so inserts done via ORM vs DB-defaults can produce different initial states.
Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
value:useful; category:bug; feedback:This was useful because it found a real mismatch between ORM and database defaults for the form cycle state. It meant one insert path could create a published cycle while another creates a draft cycle, which is risky for admin publishing flow.
|
|
||
| id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4) | ||
| status: Mapped[FormCycleStatus] = mapped_column(Enum(FormCycleStatus, name="form_cycle_status_enum"), default=FormCycleStatus.published, server_default=text("'draft'"), index=True, nullable=False) | ||
| version: Mapped[int] = mapped_column(Integer, default=0, server_default=text("1"), nullable=False) |
There was a problem hiding this comment.
There was a problem hiding this comment.
value:useful; category:bug; feedback:Marked useful because the comment identified inconsistent version initialization before this model is used by endpoints. It pointed out that records could start at version 0 or 1 depending on insert method, making later version checks unreliable.
| id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4) | ||
| status: Mapped[FormCycleStatus] = mapped_column(Enum(FormCycleStatus, name="form_cycle_status_enum"), default=FormCycleStatus.published, server_default=text("'draft'"), index=True, nullable=False) | ||
| version: Mapped[int] = mapped_column(Integer, default=0, server_default=text("1"), nullable=False) | ||
| is_published: Mapped[bool] = mapped_column(Boolean, default=True, server_default=false(), index=True, nullable=False) |
There was a problem hiding this comment.
There was a problem hiding this comment.
value:useful; category:bug; feedback:This comment is useful because it caught a publish flag default that did not match the database default. It meant ORM-created form cycles could become published immediately while database-created rows stayed unpublished, which matters for reviewer visibility.
|
augment review |
| from app.core.database import Base | ||
|
|
||
|
|
||
| class FormCycleStatus(str, enum.Enum): |
There was a problem hiding this comment.
FormCycleStatus currently only includes draft/published, but the existing Qualia LLD/API spec (qualia/docs/LLD.md) describes status values like draft/active/closed/archived. This mismatch can cause broken filtering/serialization once the endpoints are implemented against the documented contract.
Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
value:useful; category:bug; feedback:Marked useful because it checked the new model against the Qualia LLD instead of only the local code. It found that endpoints could later filter for active or archived cycles but the database enum would not allow those states.
| id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4) | ||
| status: Mapped[FormCycleStatus] = mapped_column(Enum(FormCycleStatus, name="form_cycle_status_enum"), default=FormCycleStatus.draft, server_default=text("'draft'"), index=True, nullable=False) | ||
| version: Mapped[int] = mapped_column(Integer, default=1, server_default=text("1"), nullable=False) | ||
| is_published: Mapped[bool] = mapped_column(Boolean, default=False, server_default=false(), index=True, nullable=False) |
There was a problem hiding this comment.
Having both status (which includes published) and a separate is_published flag risks persisting contradictory states (e.g., status=published with is_published=False) unless it’s enforced/synchronized on every write path.
Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
value:good-to-have; category:bug; feedback:This was good-to-have because it caught a design conflict before more write paths are added. It showed that a published status and is_published flag could disagree, making reviewer visibility depend on which field a query used.
| status: Mapped[FormCycleStatus] = mapped_column(Enum(FormCycleStatus, name="form_cycle_status_enum"), default=FormCycleStatus.draft, server_default=text("'draft'"), index=True, nullable=False) | ||
| version: Mapped[int] = mapped_column(Integer, default=1, server_default=text("1"), nullable=False) | ||
| is_published: Mapped[bool] = mapped_column(Boolean, default=False, server_default=false(), index=True, nullable=False) | ||
| deadline_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) |
There was a problem hiding this comment.
The column name deadline_at diverges from the documented field name submission_deadline in qualia/docs/LLD.md, which increases the chance of schema/API mismatches when schemas and endpoints are added. If the doc is authoritative, this may need alignment to avoid leaking inconsistent field names into the public API.
Severity: low
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
value:good-to-have; category:bug; feedback:Marked good-to-have because this comment kept the model field aligned with the documented API naming. It pointed out that deadline_at and submission_deadline could split the schema and response names, causing avoidable mapping mistakes later.
|
augment review |
|
|
||
|
|
||
| class FormCycle(Base): | ||
| __tablename__ = "form_cycle" |
There was a problem hiding this comment.
__tablename__ is set to form_cycle, but the repo docs/LLD refer to the table as form_cycles (plural). If migrations/queries/schemas are written against the documented name, this mismatch will cause runtime failures or duplicated tables.
Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
value:useful; category:bug; feedback:Marked useful because this comment caught a schema naming mismatch against the Qualia LLD. It showed that migrations or queries could target form_cycles while the model creates form_cycle, causing runtime failures or duplicate tables.
|
augment review |
| archived = "archived" | ||
|
|
||
|
|
||
| class FormCycle(Base): |
There was a problem hiding this comment.
FormCycle currently omits several fields/relationships documented for this table in qualia/docs/LLD.md (e.g., title, description, created_by_id, created_at/updated_at, and an index on submission_deadline). If the LLD/API contract is the target, this mismatch will force follow-up schema changes and can block implementing the documented endpoints/responses cleanly.
Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
value:useful; category:bug; feedback:Marked useful because this comment caught that the form cycle model was still too thin for the documented contract. It pointed out missing title, owner, timestamps, and deadline indexing, which would make endpoint schemas and queries need avoidable rework.
|
augment review |
| id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4) | ||
| title: Mapped[str] = mapped_column(String(255), nullable=False) | ||
| description: Mapped[str | None] = mapped_column(String(1000), nullable=True) | ||
| created_by_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("users.id"), nullable=False) |
There was a problem hiding this comment.
created_by_id is not indexed while other common filter fields (status, submission_deadline) are, and the LLD calls for an index here; listing/filtering cycles by creator could otherwise require full table scans. Consider whether this should be indexed to match expected query patterns.
Severity: low
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
value:good-to-have; category:bug; feedback:Marked good-to-have because this comment caught one missing index from the documented form cycle query pattern. It pointed out that filtering cycles by creator could scan the whole table as data grows, which would hurt admin listing performance.
|
augment review |
No description provided.