Files
leehc991028andClaude Fable 5.1 2869985139 feat(backend): Django + OpenCode 백엔드 추가 — 5_django_backend/
앱이 기대하는 base-backend 계약(envelope·JWT·/chat/stream SSE)을 그대로 구현.
Django 는 로그인·세션 미러(SQLite/PG)·OpenCode 이벤트 번역만 맡고, 답변은 전용
OpenCode 인스턴스(opencode/ workspace, codeassist 에이전트)가 만듦.
- accounts: 이메일 로그인, access 60분 / refresh 14일, entra/config 는 501
- chat: 세션 목록·검색·메시지·취소 + POST /chat/stream 어댑터(part.delta→token,
  idle→usage/done, 클라 끊겨도 턴 감시 태스크가 DB 마무리, 첫 이벤트 60초 타임아웃)
- OpenCode 1.18 멀티 프로젝트라 모든 요청에 ?directory= 부착
- docs-lib 에 OpenCode SDK 1.18.6 타입 원본, pytest 32

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 21:28:31 +09:00

42 lines
1.5 KiB
Python

"""사용자 — 프론트 `types/api.ts` UserPayload/UserResponse 모양으로 내보냄.
로그인 키는 email. username 은 email 과 같은 값으로 채움(Django 필수 칸이라)."""
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
email = models.EmailField("이메일", unique=True)
user_name = models.CharField("표시 이름", max_length=40, blank=True)
employee_id = models.CharField("사번", max_length=40, blank=True)
department = models.CharField("부서", max_length=80, blank=True)
class Meta:
verbose_name = "사용자"
verbose_name_plural = "사용자"
@property
def role(self) -> str:
return "ADMIN" if self.is_superuser else "USER"
def as_payload(self) -> dict:
"""UserPayload — 로그인 응답 안의 user."""
return {
"id": str(self.id),
"email": self.email,
"userName": self.user_name or None,
"role": self.role,
"employeeId": self.employee_id or None,
"department": self.department or None,
"authProvider": "local",
}
def as_response(self) -> dict:
"""UserResponse — GET /users/me."""
return {
**self.as_payload(),
"isActive": self.is_active,
"createdAt": self.date_joined.isoformat(),
"updatedAt": (self.last_login or self.date_joined).isoformat(),
}