OPUS는 부산대학교 내 SW 프로젝트(캡스톤/해커톤/교과 등)의 성과를 등록, 관리, 공유하고,
운영 측면에서는 대회/팀/결과물을 효율적으로 관리하는 시스템입니다.
🌐 운영 서비스 이동 | 🧩 Production Repo 이동 | 📄 Spring Rest Docs | 🔨 개발 서버 | 📦 MVP Backend
─ src
├─ main
│ ├─ java
│ │ └─ com
│ │ └─ opus
│ │ └─ opus
│ │ ├─ OpusApplication.java
│ │ ├─ docs
│ │ │ └─ asciidoc
│ │ ├─ global
│ │ │ ├─ base
│ │ │ ├─ config
│ │ │ ├─ error
│ │ │ └─ security
│ │ └─ modules
│ │ ├─ member
│ │ │ ├─ api
│ │ │ │ └─ Membercontroller.java
│ │ │ ├─ application
│ │ │ │ ├─ convenience
│ │ │ │ └─ MemberConvenience.java
│ │ │ │ └─ dto
│ │ │ │ ├─ request
│ │ │ │ └─ response
│ │ │ │ ├─ MemberCommandService.java
│ │ │ │ └─ MemberQueryService.java
│ │ │ ├─ domain
│ │ │ │ ├─ Member.java
│ │ │ │ ├─ dao
│ │ │ │ └─ MemberRepository.java
│ │ │ └─ exception
│ │ │ ├─ MemberException.java
│ │ │ └─ MemberExceptionType.java
│ │ ├─ contest
│ │ ├─ file
│ │ ├─ notice
│ │ └─ team
│ └─ resources
│ ├─ application.yml
│ ├─ application-secret.yml
│ └─ schema.sql
└─ test
├─ java
│ └─ com
│ └─ opus
│ └─ opus
│ ├─ helper
│ │ ├─ ApiTestHelper.java
│ │ └─ IntegrationTest.java
│ ├─ restdocs
│ │ ├─ docs
│ │ ├─ MemberApiDocsTest.java
│ │ └─ ...
│ │ ├─ RestDocsConfig.java
│ │ └─ RestDocsTest.java
│ ├─ member
│ │ ├─ application
│ │ ├─ MemberCommandServiceTestjava
│ │ └─ MemberQueryServiceTest.java
│ │ └─ MemberFixture
│ ├─ ...
└─ resources
회원, 인증
- 학번 기반 회원가입과 이메일 인증, Google OAuth2 소셜 로그인
- 이메일 인증을 거치는 비밀번호 재설정, 학번으로 이메일 찾기
- 학생, 관리자, 교수, 직원, 외부멘토 역할 기반 접근 제어
- 프로필 이미지, GitHub URL, 프로필 공개 여부 설정
- 마이페이지에서 참여 프로젝트, 투표, 댓글, 좋아요 내역 조회
- 회원 탈퇴 및 관리자 강제 탈퇴(사유 기록)
대회 운영
- 카테고리, 대회, 분과(트랙) 관리와 현재 진행 대회 지정
- 대회별 팀 등록 템플릿 설정으로 필수 입력 항목 제어
- 엑셀 파일을 통한 팀 일괄 등록
- 사이드바 노출과 팀 목록 정렬 방식 설정(이름순, 사용자 지정, 랜덤)
팀, 프로젝트
- 팀 생성과 팀장, 팀원 역할 관리
- 프로젝트 개요, GitHub, YouTube, 배포 링크 등록
- 배너, 썸네일, 포스터 이미지 업로드와 WebP 변환
- 공개 범위에 따른 프로젝트 조회
제출물
- 제출 항목별 마감일, 허용 파일 형식, 개수, 용량, 공개 범위 설정
- 지각 제출 허용 여부 제어
- 제출물 파일 첨부, 삭제, 일괄 다운로드
- 팀별 제출 현황 요약과 제출 타임라인 조회
피드백, 멘토링
- 대회별 교수, 외부멘토 배정과 담당 팀 지정
- 담당 팀 제출물에 대한 피드백 작성과 읽음 처리
- 제출물 확인 메모 기록
투표, 수상
- 투표 기간과 인당 투표 수 제한
- 투표 로그, 실시간 랭킹, 투표 통계 조회
- 팀 좋아요
- 수상 내역 등록과 팀별 수상 관리
소통
- 팀 프로젝트 댓글
- 전체 공지와 대회별 공지
- 팀, 댓글, 수상 관련 알림
전체 컬럼과 제약 조건은 src/main/resources/schema.sql에서 확인할 수 있습니다.
모든 테이블은
created_at,updated_at을 공통으로 가지며, 대부분is_deleted기반 논리 삭제를 사용합니다. 모듈 간 참조는 JPA 연관관계 대신 ID만 저장하는 컨벤션을 따르므로, 아래 관계 중 실제 DB 외래키 제약이 걸린 것은file계열 3개뿐입니다.
erDiagram
%% ── Contest 모듈 ──
contest_category ||--o{ contest : "category_id"
contest ||--o{ contest_award : "contest_id"
contest ||--|| contest_template : "contest_id (UK)"
contest ||--|| contest_sort : "contest_id (UK)"
contest ||--o{ contest_track : "contest_id"
contest ||--o{ contest_submission_item : "contest_id"
contest ||--o{ contest_member : "contest_id"
contest ||--o{ notice : "contest_id"
contest_track ||--o{ contest_submission_item : "contest_track_id"
contest_submission_item ||--o{ contest_submission_item_file_formats : "element collection"
contest_submission_item ||--o{ contest_submission : "contest_submission_item_id"
contest_submission ||--o| contest_submission_memo : "contest_submission_id (UK)"
contest_submission ||--o{ contest_submission_feedback : "contest_submission_id"
contest_member ||--o{ contest_member_team_ids : "element collection"
%% ── Team 모듈 ──
contest ||--o{ team : "contest_id"
contest_track ||--o{ team : "track_id"
team ||--o{ team_member : "team_id"
team ||--o{ team_comment : "team_id"
team ||--o{ team_like : "team_id"
team ||--o{ team_vote : "team_id"
team ||--o{ team_contest_award : "team_id"
team ||--o{ contest_submission : "team_id"
team ||--o{ contest_member_team_ids : "team_id"
team_member ||--o{ team_member_roles : "element collection"
contest_award ||--o{ team_contest_award : "contest_award_id"
%% ── Member 모듈 ──
member ||--o{ member_roles : "element collection"
member ||--o{ contest_member : "member_id"
member ||--o{ contest_submission_feedback : "member_id"
member ||--o{ team_member : "member_id"
member ||--o{ team_comment : "member_id"
member ||--o{ team_like : "member_id"
member ||--o{ team_vote : "member_id"
member ||--o{ notification : "member_id"
member ||--o{ member_withdrawal_history : "member_id"
%% ── File 모듈 ──
file ||--|| file_image : "file_id (UK)"
file ||--|| file_feedback : "file_id (UK)"
file ||--|| file_document : "file_id (UK)"
contest_submission ||--o{ file_document : "submission_id"
contest_submission_feedback ||--o{ file_feedback : "feedback_id"
contest_category {
bigint id PK
varchar category_name
bit is_deleted
}
contest {
bigint id PK
bigint category_id FK
varchar contest_name
bit is_current
int max_votes_limit
datetime vote_start_at
datetime vote_end_at
}
contest_award {
bigint id PK
bigint contest_id FK
varchar award_name
varchar award_color
}
contest_template {
bigint id PK
bigint contest_id FK "UK"
bit track_required
bit team_name_required
bit overview_required
}
contest_sort {
bigint id PK
bigint contest_id FK "UK"
enum mode "ASC, CUSTOM, RANDOM"
}
contest_track {
bigint id PK
bigint contest_id FK
varchar track_name
}
contest_submission_item {
bigint id PK
bigint contest_id FK
bigint contest_track_id FK "nullable"
varchar name
datetime start_at
datetime end_at
bit allow_late_submission
int max_file_count
int max_file_size_mb
enum visibility "TEAM, STAFF, MEMBER, PUBLIC"
}
contest_submission_item_file_formats {
bigint contest_submission_item_id PK
enum file_format PK
}
contest_submission {
bigint id PK
bigint contest_submission_item_id FK
bigint team_id FK
datetime first_submitted_at
}
contest_submission_memo {
bigint id PK
bigint contest_submission_id FK "UK (active)"
varchar content
}
contest_submission_feedback {
bigint id PK
bigint contest_submission_id FK
bigint member_id FK
varchar description
tinyint is_read
}
contest_member {
bigint id PK
bigint contest_id FK
bigint member_id FK
}
contest_member_team_ids {
bigint contest_member_id PK
bigint team_id PK
}
notice {
bigint id PK
bigint contest_id FK "nullable"
varchar title
varchar description
}
team {
bigint id PK
bigint contest_id FK
bigint track_id FK "nullable"
varchar team_name
varchar project_name
varchar professor_name
varchar overview
bit is_submitted
int item_order
}
team_member {
bigint id PK
bigint team_id FK
bigint member_id FK
}
team_member_roles {
bigint team_member_id PK
enum role PK "ROLE_팀원, ROLE_팀장"
}
team_comment {
bigint id PK
bigint team_id FK
bigint member_id FK
varchar description
}
team_like {
bigint id PK
bigint team_id FK
bigint member_id FK
}
team_vote {
bigint id PK
bigint team_id FK
bigint member_id FK
}
team_contest_award {
bigint id PK
bigint team_id FK
bigint contest_award_id FK
}
member {
bigint id PK
varchar email "UK"
varchar student_id "UK, nullable"
varchar name
varchar password "nullable"
varchar social_type "nullable"
varchar social_id "nullable"
varchar github_url
bit is_profile_public
bit is_fake
}
member_roles {
bigint member_id PK
enum role PK "ROLE_학생, ROLE_관리자, ROLE_교수, ROLE_직원, ROLE_외부멘토"
}
staff_info {
bigint id PK
varchar name
varchar email
enum role "ROLE_교수, ROLE_직원"
}
notification {
bigint id PK
bigint member_id FK
varchar title
varchar content
enum type "TEAM, TEAM_COMMENT, TEAM_AWARDS"
bigint target_id
bit is_read
}
member_withdrawal_history {
bigint id PK
bigint member_id FK
enum reason "FRAUDULENT_USE, DUPLICATE_ACCOUNT, ETC"
varchar detail
}
file {
bigint id PK
varchar name
varchar file_path
bigint file_size
varchar mime_type
}
file_image {
bigint id PK
bigint file_id FK "UK"
enum image_type "BANNER, PREVIEW, THUMBNAIL, POSTER, PROFILE"
bigint reference_id
enum reference_type "CONTEST, TEAM, TRACK, MEMBER"
bit is_webp_converted
}
file_document {
bigint id PK
bigint file_id FK "UK"
bigint submission_id FK
int file_order
}
file_feedback {
bigint id PK
bigint file_id FK "UK"
bigint feedback_id FK
int file_order
}
staff_info는 교직원 회원가입 시 명단 검증에만 사용되어 다른 테이블과 연결되지 않습니다.
file_image는 reference_id, reference_type 조합으로 대회, 팀, 분과, 회원을 가리키는 다형 참조라 관계선으로 표현하지 않았습니다.
notification의 target_id도 type에 따라 대상이 달라지는 다형 참조입니다.
