개발자 성향(DBTI) 기반 맞춤 프로젝트 추천 및 커뮤니티 서비스
Dit은 개발자가 포트폴리오 프로젝트를 준비할 때 겪는 "무엇을 만들지 모르겠다"는 문제에서 출발한 서비스입니다.
사용자는 DBTI 검사를 통해 자신의 개발 성향을 확인하고, AI 챗봇 Diti에게 DBTI 결과와 프로필 정보를 반영한 프로젝트를 추천받을 수 있습니다. 추천받은 프로젝트는 저장해 마이페이지에서 다시 확인할 수 있으며, 커뮤니티를 통해 개발 경험과 프로젝트 아이디어를 공유할 수 있습니다.
- 👥 팀원 정보 및 업무 분담
- 🎯 목표 서비스 및 구현 정도
- 🛠️ 기술 스택
- ✨ 핵심 기능
- 🤖 추천 알고리즘 및 AI 추천 구조
- 🧠 생성형 AI 활용
- 📡 API 명세서
- 🖼️ 와이어프레임
- 🗄️ 데이터베이스 모델링 ERD
- 🔐 사용자 플로우 및 권한 정책
- 📁 프로젝트 구조
- 🚀 실행 방법
- 🔗 서비스 URL
| 이름 | 담당 영역 | 주요 구현 내용 |
|---|---|---|
| 정서영 | 회원 인증, 마이페이지, AI 프로젝트 추천, 저장 프로젝트, 커뮤니티 주요 기능 | 로그인/회원가입, 로그인 상태 유지, 마이페이지/계정 설정, 비밀번호 변경/계정 삭제, Diti AI 추천 챗봇, 추천 프로젝트 상세/찜하기, 저장 프로젝트 관리, 커뮤니티 게시글/댓글 CRUD |
| 양혜림 | 프로젝트 초기 세팅, 홈, DBTI, 트렌드, 커뮤니티 검색, 공통 UI | Vue/Django 초기 세팅, 홈 화면, DBTI 검사/결과, DBTI 질문/유형 데이터 구성, 기술 트렌드 시각화, 커뮤니티 검색, 라우터 접근 제어, Navbar/아이콘/반응형 UI 개선 |
- DRF Token 기반 로그인/회원가입 API 연동
- 로그인 상태 유지 옵션에 따라
localStorage/sessionStorage분리 저장 - Pinia 기반 사용자 상태 관리 및 새로고침 시 사용자 정보 캐싱
- 마이페이지 프로필 조회/수정, 검사 기록, 저장 프로젝트 연동
- 계정 설정 페이지의 보안/상태 탭, 비밀번호 변경, 계정 삭제, 약관 모달 구현
- AI 추천 요청 시 DBTI, 희망 직무, 전공, 보유 기술을 함께 전달하는 개인화 추천 흐름 구현
- AI 응답을 JSON으로 받아 추천 카드, 상세 모달, 추천 이유 박스로 렌더링
- 추천 프로젝트 찜하기/찜 취소 및 마이페이지 저장 프로젝트 관리
- 커뮤니티 게시글/댓글 CRUD, 페이지네이션, 더보기 로직 구현
- Vue 3 + Vite 프론트엔드 초기 구조 구성
- Django REST Framework 백엔드 초기 구조 구성
- 홈 화면 및 기술 트렌드 데이터 시각화 구현
- DBTI 질문, 선택지, 유형, 궁합 데이터 구성
- DBTI 검사 진행 및 결과 페이지 구현
- 마이페이지 DBTI 검사 기록 API 연결
- DBTI 결과 페이지 직접 URL 접근 제한
- 커뮤니티 검색 기능 및 공통 UI 개선
| 목표 기능 | 구현 정도 | 설명 |
|---|---|---|
| 회원가입/로그인 | 완료 | 이메일 기반 회원가입, 로그인, 로그아웃, 토큰 인증 구현 |
| 로그인 상태 유지 | 완료 | 체크 여부에 따라 localStorage 또는 sessionStorage 저장 |
| DBTI 검사 | 완료 | 질문/선택지 기반 검사 진행 및 DBTI 결과 산출 |
| DBTI 결과 조회 | 완료 | 유형 설명, 강점, 추천 키워드, 최신 결과 조회 |
| AI 프로젝트 추천 | 완료 | DBTI + 프로필 + 사용자 입력 기반 프로젝트 3개 추천 |
| 추천 상세 기획 | 완료 | 타깃 사용자, 문제, 핵심 기능, 사용자 흐름, 포트폴리오 포인트 제공 |
| 프로젝트 저장 | 완료 | 추천 프로젝트 찜하기/찜 취소, 마이페이지 저장 목록 조회 |
| 마이페이지 | 완료 | 프로필, 최신 DBTI, 검사 기록, 저장 프로젝트, 계정 설정 제공 |
| 계정 관리 | 완료 | 비밀번호 변경, 계정 삭제, 계정 상태 안내, 약관 모달 |
| 커뮤니티 | 완료 | 카테고리, 게시글 CRUD, 댓글 작성/삭제, 검색, 더보기 |
| 기술 트렌드 | 완료 | 홈 화면에서 기술 스택/AI 도구/프레임워크/DB 트렌드 표시 |
| 배포 | 미진행 | 로컬 개발 환경 기준으로 구현 |
- Vue 3
- Vite
- Vue Router
- Pinia
- Axios
- Bootstrap 5
- HTML2Canvas
- HTML / CSS / JavaScript
- Python
- Django 5.2.4
- Django REST Framework
- DRF Token Authentication
- django-allauth
- dj-rest-auth
- django-cors-headers
- requests
- SQLite
- Django ORM
- OpenAI Chat Completions 호환 API
gpt-5-nano- Django 백엔드에서
requests로 직접 호출 .env기반 API Key, API URL, Model 관리
- Git / GitLab
- Visual Studio Code
- Figma
- Notion
- Chrome DevTools
- 개발자의 협업 방식, 문제 해결 방식, 구현 성향을 진단합니다.
- 질문별 선택지의 score 값을 기반으로 DBTI 유형을 산출합니다.
- 결과 페이지에서 유형명, 설명, 강점, 추천 키워드를 제공합니다.
- 최신 DBTI 결과는 마이페이지와 프로젝트 추천에 활용됩니다.
- 사용자의 최신 DBTI, 희망 직무, 전공, 보유 기술을 추천 요청에 포함합니다.
- 사용자가 자유롭게 입력한 도메인/주제/조건을 함께 반영합니다.
- AI는 프로젝트 3개를 추천하고, 각 프로젝트에 다음 정보를 포함합니다.
- 제목
- 카테고리
- 요약
- 난이도
- 예상 기간
- 추천 기술 스택
- 추천 이유
- 상세 기획 정보
추천 프로젝트는 단순 제목 추천에서 끝나지 않고, 기획서 형태의 상세 정보를 제공합니다.
- 타깃 사용자
- 해결하려는 문제
- 핵심 기능
- 사용자 흐름
- 데이터 흐름
- 확장 아이디어
- 포트폴리오에서 강조할 수 있는 역량
- 추천받은 프로젝트를 찜할 수 있습니다.
- 이미 저장한 프로젝트를 다시 누르면 찜이 취소됩니다.
- 저장한 프로젝트는 마이페이지에서 다시 확인할 수 있습니다.
- 저장 프로젝트에서도 상세 보기와 찜 취소가 가능합니다.
- 사용자 프로필 조회/수정
- 최신 DBTI 결과 요약
- DBTI 검사 기록 조회
- 저장한 프로젝트 조회
- 계정 설정
- 계정 정보 확인
- 비밀번호 변경
- 계정 삭제
- 계정 상태 확인
- Dit 이용 약관/커뮤니티 지침 모달
- 자유게시판, 질문답변, 프로젝트 홍보, 정보공유 카테고리 제공
- 게시글 작성/조회/수정/삭제
- 댓글 작성/삭제
- 카테고리별 필터링
- 제목/내용/작성자 기반 검색
- 더보기 기반 페이지네이션
Dit의 추천은 규칙 기반 DBTI 결과와 생성형 AI 추천을 함께 사용합니다.
DBTI 검사는 질문별 선택지에 부여된 score 값을 기반으로 사용자의 개발 성향을 산출합니다.
사용자 응답
→ 선택지별 score 집계
→ DBTI 유형 결정
→ DbtiTestResult 저장
→ 최신 DBTI 결과를 추천/마이페이지에서 활용
DBTI 유형 데이터는 dbti_types.json에 정의되어 있으며, 각 유형은 다음 정보를 포함합니다.
- type_code
- type_name
- short_description
- description
- strengths
- recommended_keywords
- character_image
프로젝트 추천 페이지에서 사용자가 메시지를 입력하면 프론트엔드는 사용자 입력에 프로필 정보를 함께 붙여 백엔드로 전달합니다.
[사용자 프로필]
DBTI: TDL
희망 직무: 프론트엔드
전공: 경영학과
보유 기술: Java, JavaScript, Vue, Python, React
[사용자 메시지]
금융 쪽 프로젝트 추천해줘
이 구조를 선택한 이유는 AI가 마지막 사용자 입력만 보고 추천하지 않고, 사용자의 성향과 현재 역량을 함께 고려하도록 하기 위해서입니다.
추천 요청은 ProjectRecommendationSession 단위로 관리됩니다.
추천 세션 생성
→ 사용자 메시지 저장
→ 같은 세션의 대화 히스토리 조회
→ developer 프롬프트 + 대화 히스토리로 AI API 호출
→ AI 응답 저장
→ 추천 프로젝트 DB 저장
대화 히스토리를 함께 전달하기 때문에 사용자가 조건을 나눠 말하거나, "다른 프로젝트 추천해줘"처럼 이어지는 요청을 해도 이전 맥락을 반영할 수 있습니다.
AI 응답은 프론트 UI에서 바로 사용할 수 있도록 JSON 형식으로 강제했습니다.
{
"message": "채팅창에 보여줄 짧은 답변",
"recommendation_reason": "추천 이유 박스에 보여줄 자연스러운 설명",
"quick_options": [],
"projects": [
{
"title": "개인 소비 패턴 분석 대시보드",
"category": "금융 웹앱",
"summary": "소비 내역을 시각화하고 월별 지출 패턴을 분석하는 서비스",
"difficulty": "보통",
"expected_period": "2주",
"skills": ["Vue", "JavaScript", "Chart.js"],
"reason": "프론트엔드 구현력과 데이터 시각화 역량을 보여주기 좋습니다.",
"rank": 1,
"detail": {
"target_users": "소비 습관을 관리하고 싶은 개인 사용자",
"problem": "지출 흐름을 한눈에 파악하기 어렵다",
"core_features": ["소비 입력", "카테고리별 시각화", "월별 리포트"],
"user_flow": ["소비 내역 입력", "대시보드 확인", "월간 리포트 조회"],
"data_flow": "사용자 입력 데이터를 카테고리별로 집계하고 차트로 표시",
"extension_ideas": ["예산 초과 알림", "CSV 내보내기"],
"portfolio_points": ["데이터 시각화", "상태 관리", "사용자 경험 설계"]
}
}
]
}JSON을 강제한 이유는 AI 응답을 단순 텍스트가 아니라 서비스 데이터처럼 사용하기 위해서입니다. 추천 결과는 카드, 상세 모달, 추천 이유 박스에 각각 연결됩니다.
AI가 생성한 추천 결과와 사용자가 저장한 프로젝트는 분리해서 관리합니다.
RecommendedProject
AI 추천 세션에 속한 추천 결과
Project
사용자가 저장할 수 있는 프로젝트 데이터
SavedProject
사용자와 Project를 연결하는 찜/저장 테이블
사용자가 찜하기를 누르면 RecommendedProject를 기반으로 Project를 생성하거나 조회하고, SavedProject로 사용자와 연결합니다. 이미 저장되어 있으면 삭제하여 찜 취소로 동작합니다.
- 프로젝트 추천 챗봇 Diti
- 추천 이유 생성
- 프로젝트 상세 기획 정보 생성
- 프론트엔드에서 직접 AI API를 호출하지 않습니다.
- Django 백엔드에서
.env에 저장된 API Key를 사용해 외부 LLM API를 호출합니다. - API Key 노출을 방지하고, 응답 파싱 및 예외 처리를 서버에서 관리하기 위한 구조입니다.
- Diti의 역할과 말투 정의
- 항상 한국어 존댓말 사용
- JSON 외의 텍스트 반환 금지
- 사용자 프로필 태그 적극 반영
- 사용자가 주제/도메인을 입력하면 추가 질문 없이 바로 추천
- 모호한 경우에만 quick options 제공
- 추천 시 프로젝트는 반드시 3개
- 각 프로젝트에 상세 기획 정보 포함
- AI API timeout 발생 시 504 응답 반환
- AI 응답 JSON 파싱 실패 시 기본 메시지 형태로 fallback
- 프론트에서는 실패 시 사용자에게 재시도 메시지 표시
| Method | Endpoint | 인증 | 설명 |
|---|---|---|---|
| POST | /signup/ |
- | 회원가입 |
| GET | /check-email/ |
- | 이메일 중복 확인 |
| GET | /check-nickname/ |
- | 닉네임 중복 확인 |
| POST | /login/ |
- | 로그인 (토큰 발급) |
| POST | /logout/ |
필요 | 로그아웃 |
| GET | /me/ |
필요 | 내 정보 조회 |
| POST | /password/ |
필요 | 비밀번호 변경 |
| DELETE | /account/ |
필요 | 계정 삭제 |
| Method | Endpoint | 인증 | 설명 |
|---|---|---|---|
| GET / PATCH | /profile/ |
필요 | 마이페이지 프로필 조회/수정 |
| GET | /dbti-results/ |
필요 | DBTI 검사 기록 목록 조회 |
| Method | Endpoint | 인증 | 설명 |
|---|---|---|---|
| GET | /types/ |
- | DBTI 유형 전체 목록 |
| GET | /types/<code>/ |
- | DBTI 유형 상세 |
| GET | /questions/ |
- | DBTI 검사 질문 목록 |
| POST | /results/ |
필요 | DBTI 검사 결과 생성 |
| GET | /results/latest/ |
필요 | 최신 DBTI 결과 조회 |
| GET | /results/<id>/ |
필요 | DBTI 결과 상세 조회 |
| Method | Endpoint | 인증 | 설명 |
|---|---|---|---|
| GET / POST | /sessions/ |
필요 | 추천 세션 목록 조회 / 생성 |
| GET | /sessions/<id>/ |
필요 | 추천 세션 상세(대화 히스토리) 조회 |
| POST | /sessions/<id>/messages/ |
필요 | 메시지 전송 및 AI 추천 응답 생성 |
| Method | Endpoint | 인증 | 설명 |
|---|---|---|---|
| GET / POST | /saved/ |
필요 | 저장 프로젝트 목록 조회 / 찜하기 |
| DELETE | /saved/<id>/ |
필요 | 저장 프로젝트 삭제(찜 취소) |
| Method | Endpoint | 인증 | 설명 |
|---|---|---|---|
| GET | /categories/ |
- | 카테고리 목록 |
| GET / POST | /posts/ |
GET: - / POST: 필요 | 게시글 목록 조회 / 작성 |
| GET / PATCH / DELETE | /posts/<id>/ |
GET: - / PATCH·DELETE: 필요(작성자) | 게시글 상세 조회 / 수정 / 삭제 |
| POST | /posts/<id>/comments/ |
필요 | 댓글 작성 |
| DELETE | /comments/<id>/ |
필요 | 댓글 삭제(작성자) |
| Method | Endpoint | 인증 | 설명 |
|---|---|---|---|
| GET | /trends/tech-stacks/ |
- | 기술 스택 트렌드 |
| GET | /trends/ai-tools/ |
- | AI 도구 트렌드 |
| GET | /trends/frameworks/ |
- | 프레임워크 트렌드 |
| GET | /trends/databases/ |
- | DB 트렌드 |
| GET | /home/stats/ |
- | 홈 통계 (DBTI 검사 수, 추천 프로젝트 수) |
인증이 필요한 요청은
Authorization: Token <token>헤더로 DRF Token을 전달합니다.
erDiagram
User ||--|| UserProfile : has
User ||--o{ DbtiTestResult : takes
DbtiType ||--o{ DbtiTestResult : result_type
DbtiType ||--o{ DbtiCompatibility : base_type
DbtiType ||--o{ DbtiCompatibility : target_type
DbtiQuestion ||--o{ DbtiOption : has
User ||--o{ ProjectRecommendationSession : owns
DbtiTestResult ||--o{ ProjectRecommendationSession : based_on
ProjectRecommendationSession ||--o{ RecommendationMessage : has
ProjectRecommendationSession ||--o{ RecommendedProject : recommends
User ||--o{ SavedProject : saves
Project ||--o{ SavedProject : saved_as
User ||--o{ Post : writes
CommunityCategory ||--o{ Post : contains
Post ||--o{ Comment : has
User ||--o{ Comment : writes
User {
int id PK
string email
string nickname
datetime created_at
datetime updated_at
}
UserProfile {
int id PK
int user_id FK
string profile_image
string major
string desired_job
string skills
string bio
}
DbtiType {
string type_code PK
string type_name
string short_description
text description
json strengths
json recommended_keywords
string character_image
}
DbtiQuestion {
int id PK
int question_order
string question_text
}
DbtiOption {
int id PK
int question_id FK
string option_text
string description
string score_value
}
DbtiTestResult {
int id PK
int user_id FK
string dbti_type_id FK
datetime created_at
}
ProjectRecommendationSession {
int id PK
int user_id FK
int dbti_result_id FK
text desired_idea
string expected_period
string service_purpose
string preferred_difficulty
string status
}
RecommendationMessage {
int id PK
int session_id FK
string sender
text message
datetime created_at
}
RecommendedProject {
int id PK
int session_id FK
string title
string category
string summary
string difficulty
string expected_period
json skills
text reason
json detail
int rank
}
Project {
int id PK
string title
string category
string summary
text description
string difficulty
string expected_period
text portfolio_point
json skills
json detail
}
SavedProject {
int id PK
int user_id FK
int project_id FK
datetime created_at
}
CommunityCategory {
int id PK
string name
string slug
int order
}
Post {
int id PK
int user_id FK
int category_id FK
string title
text content
datetime created_at
datetime updated_at
}
Comment {
int id PK
int post_id FK
int user_id FK
text content
datetime created_at
datetime updated_at
}
회원가입/로그인
→ DBTI 검사
→ DBTI 결과 확인
→ 프로젝트 추천 페이지 이동
→ Diti와 대화 또는 조건 선택
→ AI 추천 프로젝트 확인
→ 상세 보기
→ 프로젝트 저장
→ 마이페이지에서 저장 프로젝트 관리
→ 커뮤니티에서 아이디어 공유
| 기능 | 비회원 | 로그인 사용자 | 작성자/소유자 |
|---|---|---|---|
| 홈 조회 | 가능 | 가능 | 가능 |
| 회원가입/로그인 | 가능 | 불필요 | 불필요 |
| DBTI 메인 조회 | 가능 | 가능 | 가능 |
| DBTI 검사 | 불가 | 가능 | 가능 |
| DBTI 결과 상세 | 제한 | 본인 결과 중심 접근 | 본인 결과 접근 |
| 프로젝트 추천 | 불가 | 가능 | 가능 |
| 추천 프로젝트 저장 | 불가 | 가능 | 본인 추천 결과만 가능 |
| 저장 프로젝트 조회/삭제 | 불가 | 가능 | 본인 저장 프로젝트만 가능 |
| 마이페이지 조회/수정 | 불가 | 가능 | 본인 정보만 가능 |
| 비밀번호 변경/계정 삭제 | 불가 | 가능 | 본인 계정만 가능 |
| 커뮤니티 목록/상세 조회 | 가능 | 가능 | 가능 |
| 커뮤니티 글 작성 | 불가 | 가능 | 가능 |
| 커뮤니티 글 수정/삭제 | 불가 | 불가 | 작성자만 가능 |
| 댓글 작성 | 불가 | 가능 | 가능 |
| 댓글 삭제 | 불가 | 불가 | 작성자만 가능 |
- 프론트엔드
- Vue Router
beforeEach로 로그인 필요 페이지 접근 제한 - 로그인하지 않은 사용자가 프로젝트 추천, DBTI 검사/결과 등에 접근하면 로그인 페이지로 이동
- Vue Router
- 백엔드
- DRF
IsAuthenticated,IsAuthenticatedOrReadOnly사용 - 게시글/댓글 수정 삭제 시 작성자 검증
- 추천 프로젝트 저장 시
session__user=request.user조건으로 본인 추천 결과만 저장 가능 - 저장 프로젝트 조회/삭제 시
user=request.user조건으로 본인 데이터만 접근 가능
- DRF
Dit
├── README.md
├── backend
│ ├── .gitignore
│ ├── manage.py
│ ├── requirements.txt
│ ├── accounts
│ │ ├── __init__.py
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── models.py
│ │ ├── mypage_urls.py
│ │ ├── serializers.py
│ │ ├── tests.py
│ │ ├── urls.py
│ │ ├── views.py
│ │ └── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── community
│ │ ├── __init__.py
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── models.py
│ │ ├── serializers.py
│ │ ├── tests.py
│ │ ├── urls.py
│ │ ├── views.py
│ │ ├── fixtures
│ │ │ └── community_categories.json
│ │ └── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── config
│ │ ├── __init__.py
│ │ ├── asgi.py
│ │ ├── settings.py
│ │ ├── urls.py
│ │ └── wsgi.py
│ ├── dbti
│ │ ├── __init__.py
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── models.py
│ │ ├── tests.py
│ │ ├── urls.py
│ │ ├── views.py
│ │ ├── fixtures
│ │ │ ├── dbti_compatibilities.json
│ │ │ ├── dbti_options.json
│ │ │ ├── dbti_questions.json
│ │ │ └── dbti_types.json
│ │ └── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── home
│ │ ├── __init__.py
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── models.py
│ │ ├── tests.py
│ │ ├── views.py
│ │ ├── fixtures
│ │ │ ├── 2024_2025_trend_data.json
│ │ │ ├── 2025_ai_tool_trend_data.json
│ │ │ ├── 2025_database_trend_data.json
│ │ │ └── 2025_framework_trend_data.json
│ │ └── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_aitooltrend.py
│ │ ├── 0003_databasetrend_frameworktrend.py
│ │ └── __init__.py
│ ├── projects
│ │ ├── __init__.py
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── models.py
│ │ ├── serializers.py
│ │ ├── tests.py
│ │ ├── urls.py
│ │ ├── views.py
│ │ └── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_project_skills.py
│ │ ├── 0003_project_detail.py
│ │ └── __init__.py
│ ├── recommendations
│ │ ├── __init__.py
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── models.py
│ │ ├── serializers.py
│ │ ├── services.py
│ │ ├── tests.py
│ │ ├── urls.py
│ │ ├── views.py
│ │ └── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_alter_recommendedproject_options_and_more.py
│ │ ├── 0003_recommendedproject_detail.py
│ │ └── __init__.py
│
├── frontend
│ ├── .gitignore
│ ├── index.html
│ ├── jsconfig.json
│ ├── package-lock.json
│ ├── package.json
│ ├── vite.config.js
│ ├── public
│ │ ├── favicon.ico
│ │ └── favicon.png
│ ├── src
│ │ ├── App.vue
│ │ ├── main.js
│ │ ├── api
│ │ │ ├── projects.js
│ │ │ └── recommendations.js
│ │ ├── assets
│ │ │ ├── base.css
│ │ │ ├── main.css
│ │ │ ├── images
│ │ │ │ ├── common
│ │ │ │ │ ├── Logo.png
│ │ │ │ │ └── diti_icon.png
│ │ │ │ ├── community
│ │ │ │ │ ├── community1.png
│ │ │ │ │ ├── noSearch.png
│ │ │ │ │ └── search.png
│ │ │ │ ├── dbti
│ │ │ │ │ ├── BadIcon.png
│ │ │ │ │ ├── DbtiCharacter.png
│ │ │ │ │ ├── DbtiTypeCharacter.png
│ │ │ │ │ ├── FeatureIcon1.png
│ │ │ │ │ ├── FeatureIcon2.png
│ │ │ │ │ ├── FeatureIcon3.png
│ │ │ │ │ ├── GoodIcon.png
│ │ │ │ │ ├── dbti1.png
│ │ │ │ │ └── dbti2.png
│ │ │ │ ├── home
│ │ │ │ │ ├── BannerBg.png
│ │ │ │ │ ├── HomeCharacter.png
│ │ │ │ │ ├── home1.png
│ │ │ │ │ ├── home2.png
│ │ │ │ │ ├── home3.png
│ │ │ │ │ ├── home4.png
│ │ │ │ │ ├── home5.png
│ │ │ │ │ ├── home6.png
│ │ │ │ │ ├── home7.png
│ │ │ │ │ ├── wave-bottom.svg
│ │ │ │ │ └── wave-top.svg
│ │ │ │ └── profile
│ │ │ │ ├── MyProfileEdit.png
│ │ │ │ ├── profile1.png
│ │ │ │ ├── profile2.png
│ │ │ │ ├── profile3.png
│ │ │ │ └── profile4.png
│ │ │ └── styles
│ │ │ ├── auth.css
│ │ │ ├── community.css
│ │ │ ├── dbti.css
│ │ │ ├── home.css
│ │ │ ├── mypage.css
│ │ │ ├── project.css
│ │ │ └── variables.css
│ │ ├── components
│ │ │ ├── auth
│ │ │ │ ├── AuthIntroCarousel.vue
│ │ │ │ ├── LoginForm.vue
│ │ │ │ └── SignupForm.vue
│ │ │ ├── common
│ │ │ │ ├── Footer.vue
│ │ │ │ ├── Navbar.vue
│ │ │ │ └── PolicyModal.vue
│ │ │ ├── community
│ │ │ │ ├── CommunityCategoryTabs.vue
│ │ │ │ ├── CommunityCommentItem.vue
│ │ │ │ ├── CommunityCommentList.vue
│ │ │ │ ├── CommunityHero.vue
│ │ │ │ ├── CommunityPostDetail.vue
│ │ │ │ ├── CommunityPostForm.vue
│ │ │ │ ├── CommunityPostItem.vue
│ │ │ │ └── CommunityPostList.vue
│ │ │ ├── dbti
│ │ │ │ ├── DbtiBanner.vue
│ │ │ │ ├── DbtiChemistry.vue
│ │ │ │ ├── DbtiExamCard.vue
│ │ │ │ ├── DbtiFeatures.vue
│ │ │ │ ├── DbtiProgressBar.vue
│ │ │ │ ├── DbtiRecommendLink.vue
│ │ │ │ ├── DbtiReportCard.vue
│ │ │ │ └── DbtiTypePreview.vue
│ │ │ ├── home
│ │ │ │ ├── HomeBanner.vue
│ │ │ │ ├── HomeFeatures.vue
│ │ │ │ ├── HomeStats.vue
│ │ │ │ └── HomeTrends.vue
│ │ │ ├── mypage
│ │ │ │ ├── MyDbtiBanner.vue
│ │ │ │ ├── MyInfoSummary.vue
│ │ │ │ ├── MyPageSidebar.vue
│ │ │ │ ├── MyProfileEditModal.vue
│ │ │ │ ├── MyProfileSummary.vue
│ │ │ │ ├── MyTestHistoryList.vue
│ │ │ │ └── MyTestHistorySummary.vue
│ │ │ ├── project
│ │ │ │ ├── ProjectCard.vue
│ │ │ │ ├── ProjectDetailModal.vue
│ │ │ │ ├── ProjectReasonBox.vue
│ │ │ │ ├── ProjectSideCard.vue
│ │ │ │ └── ProjectSummaryBar.vue
│ │ │ └── recommendations
│ │ │ ├── RecommendationChatBox.vue
│ │ │ └── RecommendationMessageItem.vue
│ │ ├── router
│ │ │ └── index.js
│ │ ├── stores
│ │ │ ├── auth.js
│ │ │ ├── community.js
│ │ │ └── counter.js
│ │ ├── utils
│ │ │ └── skillColors.js
│ │ ├── views
│ │ │ ├── community
│ │ │ │ ├── CommunityCreateView.vue
│ │ │ │ ├── CommunityDetailView.vue
│ │ │ │ ├── CommunityEditView.vue
│ │ │ │ └── CommunityListView.vue
│ │ │ ├── dbti
│ │ │ │ ├── DbtiExamView.vue
│ │ │ │ ├── DbtiMainView.vue
│ │ │ │ └── DbtiResultView.vue
│ │ │ ├── HomeView.vue
│ │ │ ├── LoginView.vue
│ │ │ ├── MyPageAccountSettingsView.vue
│ │ │ ├── MyPageSavedProjectsView.vue
│ │ │ ├── MyPageTestsView.vue
│ │ │ ├── MyPageView.vue
│ │ │ ├── ProjectRecommendView.vue
│ │ │ └── SignupView.vue
│ │ └── README.md
│ └── README.mdcd backend
python -m venv venv
venv\Scripts\activate
pip install -r requirements.txt.env 파일을 backend/.env 경로에 생성합니다.
GMS_KEY=your_api_key
GMS_API_URL=your_chat_completions_api_url
GMS_MODEL=gpt-5-nanoDB 마이그레이션 및 fixture 로드:
python manage.py migrate
python manage.py loaddata dbti/fixtures/dbti_types.json
python manage.py loaddata dbti/fixtures/dbti_questions.json
python manage.py loaddata dbti/fixtures/dbti_options.json
python manage.py loaddata dbti/fixtures/dbti_compatibilities.json
python manage.py loaddata community/fixtures/community_categories.json개발 서버 실행:
python manage.py runservercd frontend
npm install
npm run dev기본 접속 주소:
Frontend: http://localhost:5173
Backend: http://127.0.0.1:8000
현재 배포는 진행하지 않았으며, 로컬 개발 환경 기준으로 실행합니다.
http://localhost:5173
dit: 최종 통합 브랜치- 기능 단위 브랜치:
home,dbti,community,project,chatbot,fix등 - 기능 구현 후 merge request를 통해 통합
| 태그 | 설명 |
|---|---|
setting |
프로젝트 초기 세팅 |
feat |
기능 구현 및 추가 |
fix |
버그 수정 |
refactor |
기능 변경 없는 구조 개선 |
chore |
설정, 이미지, 기타 작업 |
docs |
문서 수정 |
- Django와 Vue 3 프로젝트 초기 세팅을 직접 구성하면서, 두 서버가 분리된 구조에서 CORS와 API 베이스 URL을 어떻게 맞춰야 하는지 학습했습니다.
- DBTI 검사를 문항, 선택지, 유형, 유형 간 호환성으로 모델을 나누어 설계하면서, 진단 로직을 프론트가 아니라 데이터 구조로 표현하는 방법을 익혔습니다.
- Vue Router의
beforeEach가드와START_LOCATION을 활용해, 새로고침이나 URL 직접 입력처럼 "앱 내부 이동이 아닌 진입"을 구분하는 방법을 학습했습니다. - 홈 화면 트렌드 위젯을 만들면서
Stack Overflow Developer Survey같은 외부 공개 데이터를 fixture로 가공해 보여주는 흐름을 익혔습니다.
- 프로필 드롭다운 메뉴가 바깥을 클릭해도 닫히지 않는 문제를 고치면서, Vue 컴포넌트 안에서
document에 직접 이벤트 리스너를 등록·해제하는 타이밍을 맞추는 게 생각보다 까다로웠습니다. - DBTI 결과 페이지를 주소창 직접 입력이나 새로고침으로 들어오지 못하게 막아야 했는데, "정상적인 이동"과 "직접 진입"을 라우터 단에서 구분하는 기준을 잡는 데 시간이 걸렸습니다.
- 커뮤니티 검색을 "전체 탭에서는 모든 게시글, 특정 탭에서는 그 카테고리만" 검색되도록 범위를 나누는 과정에서, 프론트만으로는 한계가 있어 백엔드 쿼리 파라미터까지 같이 손봐야 했습니다.
- 커뮤니티 페이지를 사이드바 레이아웃으로 리뉴얼하는 과정에서 CSS Grid의
align-items: stretch와 디바이더 위치 같은 디테일을 맞추느라 같은 부분을 여러 번 수정했습니다.
- Bootstrap 유틸리티 클래스(
.mb-3등)는!important로 정의되어 있어서, 같은 요소에 인라인 스타일을 줘도 조용히 무시될 수 있다는 점을 직접 겪고 배웠습니다. - 구분선을 "카드 끝까지 가득 차게" 할지 "위아래 여백을 두고" 할지에 따라, 패딩을 부모(카드)에 줄지 자식(아이템)에 줄지가 달라진다는 CSS 박스 모델의 디테일을 배웠습니다.
- 프론트엔드 라우터 가드만으로는 막을 수 없는 부분(새로고침, 직접 진입)도 있고, 이런 흐름 제어는 화면 전환 방식 자체를 이해해야 다룰 수 있다는 점을 배웠습니다.
- 외부 설문 데이터를 그대로 보여주는 것보다, TOP10처럼 일정한 기준으로 가공하고 출처를 명시해야 신뢰할 수 있는 콘텐츠가 된다는 점을 배웠습니다.
- 반복되는 모달(이용약관, 커뮤니티 지침 등)은 타입을 prop으로 받는 공용 컴포넌트로 분리하면, 페이지마다 같은 마크업을 복사하지 않아도 된다는 걸 배웠습니다.
- 초기 세팅부터 화면 디테일을 다듬는 작업까지 직접 해보면서, 기능이 동작하는 것과 "사용자가 어색함을 못 느끼게" 만드는 것 사이에 꽤 큰 차이가 있다는 걸 느꼈습니다.
- 같은 레이아웃이라도 화면 크기가 줄어들면 의도와 다르게 깨지는 경우가 많아서, 반응형까지 고려해야 진짜 끝난 작업이라는 걸 체감했습니다.
- 디자인을 여러 번 엎고 다시 만드는 과정이 많았는데, 그만큼 작은 디테일(정렬, 간격, 폰트 크기)이 전체 인상에 미치는 영향이 크다는 걸 느꼈습니다.
- 트렌드처럼 외부 데이터를 다루는 기능은 "어떤 데이터를 보여줄지" 기획하는 단계가 구현보다 더 오래 걸릴 수 있다는 걸 알게 됐습니다.
- 혼자 작업한 기능이라도 결국 다른 페이지(마이페이지, 프로젝트 추천)와 자연스럽게 이어져야 한다는 걸 느꼈고, 그래서 작은 버그 하나도 전체 흐름을 다시 점검하게 되는 경우가 많았습니다.
- Django REST Framework의 Token Authentication을 사용해 로그인/회원가입 이후 인증이 필요한 API를 호출하는 흐름을 학습했습니다.
- Pinia store를 활용해 로그인 상태, 사용자 정보, 마이페이지 정보를 전역 상태로 관리하는 방식을 익혔습니다.
localStorage와sessionStorage의 차이를 활용해 로그인 상태 유지 여부에 따라 저장 방식을 분리했습니다.- AI 추천 결과를 단순 텍스트가 아니라 프론트 UI에서 바로 사용할 수 있는 JSON 데이터로 다루는 방식을 학습했습니다.
- 추천 프로젝트와 저장 프로젝트를 분리해
RecommendedProject,Project,SavedProject로 관리하는 데이터 흐름을 설계했습니다. - 비밀번호 변경, 계정 삭제처럼 민감한 기능은 프론트 검증과 백엔드 검증을 함께 적용해야 한다는 점을 학습했습니다.
- AI가 사용자의 의도를 충분히 이해하면서도 항상 일정한 JSON 형식으로 응답하게 만드는 프롬프트 설계가 어려웠습니다.
- 사용자가 조건을 모두 선택하지 않고 자유롭게 입력했을 때, 추가 질문 없이 바로 추천되도록 AI 규칙을 조정하는 과정이 까다로웠습니다.
- 프로젝트 추천 페이지에서 다른 페이지로 이동했다가 돌아와도 채팅과 추천 결과가 유지되도록 상태를 관리하는 부분이 어려웠습니다.
- 새로고침 시 Navbar나 마이페이지에서 사용자 정보가 잠깐 기본값으로 보이는 문제를 해결하기 위해 Pinia와 storage 캐싱 흐름을 맞추는 데 시간이 걸렸습니다.
- 추천 프로젝트를 찜했을 때 마이페이지 저장 프로젝트와 자연스럽게 연결되도록 프론트 상태와 백엔드 저장 로직을 맞추는 과정이 복잡했습니다.
- 프론트엔드 라우터 가드는 사용자 경험을 위한 1차 접근 제어이고, 실제 권한 검증은 백엔드에서 반드시 다시 처리해야 한다는 점을 배웠습니다.
- AI API Key는 프론트에 두지 않고 백엔드
.env에서 관리해야 하며, 외부 API 호출과 응답 파싱도 서버에서 처리하는 것이 안전하다는 점을 배웠습니다. - AI 응답을 서비스 화면에 연결하려면 프롬프트에서 응답 구조, 필수 필드, 예외 상황을 구체적으로 정의해야 한다는 점을 배웠습니다.
- 사용자 프로필이나 DBTI 결과가 바뀌면 기존 추천 결과가 더 이상 적절하지 않을 수 있으므로, 추천 당시의 프로필 snapshot을 저장해 비교하는 방식이 필요하다는 점을 배웠습니다.
- 저장/찜하기 기능은 별도 저장 API와 삭제 API로 나눌 수도 있지만, toggle 방식으로 구현하면 프론트의 버튼 상태 관리가 단순해질 수 있다는 점을 배웠습니다.
- 단순히 기능을 구현하는 것보다 사용자의 흐름이 끊기지 않도록 데이터를 어떻게 이어줄지 고민하는 과정이 중요하다고 느꼈습니다.
- AI를 활용할 때는 API를 호출하는 것 자체보다, AI가 반환한 결과를 실제 서비스 데이터처럼 안정적으로 사용할 수 있도록 구조를 설계하는 것이 더 중요하다고 느꼈습니다.
- 로그인, 마이페이지, AI 추천, 저장 프로젝트가 각각 따로 있는 기능처럼 보이지만, 실제 서비스에서는 하나의 사용자 경험으로 이어져야 한다는 점을 많이 배웠습니다.
- 구현 중간에 UI 문구나 추천 이유가 어색하게 느껴지는 부분이 많았고, 기능뿐 아니라 사용자가 읽고 납득할 수 있는 흐름을 만드는 것도 중요하다고 느꼈습니다.
- 짧은 기간 안에 여러 기능을 연결하면서 버그도 많았지만, 문제를 하나씩 추적하고 상태 흐름을 정리하면서 전체 서비스 구조를 더 잘 이해할 수 있었습니다.
- 추천 결과에 대한 사용자 피드백 수집
- 저장/취소 데이터를 기반으로 한 추천 품질 개선
- 저장 프로젝트 진행률 및 체크리스트 기능 추가
- 추천 프로젝트 커뮤니티 공유 기능
- DBTI 기반 팀원 매칭 기능
- AI 응답 JSON schema 검증 및 재요청 로직 강화
- 실제 배포 환경 기준의 인증 보안 강화