refactor: tighten backend, flows, frontend, tests; push flows to Langflow
This commit is contained in:
parent
6688fb08c6
commit
06ab25fb47
31 changed files with 783 additions and 358 deletions
18
backend/app/models/base.py
Normal file
18
backend/app/models/base.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
"""Shared SQLModel base: UTC timestamps, no copy-paste across models."""
|
||||
|
||||
from datetime import UTC, datetime
|
||||
|
||||
from sqlalchemy import Column, DateTime
|
||||
from sqlmodel import Field
|
||||
|
||||
|
||||
def utcnow() -> datetime:
|
||||
return datetime.now(UTC)
|
||||
|
||||
|
||||
def ts_column() -> Column:
|
||||
return Column(DateTime(timezone=True))
|
||||
|
||||
|
||||
def ts_field(*, default_factory=utcnow) -> datetime: # type: ignore[no-untyped-def]
|
||||
return Field(default_factory=default_factory, sa_column=ts_column())
|
||||
|
|
@ -1,18 +1,12 @@
|
|||
"""Flow engine domain models (SQLModel tables)."""
|
||||
|
||||
from datetime import UTC, datetime
|
||||
from datetime import datetime
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
from sqlalchemy import JSON, Column, DateTime, UniqueConstraint
|
||||
from sqlalchemy import JSON, Column, UniqueConstraint
|
||||
from sqlmodel import Field, SQLModel
|
||||
|
||||
|
||||
def utcnow() -> datetime:
|
||||
return datetime.now(UTC)
|
||||
|
||||
|
||||
def _ts_column() -> Column:
|
||||
return Column(DateTime(timezone=True))
|
||||
from .base import ts_column, utcnow
|
||||
|
||||
|
||||
def _json_column() -> Column:
|
||||
|
|
@ -34,7 +28,7 @@ class FlowDefinition(SQLModel, table=True):
|
|||
source_path: str | None = Field(default=None, max_length=255)
|
||||
# Flow to run after a human approval on this flow's runs (nullable).
|
||||
continuation_flow_id: UUID | None = Field(default=None, foreign_key="flow_definitions.id")
|
||||
created_at: datetime = Field(default_factory=utcnow, sa_column=_ts_column())
|
||||
created_at: datetime = Field(default_factory=utcnow, sa_column=ts_column())
|
||||
|
||||
|
||||
class FlowVersion(SQLModel, table=True):
|
||||
|
|
@ -49,9 +43,9 @@ class FlowVersion(SQLModel, table=True):
|
|||
langflow_json: dict = Field(default_factory=dict, sa_column=_json_column())
|
||||
# Flow id under which LFX serves this version (set on deploy).
|
||||
lfx_flow_id: str | None = Field(default=None, max_length=200)
|
||||
deployed_at: datetime | None = Field(default=None, sa_column=_ts_column())
|
||||
deployed_at: datetime | None = Field(default=None, sa_column=ts_column())
|
||||
author: str = Field(default="", max_length=200)
|
||||
created_at: datetime = Field(default_factory=utcnow, sa_column=_ts_column())
|
||||
created_at: datetime = Field(default_factory=utcnow, sa_column=ts_column())
|
||||
# Cached form schema for this exact JSON (see app/flows/input_schema.py).
|
||||
# Computed at version creation; nullable for pre-Phase-3 rows.
|
||||
input_schema: dict | None = Field(default=None, sa_column=_json_column())
|
||||
|
|
@ -70,8 +64,8 @@ class FlowRun(SQLModel, table=True):
|
|||
input: dict | None = Field(default=None, sa_column=_json_column())
|
||||
output: dict | None = Field(default=None, sa_column=_json_column())
|
||||
session_id: str | None = Field(default=None, max_length=200)
|
||||
created_at: datetime = Field(default_factory=utcnow, sa_column=_ts_column())
|
||||
finished_at: datetime | None = Field(default=None, sa_column=_ts_column())
|
||||
created_at: datetime = Field(default_factory=utcnow, sa_column=ts_column())
|
||||
finished_at: datetime | None = Field(default=None, sa_column=ts_column())
|
||||
|
||||
|
||||
class ApprovalTask(SQLModel, table=True):
|
||||
|
|
@ -90,5 +84,5 @@ class ApprovalTask(SQLModel, table=True):
|
|||
# open | approved | rejected
|
||||
status: str = Field(default="open", index=True, max_length=20)
|
||||
decision_note: str = Field(default="", max_length=2000)
|
||||
created_at: datetime = Field(default_factory=utcnow, sa_column=_ts_column())
|
||||
decided_at: datetime | None = Field(default=None, sa_column=_ts_column())
|
||||
created_at: datetime = Field(default_factory=utcnow, sa_column=ts_column())
|
||||
decided_at: datetime | None = Field(default=None, sa_column=ts_column())
|
||||
|
|
|
|||
|
|
@ -1,18 +1,11 @@
|
|||
"""Access-management domain models (SQLModel tables)."""
|
||||
|
||||
from datetime import UTC, datetime
|
||||
from datetime import datetime
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
from sqlalchemy import Column, DateTime
|
||||
from sqlmodel import Field, SQLModel
|
||||
|
||||
|
||||
def utcnow() -> datetime:
|
||||
return datetime.now(UTC)
|
||||
|
||||
|
||||
def _ts_column() -> Column:
|
||||
return Column(DateTime(timezone=True))
|
||||
from .base import ts_column, utcnow
|
||||
|
||||
|
||||
class User(SQLModel, table=True):
|
||||
|
|
@ -26,7 +19,7 @@ class User(SQLModel, table=True):
|
|||
# member | admin
|
||||
role: str = Field(default="member", max_length=20)
|
||||
tenant_id: str = Field(default="default", max_length=200)
|
||||
created_at: datetime = Field(default_factory=utcnow, sa_column=_ts_column())
|
||||
created_at: datetime = Field(default_factory=utcnow, sa_column=ts_column())
|
||||
|
||||
|
||||
class AccessRequest(SQLModel, table=True):
|
||||
|
|
@ -40,8 +33,8 @@ class AccessRequest(SQLModel, table=True):
|
|||
reason: str = Field(default="", max_length=2000)
|
||||
# pending | approved | rejected
|
||||
status: str = Field(default="pending", index=True, max_length=20)
|
||||
created_at: datetime = Field(default_factory=utcnow, sa_column=_ts_column())
|
||||
decided_at: datetime | None = Field(default=None, sa_column=_ts_column())
|
||||
created_at: datetime = Field(default_factory=utcnow, sa_column=ts_column())
|
||||
decided_at: datetime | None = Field(default=None, sa_column=ts_column())
|
||||
decided_by: str | None = Field(default=None, max_length=320)
|
||||
|
||||
|
||||
|
|
@ -53,11 +46,11 @@ class MagicLinkToken(SQLModel, table=True):
|
|||
id: UUID = Field(default_factory=uuid4, primary_key=True)
|
||||
user_id: UUID = Field(foreign_key="users.id", index=True)
|
||||
token_hash: str = Field(index=True, unique=True, max_length=64)
|
||||
expires_at: datetime = Field(sa_column=_ts_column())
|
||||
expires_at: datetime = Field(sa_column=ts_column())
|
||||
# Set before the session row is created, so a reused token can never
|
||||
# mint a second session.
|
||||
used_at: datetime | None = Field(default=None, sa_column=_ts_column())
|
||||
created_at: datetime = Field(default_factory=utcnow, sa_column=_ts_column())
|
||||
used_at: datetime | None = Field(default=None, sa_column=ts_column())
|
||||
created_at: datetime = Field(default_factory=utcnow, sa_column=ts_column())
|
||||
|
||||
|
||||
class UserSession(SQLModel, table=True):
|
||||
|
|
@ -67,6 +60,6 @@ class UserSession(SQLModel, table=True):
|
|||
|
||||
id: str = Field(primary_key=True, max_length=128)
|
||||
user_id: UUID = Field(foreign_key="users.id", index=True)
|
||||
created_at: datetime = Field(default_factory=utcnow, sa_column=_ts_column())
|
||||
expires_at: datetime = Field(sa_column=_ts_column())
|
||||
revoked_at: datetime | None = Field(default=None, sa_column=_ts_column())
|
||||
created_at: datetime = Field(default_factory=utcnow, sa_column=ts_column())
|
||||
expires_at: datetime = Field(sa_column=ts_column())
|
||||
revoked_at: datetime | None = Field(default=None, sa_column=ts_column())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue