Initial Switch to V2. Completely Overhauled Backend, Frontend and General Structure.
This commit is contained in:
@@ -18,3 +18,8 @@ class AuthorizationError(HTTPException):
|
||||
class NotFoundError(HTTPException):
|
||||
def __init__(self, resource: str = "Resource"):
|
||||
super().__init__(status_code=404, detail=f"{resource} not found")
|
||||
|
||||
|
||||
class ValidationError(HTTPException):
|
||||
def __init__(self, detail: str = "Validation error"):
|
||||
super().__init__(status_code=422, detail=detail)
|
||||
|
||||
46
backend/shared/orm.py
Normal file
46
backend/shared/orm.py
Normal file
@@ -0,0 +1,46 @@
|
||||
from datetime import datetime, timezone
|
||||
from sqlalchemy import BigInteger, Column, DateTime, Index, String, Text
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from database.postgres import Base
|
||||
|
||||
|
||||
def _now():
|
||||
return datetime.now(timezone.utc)
|
||||
|
||||
|
||||
class MigrationRun(Base):
|
||||
"""Tracks every migration script execution — what ran, when, row counts, success/failure."""
|
||||
__tablename__ = "_migration_runs"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, autoincrement=True)
|
||||
script_name = Column(String(256), nullable=False)
|
||||
ran_at = Column(DateTime(timezone=True), nullable=False, default=_now)
|
||||
source_rows = Column(BigInteger, nullable=False, default=0)
|
||||
dest_rows = Column(BigInteger, nullable=False, default=0)
|
||||
success = Column(String(8), nullable=False, default="ok") # 'ok' | 'error'
|
||||
notes = Column(Text)
|
||||
|
||||
|
||||
class AuditLog(Base):
|
||||
"""Staff action audit trail — all create/update/delete/command events."""
|
||||
__tablename__ = "audit_log"
|
||||
__table_args__ = (
|
||||
Index("idx_audit_actor", "actor_id", "occurred_at"),
|
||||
Index("idx_audit_entity", "entity_type", "entity_id", "occurred_at"),
|
||||
Index("idx_audit_action", "action", "occurred_at"),
|
||||
Index("idx_audit_occurred", "occurred_at"),
|
||||
)
|
||||
|
||||
id = Column(BigInteger, primary_key=True, autoincrement=True)
|
||||
occurred_at = Column(DateTime(timezone=True), nullable=False, default=_now)
|
||||
actor_id = Column(String(128), nullable=False)
|
||||
actor_name = Column(String(255), nullable=False)
|
||||
action = Column(String(64), nullable=False)
|
||||
# CREATE | UPDATE | DELETE | COMMAND | PUBLISH | UNPUBLISH |
|
||||
# LOGIN | LOGOUT | PERMISSION_CHANGE | STATUS_CHANGE
|
||||
entity_type = Column(String(64), nullable=False)
|
||||
# customer | order | device | melody | product | staff | ticket | note | quotation | ...
|
||||
entity_id = Column(String(128), nullable=False)
|
||||
entity_label = Column(String(500)) # denormalised human name
|
||||
changes = Column(JSONB) # {"field": {"old": x, "new": y}} — null for CREATE/DELETE
|
||||
meta = Column(JSONB) # extra context: ip_address, command_name, etc.
|
||||
Reference in New Issue
Block a user