Files
Aegis/backend/app/models/worklog.py
Kitos 9b98f60a9a
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
feat(phase-35): Jira + Tempo integration with internal worklogs
Full Jira/Tempo pipeline: link Aegis entities to Jira issues, auto-sync
status hourly, log time internally with integrity hashing, and optionally
push worklogs to Tempo.

- 1.1 JiraLink model + Worklog model: Alembic migration b020 with indexes,
  enums (jiralinkentitytype, jirasyncdirection), and integrity_hash column
- 1.2 Jira service: atlassian-python-api wrapper with lazy singleton client,
  search/create/sync operations, feature-flagged via JIRA_ENABLED
- 1.3 Jira router: CRUD endpoints for /jira/links, /jira/search,
  /jira/create-issue with audit logging and entity-to-issue auto-creation
- 1.4 Tempo service: worklog push via tempo-api-python-client, auto-log from
  test completions when TEMPO_ENABLED, graceful fallback on failure
- 1.5 Worklog service + router: immutable internal time records with SHA-256
  integrity hash, CRUD at /worklogs, /worklogs/{id}/verify endpoint
- 1.6 Frontend: JiraLinkPanel component (search, link, sync, unlink) and
  WorklogTimeline component (timeline view, manual log form) integrated into
  TestDetailPage sidebar, CampaignDetailPage grid, TechniqueDetailPage
- 1.7 Jira sync job: APScheduler hourly job syncs all links from Jira,
  registered in background scheduler alongside existing jobs
2026-02-17 15:57:39 +01:00

45 lines
1.6 KiB
Python

"""Worklog model — immutable internal time-tracking records."""
import uuid
from datetime import datetime
from sqlalchemy import Column, String, Integer, DateTime, ForeignKey, Text, Index
from sqlalchemy.dialects.postgresql import UUID, JSONB
from sqlalchemy.orm import relationship
from app.database import Base
class Worklog(Base):
"""Internal worklog entry with integrity hash for audit compliance.
Each worklog is tied to an Aegis entity (test, campaign, etc.) and
optionally synced to Tempo. The ``integrity_hash`` is a SHA-256 of
the immutable fields so tampering can be detected.
"""
__tablename__ = "worklogs"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
entity_type = Column(String(50), nullable=False)
entity_id = Column(UUID(as_uuid=True), nullable=False)
user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
activity_type = Column(String(100), nullable=False)
started_at = Column(DateTime, nullable=False)
ended_at = Column(DateTime)
duration_seconds = Column(Integer, nullable=False)
description = Column(Text)
tempo_synced = Column(DateTime)
tempo_worklog_id = Column(String(100))
integrity_hash = Column(String(64))
created_at = Column(DateTime, default=datetime.utcnow)
extra_metadata = Column("metadata", JSONB, default={})
user = relationship("User", foreign_keys=[user_id])
__table_args__ = (
Index("ix_worklogs_entity_id", "entity_id"),
Index("ix_worklogs_user_id", "user_id"),
Index("ix_worklogs_entity_type_entity_id", "entity_type", "entity_id"),
)