PDF-accessibility-saas/backend/app/models/job.py
Vadym Samoilenko fc6f4a12e6 Phase 2+3: FastAPI backend + multi-tenancy schema
Backend (replaces PHP api.php + auth.php):
- FastAPI app with routers: jobs, auth, billing
- Supabase JWT authentication in deps.py
- Celery + Redis job queue (process_pdf_task)
- MinIO S3-compatible storage service
- PDF checker wrapper (delegates to enterprise_pdf_checker.py)
- Stripe billing: checkout, portal, webhook handler

Multi-tenancy (Phase 3):
- Alembic migration 001: workspaces, workspace_members, jobs, usage_events
- Row-Level Security on all tenant tables via app.workspace_id session var
- Monthly quota enforcement per workspace (402 on exceeded)
- Plan tiers: free(5) / pro(100) / business(unlimited)

Config:
- pydantic-settings based config.py (no hardcoded values)
- docker-compose.yml rewritten: postgres, redis, minio, api, celery

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 14:46:05 +01:00

23 lines
1.4 KiB
Python

import uuid
from datetime import datetime
from sqlalchemy import String, Integer, Float, DateTime, ForeignKey, Text, func
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.dialects.postgresql import UUID, JSONB
from app.db import Base
class Job(Base):
__tablename__ = "jobs"
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
workspace_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("workspaces.id", ondelete="CASCADE"), nullable=False)
user_id: Mapped[str] = mapped_column(String(255), nullable=False)
filename: Mapped[str] = mapped_column(String(500), nullable=False)
file_size: Mapped[int] = mapped_column(Integer, nullable=True)
status: Mapped[str] = mapped_column(String(50), default="pending") # pending|processing|completed|failed
accessibility_score: Mapped[float | None] = mapped_column(Float, nullable=True)
result: Mapped[dict | None] = mapped_column(JSONB, nullable=True)
error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)