cors 문제 해결 .

This commit is contained in:
hbyang 2026-06-18 16:30:03 +09:00
parent dd03c2aecd
commit b0b787a8ce
6 changed files with 25 additions and 11 deletions

View File

@ -3,7 +3,7 @@ import json
from typing import Any, Union
from fastapi import Depends
from fastapi.responses import ORJSONResponse
from fastapi.responses import JSONResponse
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
import bcrypt
from jose import jwt, JWTError, ExpiredSignatureError
@ -109,5 +109,7 @@ def RemoveNoneValues(obj: Any) -> Any:
return obj
def RemoveNoneResponse(obj) -> ORJSONResponse:
return ORJSONResponse(content=RemoveNoneValues(obj.model_dump()))
def RemoveNoneResponse(obj) -> JSONResponse:
# mode="json": datetime/uuid 등을 JSON-safe 문자열로 변환(표준 JSONResponse 가 직렬화 가능).
# (ORJSONResponse 는 최신 FastAPI 에서 deprecated)
return JSONResponse(content=RemoveNoneValues(obj.model_dump(mode="json")))

View File

@ -35,6 +35,7 @@ class MainTableMixin(_DBTypeMixin):
# ERD 도메인 모델
class companies(MainTableMixin, MAIN_BASE):
__tablename__ = "companies"
__table_args__ = {"schema": "company"}
company_id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
name = Column(String(100), nullable=False)
@ -50,6 +51,7 @@ class companies(MainTableMixin, MAIN_BASE):
class users(MainTableMixin, MAIN_BASE):
__tablename__ = "users"
__table_args__ = {"schema": "company"}
user_id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
company_id = Column(UUID(as_uuid=True), nullable=False, index=True)
@ -65,6 +67,7 @@ class users(MainTableMixin, MAIN_BASE):
class items(MainTableMixin, MAIN_BASE):
__tablename__ = "items"
__table_args__ = {"schema": "partner"}
item_id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
company_id = Column(UUID(as_uuid=True), nullable=False, index=True)
@ -94,6 +97,7 @@ class items(MainTableMixin, MAIN_BASE):
class suppliers(MainTableMixin, MAIN_BASE):
__tablename__ = "suppliers"
__table_args__ = {"schema": "partner"}
supplier_id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
company_id = Column(UUID(as_uuid=True), nullable=False, index=True)
@ -109,6 +113,7 @@ class suppliers(MainTableMixin, MAIN_BASE):
class nego_cards(MainTableMixin, MAIN_BASE):
__tablename__ = "nego_cards"
__table_args__ = {"schema": "card"}
nego_card_id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
user_id = Column(UUID(as_uuid=True), nullable=True, index=True) # 등록 유저(o2o 기본 카드는 NULL)
@ -120,6 +125,7 @@ class nego_cards(MainTableMixin, MAIN_BASE):
class wild_cards(MainTableMixin, MAIN_BASE):
__tablename__ = "wild_cards"
__table_args__ = {"schema": "card"}
wild_card_id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
user_id = Column(UUID(as_uuid=True), nullable=True, index=True) # 등록 유저(o2o 기본 카드는 NULL)
@ -134,6 +140,7 @@ class wild_cards(MainTableMixin, MAIN_BASE):
class quotation_settings(MainTableMixin, MAIN_BASE):
__tablename__ = "quotation_settings"
__table_args__ = {"schema": "quotation"}
qt_setting_id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
user_id = Column(UUID(as_uuid=True), nullable=True, index=True) # 설정 소유 유저
@ -144,6 +151,7 @@ class quotation_settings(MainTableMixin, MAIN_BASE):
class quotations(MainTableMixin, MAIN_BASE):
__tablename__ = "quotations"
__table_args__ = {"schema": "quotation"}
qt_id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
user_id = Column(UUID(as_uuid=True), nullable=False, index=True)
@ -173,6 +181,7 @@ class quotations(MainTableMixin, MAIN_BASE):
class sessions(MainTableMixin, MAIN_BASE):
__tablename__ = "sessions"
__table_args__ = {"schema": "negotiation"}
session_id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
quotation_id = Column(UUID(as_uuid=True), nullable=False, index=True) # 소속 견적(quotations.qt_id)
@ -194,6 +203,7 @@ class sessions(MainTableMixin, MAIN_BASE):
class chats(MainTableMixin, MAIN_BASE):
__tablename__ = "chats"
__table_args__ = {"schema": "negotiation"}
chat_id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
session_id = Column(UUID(as_uuid=True), nullable=False, index=True) # 소속 세션(sessions.session_id)

View File

@ -3,7 +3,7 @@ import json
from typing import Any, Union
from fastapi import Depends
from fastapi.responses import ORJSONResponse
from fastapi.responses import JSONResponse
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
import bcrypt
from jose import jwt, JWTError, ExpiredSignatureError
@ -109,7 +109,8 @@ def RemoveNoneValues(obj: Any) -> Any:
return obj
def RemoveNoneResponse(obj) -> ORJSONResponse:
def RemoveNoneResponse(obj) -> JSONResponse:
# mode="json": uuid/datetime 등 DB 네이티브 타입(asyncpg.UUID 포함)을 pydantic 단에서
# JSON 안전한 문자열로 변환한다. (python 모드면 orjson 이 asyncpg.UUID 를 직렬화 못 함)
return ORJSONResponse(content=RemoveNoneValues(obj.model_dump(mode="json")))
# JSON 안전한 문자열로 변환한다. content 가 이미 JSON-safe dict 이므로 표준 JSONResponse 사용
# (ORJSONResponse 는 최신 FastAPI 에서 deprecated).
return JSONResponse(content=RemoveNoneValues(obj.model_dump(mode="json")))

View File

@ -1,4 +1,5 @@
FROM node:20-alpine
# node 22 (orval 은 node>=22.18 요구) + Debian slim(glibc) — alpine(musl)+esbuild 의 ETXTBSY 회피.
FROM node:22-slim
WORKDIR /app

View File

@ -151,7 +151,7 @@ CREATE TABLE IF NOT EXISTS partner.items (
lead_time SMALLINT NULL, -- 상품 주문 완료 후, 배송 도착까지의 시간
manufacturer VARCHAR(50) NULL, -- 제조사
made_in VARCHAR(100) NULL, -- 원산지
quantity_unit SMALLINT NULL, -- 상품 취급 단위 (코드: 예 EA/BOX/SET, 앱 enum 매핑)
quantity_unit VARCHAR(50) NULL, -- 상품 취급 단위 라벨(자유입력): EA/BOX/SET/ROLL ... (ORM String 기준)
delivery_type SMALLINT NULL, -- 배송 유형 (코드, 앱 enum 매핑)
vat_yn BOOLEAN NULL, -- 부가세 포함 여부
delivery_fee_yn BOOLEAN NULL, -- 배송비 포함 여부

View File

@ -13,13 +13,13 @@ WHERE NOT EXISTS (
SELECT 1 FROM company.companies WHERE company_id = '00000000-0000-0000-0000-000000000001'
);
-- admin 유저. password 는 'admin1234' 의 bcrypt 해시(백엔드 GetHashedPW 와 동일 알고리즘, checkpw 로 검증됨).
-- admin 유저. password 는 'admin123' 의 bcrypt 해시(백엔드 GetHashedPW 와 동일 알고리즘, checkpw 로 검증됨).
-- role 2=manager (UserRole.MANAGER; ADMIN 코드는 enum 에 없어 최상위인 MANAGER 사용). status 1=active.
INSERT INTO company.users (user_id, company_id, id, password, name, email, last_accessed_at, status, role)
SELECT '00000000-0000-0000-0000-000000000002',
'00000000-0000-0000-0000-000000000001',
'admin',
'$2b$12$oq5qlcYQ4BNywh9iS7cF1OBP6kGBvB6SfsGgVknCiJ6lMSW5cjW.C',
'$2b$12$KY4T0kXQ2npvvt71iWZG0.JZHlMNt9angIkE/7.lBC4vta4dHgrj2',
'admin', 'admin@negosium.dev', now(), 1, 2
WHERE NOT EXISTS (
SELECT 1 FROM company.users WHERE id = 'admin' AND deleted = FALSE