feat: Phase 4 — inspection sessions (create, execute, complete)
All checks were successful
Deploy to Production / deploy (push) Successful in 1m5s
All checks were successful
Deploy to Production / deploy (push) Successful in 1m5s
Backend: - InspectionSession + InspectionRecord models with alembic migration - 6 API endpoints: create, list, get detail, save records, complete, delete - Auto pass/fail judgment for numeric (spec range) and boolean items - Completed inspections are immutable, required items enforced on complete - 14 new tests (total 53/53 passed) Frontend: - Inspection list page with in_progress/completed tabs - Template select modal for starting new inspections - Inspection execution page with data-type-specific inputs - Auto-save with 1.5s debounce, manual save button - Completion modal with notes and required item validation - Read-only view for completed inspections - Pass/fail badges and color-coded item cards Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
This commit is contained in:
@@ -233,3 +233,75 @@ class InspectionTemplateItem(Base):
|
||||
__table_args__ = (
|
||||
Index("ix_template_items_template_order", "template_id", "sort_order"),
|
||||
)
|
||||
|
||||
|
||||
class InspectionSession(Base):
|
||||
__tablename__ = "inspection_sessions"
|
||||
|
||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
tenant_id = Column(String(50), ForeignKey("tenants.id"), nullable=False)
|
||||
template_id = Column(
|
||||
UUID(as_uuid=True),
|
||||
ForeignKey("inspection_templates.id"),
|
||||
nullable=False,
|
||||
)
|
||||
inspector_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
|
||||
status = Column(
|
||||
String(20), nullable=False, default="draft"
|
||||
) # draft | in_progress | completed
|
||||
started_at = Column(TIMESTAMP(timezone=True), nullable=True)
|
||||
completed_at = Column(TIMESTAMP(timezone=True), nullable=True)
|
||||
notes = Column(Text, nullable=True)
|
||||
created_at = Column(TIMESTAMP(timezone=True), default=utcnow)
|
||||
updated_at = Column(TIMESTAMP(timezone=True), default=utcnow, onupdate=utcnow)
|
||||
|
||||
tenant = relationship("Tenant")
|
||||
template = relationship("InspectionTemplate")
|
||||
inspector = relationship("User")
|
||||
records = relationship(
|
||||
"InspectionRecord",
|
||||
back_populates="session",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
|
||||
__table_args__ = (
|
||||
Index("ix_sessions_tenant_status", "tenant_id", "status"),
|
||||
Index("ix_sessions_tenant_template", "tenant_id", "template_id"),
|
||||
Index("ix_sessions_tenant_inspector", "tenant_id", "inspector_id"),
|
||||
)
|
||||
|
||||
|
||||
class InspectionRecord(Base):
|
||||
__tablename__ = "inspection_records"
|
||||
|
||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
session_id = Column(
|
||||
UUID(as_uuid=True),
|
||||
ForeignKey("inspection_sessions.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
)
|
||||
template_item_id = Column(
|
||||
UUID(as_uuid=True),
|
||||
ForeignKey("inspection_template_items.id"),
|
||||
nullable=False,
|
||||
)
|
||||
value_numeric = Column(Float, nullable=True)
|
||||
value_boolean = Column(Boolean, nullable=True)
|
||||
value_text = Column(Text, nullable=True)
|
||||
value_select = Column(String(200), nullable=True)
|
||||
is_pass = Column(
|
||||
Boolean, nullable=True
|
||||
) # None = 미판정, True = 합격, False = 불합격
|
||||
recorded_at = Column(TIMESTAMP(timezone=True), nullable=True)
|
||||
created_at = Column(TIMESTAMP(timezone=True), default=utcnow)
|
||||
updated_at = Column(TIMESTAMP(timezone=True), default=utcnow, onupdate=utcnow)
|
||||
|
||||
session = relationship("InspectionSession", back_populates="records")
|
||||
template_item = relationship("InspectionTemplateItem")
|
||||
|
||||
__table_args__ = (
|
||||
UniqueConstraint(
|
||||
"session_id", "template_item_id", name="uq_record_session_item"
|
||||
),
|
||||
Index("ix_records_session", "session_id"),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user