- tbl_account 예시 인증 제거, supplier_users 기반으로 일원화(generic 네이밍 재사용) - DBType USER/PARTNER 분리, AccountStatus/UserRole/TokenType enum 추가 - 보호 요청 시 su_id DB 존재/활성 검증(stateless JWT 빈틈 보완), 공급사명(partner.suppliers) 응답 포함 - 로그인 시 단일 세션 access/refresh 토큰을 supplier_user_tokens 에 저장(재로그인 시 교체) - greenlet 의존성 추가, 인증 e2e 테스트(test_auth.py) 재작성 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
78 lines
6.1 KiB
Python
78 lines
6.1 KiB
Python
from sqlalchemy.orm import declarative_base
|
|
from sqlalchemy import Column, Integer, String, Boolean, DateTime, SmallInteger
|
|
from sqlalchemy.dialects.postgresql import UUID, JSONB
|
|
from sqlalchemy.sql import text
|
|
|
|
from common.enums import DBType
|
|
|
|
# 모든 ORM 모델의 베이스. insert 시 isinstance 체크에도 사용된다.
|
|
MAIN_BASE = declarative_base()
|
|
|
|
|
|
class supplier_users(MAIN_BASE):
|
|
# 이 프로젝트의 기본 유저. 실제 테이블은 negosium_db 의 supplier 스키마(supplier_users).
|
|
@staticmethod
|
|
def DBType():
|
|
return DBType.USER.value
|
|
|
|
__tablename__ = "supplier_users"
|
|
__table_args__ = {"schema": "supplier"}
|
|
|
|
# gen_random_uuid() 는 pgcrypto 확장 기준. 코드값(status/role/type)은 SMALLINT 정수 코드(앱 enum 매핑).
|
|
su_id = Column(UUID(as_uuid=True), primary_key=True, server_default=text("gen_random_uuid()")) # 유저 식별자(PK)
|
|
supplier_id = Column(UUID(as_uuid=True), nullable=False) # 소속 공급사(partner.suppliers.supplier_id)
|
|
id = Column(String(20), nullable=False) # 로그인 ID
|
|
password = Column(String(255), nullable=False) # 해시된 비밀번호이어야 함
|
|
name = Column(String(50), nullable=True) # 이름
|
|
email = Column(String(255), nullable=True) # 이메일
|
|
contact_number = Column(String(20), nullable=True) # 연락처
|
|
last_accessed_at = Column(DateTime(timezone=True), nullable=False) # 마지막 접속 시각
|
|
status = Column(SmallInteger, nullable=False, server_default=text("1")) # 상태: 1=active, 2=inactive
|
|
role = Column(SmallInteger, nullable=False, server_default=text("1")) # 권한: 1=user, 2=manager
|
|
created_at = Column(DateTime(timezone=True), nullable=False, server_default=text("(now() AT TIME ZONE 'utc')")) # 생성 시각(UTC)
|
|
updated_at = Column(DateTime(timezone=True), nullable=False, server_default=text("(now() AT TIME ZONE 'utc')")) # 수정 시각(UTC, 앱에서 갱신)
|
|
deleted = Column(Boolean, nullable=False, server_default=text("false")) # 소프트 삭제 여부
|
|
|
|
|
|
class suppliers(MAIN_BASE):
|
|
# partner.suppliers (공급사 회사). 공급사명(name) 조회용. partner 도메인이라 DBType 은 PARTNER.
|
|
@staticmethod
|
|
def DBType():
|
|
return DBType.PARTNER.value
|
|
|
|
__tablename__ = "suppliers"
|
|
__table_args__ = {"schema": "partner"}
|
|
|
|
supplier_id = Column(UUID(as_uuid=True), primary_key=True, server_default=text("gen_random_uuid()")) # 공급사 식별자(PK)
|
|
company_id = Column(UUID(as_uuid=True), nullable=False) # 소속 회사(company.companies.company_id)
|
|
user_id = Column(UUID(as_uuid=True), nullable=False) # 등록 유저(company.users.user_id)
|
|
name = Column(String(100), nullable=False) # 공급사명
|
|
code = Column(String(20), nullable=True) # 공급사 코드
|
|
manager_name = Column(String(50), nullable=True) # 담당자명
|
|
manager_email = Column(String(255), nullable=True) # 담당자 이메일
|
|
manager_contact_number = Column(String(20), nullable=True) # 담당자 연락처
|
|
priority = Column(String(10), nullable=True) # 우선순위 (고객사별 문자열 값 가능)
|
|
created_at = Column(DateTime(timezone=True), nullable=False, server_default=text("(now() AT TIME ZONE 'utc')")) # 생성 시각(UTC)
|
|
updated_at = Column(DateTime(timezone=True), nullable=False, server_default=text("(now() AT TIME ZONE 'utc')")) # 수정 시각(UTC, 앱에서 갱신)
|
|
deleted = Column(Boolean, nullable=False, server_default=text("false")) # 소프트 삭제 여부
|
|
|
|
|
|
class supplier_user_tokens(MAIN_BASE):
|
|
# 유저 인증 토큰. supplier_users 1 : N tokens.
|
|
@staticmethod
|
|
def DBType():
|
|
return DBType.USER.value
|
|
|
|
__tablename__ = "supplier_user_tokens"
|
|
__table_args__ = {"schema": "supplier"}
|
|
|
|
sut_id = Column(UUID(as_uuid=True), primary_key=True, server_default=text("gen_random_uuid()")) # 토큰 식별자(PK)
|
|
su_id = Column(UUID(as_uuid=True), nullable=False) # 소유 유저(supplier.supplier_users.su_id)
|
|
type = Column(SmallInteger, nullable=False) # 토큰 종류 (코드, 앱 enum 매핑)
|
|
token = Column(JSONB, nullable=False) # 토큰 본문(JSON)
|
|
issued_at = Column(DateTime(timezone=True), nullable=False) # 발급 시각
|
|
expired_at = Column(DateTime(timezone=True), nullable=False) # 만료 시각
|
|
created_at = Column(DateTime(timezone=True), nullable=False, server_default=text("(now() AT TIME ZONE 'utc')")) # 생성 시각(UTC)
|
|
updated_at = Column(DateTime(timezone=True), nullable=False, server_default=text("(now() AT TIME ZONE 'utc')")) # 수정 시각(UTC, 앱에서 갱신)
|
|
deleted = Column(Boolean, nullable=False, server_default=text("false")) # 소프트 삭제 여부
|