1## 1. 🏷️DaLabel (데이터 라벨링 플랫폼)

DaLabel은 AI 학습 데이터셋 구축을 위한 협업 플랫폼입니다. AI 모델 개발의 핵심은 잘 정제된 대량의 ‘라벨링된 데이터’이며, 이 프로젝트의 목표는 데이터 라벨링을 필요로 하는 ‘의뢰자’와 라벨링 작업을 수행하는 ‘작업자’를 연결하고, 전 과정을 효율적으로 관리할 수 있는 웹 기반 솔루션을 제공하는 것이었습니다.

프로젝트 상태

본 프로젝트는 교육 과정의 일환으로 개발되었으며, 현재는 서비스되고 있지 않습니다. 이 문서는 향후 업데이트 계획이 없는 기술 아카이브 및 회고 자료입니다.

3. 👨‍👩‍👧‍👦 HiddenLayer 팀 (Team & Roles)

본 프로젝트는 5인의 팀으로 구성되었으며, 각 팀원의 담당 역할은 다음과 같습니다.

이름역할주요 담당 기능
신용대팀장 / 백엔드라벨링 의뢰 유저(Requestor) 시스템 구현, 프로젝트 총괄 관리
이미주프론트엔드게시글 댓글/대댓글 기능, 다중 이미지 업로드 게시글 작성 기능 구현
나준호백엔드 / 프론트엔드커뮤니티 게시판, 라벨링 데이터 신고 기능 구현
박아멘백엔드데이터 분배 시스템, 유저 권한 관리, 라벨링 작업자(Worker) 시스템 구축
유성훈백엔드 / AI정산 서버 구축, 라벨링 신뢰도 평가 AI 모델 구축 (FastAPI, Keras)
공통-데이터베이스(ERD) 설계, 화면 및 기능 설계, 로그인/회원가입 등 공통 모듈

4. 🏗️ 아키텍처 및 설계

4-1. 시스템 아키텍처 (3-Tier MVC)

본 프로젝트는 레거시 Spring MVC(3.1.1)JSP 템플릿 엔진을 기반으로 하는 전통적인 3-Tier, N-Layered 아키텍처를 따릅니다.

graph RL
    subgraph "User's Browser"
        U["User<br>(JSP View in Browser)"]
    end

    subgraph "Web Application Server (Tomcat)"
        subgraph "Presentation Layer (servlet-context.xml)"
            C["<b>@Controller</b><br>(MemberController, BoardController...)"]
            I["<b>Interceptor</b><br>(AuthLoginInterceptor)"]
            JSP["<b>ViewResolver</b><br>(Renders JSP to HTML)"]
        end
        
        subgraph "Business Logic Layer (root-context.xml)"
            S["<b>@Service / DAO</b><br>(MemberDAO, BoardDAO...)"]
        end

        subgraph "Data Access Layer (root-context.xml)"
            D["<b>@Repository (MyBatis)</b><br>(MyBatis SqlSession)"]
            M["<b>MyBatis Mapper</b><br>(*.xml)"]
        end
    end

    subgraph "Database Server"
        DB[("<b>OracleDB</b>")]
    end

    U -- HTTP Request --> I
    I -- Auth Success --> C
    C -- Logic Request --> S
    S -- DB Request --> D
    D -- SQL Call --> M
    M -- SQL Query --> DB
    DB -- Result --> M
    M -- Result --> D
    D -- Result --> S
    S -- Model --> C
    C -- View Name & Model --> JSP
    JSP -- Rendered HTML --> U
  • Presentation Layer: 사용자의 HTTP 요청을 받아 @Controller가 처리하고, 뷰(JSP)를 서버 사이드에서 렌더링하여 완전한 HTML 페이지로 응답합니다.

  • Business Logic Layer: @ServiceDAO로 구성되어 비즈니스 로직(e.g., 데이터 분배)을 수행합니다.

  • Data Access Layer: MyBatisMapper.xml을 통해 OracleDB와 통신하며 SQL 쿼리를 실행합니다.

4-2. 데이터베이스 스키마 (ERD)

erDiagram
    DL_MEMBER {
        string USER_ID PK
        int USER_TYPE "역할 (1:작업자, 2:의뢰자, 99:관리자)"
        string USER_NAME
    }
    
    DL_PROJECT {
        int PROJECT_NO PK
        string REQUESTOR_ID FK "의뢰자 ID"
        string TITLE
        int BUNDLE_NO FK "사용할 데이터 번들"
    }
    
    DL_DATA_BUNDLE {
        int BUNDLE_NO PK
        string UPLOADER_ID FK "업로더 ID (의뢰자)"
        string FILENAME
    }
    
    DL_DATA {
        string DATA_NO PK
        int BUNDLE_NO FK
        string FILE_PATH
    }
    
    DL_LABELING {
        int LABELING_NO PK
        string DATA_NO FK "라벨링 대상 데이터"
        string WORKER_ID FK "작업자 ID"
        string LABEL_VALUE "라벨링 결과값"
        int LABEL_STATUS "0:작업중, 1:제출, 2:승인, 3:반려"
    }

    DL_BOARD {
        int BOARD_NO PK
        string WRITER_ID FK "작성자 ID"
        string TITLE
    }
    
    DL_BOARD_COMMENT {
        int COMMENT_NO PK
        int BOARD_NO FK
        string WRITER_ID FK
        int COMMENT_REF FK "대댓글 (Self-ref)"
    }
    
    DL_REPORT {
        int REPORT_NO PK
        string REPORTER_ID FK "신고자 ID"
        string REPORT_TYPE "신고 대상 타입"
        string TARGET_PK "신고 대상 PK"
    }

    DL_MEMBER ||--o{ DL_PROJECT : "의뢰 (1:N)"
    DL_MEMBER ||--o{ DL_DATA_BUNDLE : "업로드 (1:N)"
    DL_MEMBER ||--o{ DL_LABELING : "작업 (1:N)"
    DL_MEMBER ||--o{ DL_BOARD : "작성 (1:N)"
    DL_MEMBER ||--o{ DL_BOARD_COMMENT : "작성 (1:N)"
    DL_MEMBER ||--o{ DL_REPORT : "신고 (1:N)"
    
    DL_PROJECT }o--|| DL_DATA_BUNDLE : "사용 (1:1)"
    DL_DATA_BUNDLE ||--o{ DL_DATA : "포함 (1:N)"
    DL_DATA ||--o{ DL_LABELING : "수행 (1:N)"

    DL_BOARD ||--o{ DL_BOARD_COMMENT : "포함 (1:N)"
    DL_BOARD_COMMENT }o--o{ DL_BOARD_COMMENT : "답글 (1:N)"

5. 🛠️ 핵심 기술 스택 (Tech Stack)

구분Backend (Main)Backend (AI/Settlement)FrontendDatabase
LanguageJava 1.8PythonJavaScript (ES5), CSSSQL
FrameworkSpring MVC 3.1.1FastAPI, KerasjQuery, AJAX-
PersistenceMyBatis 3--OracleDB 11g
Server/BuildApache Tomcat---
ToolsGit, GitHub, EclipseVS Code--

6. 💡 주요 기능 및 기술적 포인트

6-1. 🛡️ 인증/인가 및 접근 제어

(담당: 박아멘, 공통)

‘의뢰자(Requestor)’, ‘작업자(Worker)’, ‘관리자(Admin)‘라는 3가지 사용자 유형에 따라 접근 가능한 페이지를 제어해야 했습니다.

  • Interceptor 활용: Spring의 HandlerInterceptorAdapter를 상속받은 AuthLoginInterceptor를 구현했습니다.

  • 역할 기반 접근 제어(RBAC): preHandle 메소드에서 HttpSessionuser_type을 확인하여, 요청 URI에 대한 접근 권한이 있는지 검사했습니다. (e.g., user_type이 ‘작업자’일 경우 /manage_labeling.go 접근 차단)

  • 중복 로그인 방지: 세션에 로그인 정보를 저장하여 중복 로그인을 제어했습니다.

flowchart LR
    A["User Request (/manage/project)"] --> I["AuthLoginInterceptor.preHandle()"]
    I --> C1{"Is Logged In? (Session exists?)"}
    C1 -- No --> R1["Redirect to /login.go"]
    C1 -- Yes --> C2{"Has Correct Role? (user_type == 2)"}
    C2 -- No --> R2["Redirect to Home (/)"]
    C2 -- Yes --> GC["return true (pass to Controller)"]
    GC --> CTRL["Controller executes (manage_labeling.jsp)"]

6-2. 🗂️ 데이터 관리 (ZIP 비동기 처리)

(담당: 신용대)

의뢰자는 수백 개의 이미지가 담긴 .zip 파일을 업로드해야 했습니다. HTTP 요청 시간 내에 이 파일들의 압축 해제 및 DB 삽입을 완료하는 것은 불가능했습니다.

  • 비동기 스레드 처리: ManageLabelingController는 파일 업로드(MultipartFile) 요청을 받으면, 파일을 서버의 임시 저장소에 저장한 뒤 즉시 사용자에게 “업로드 접수” 응답을 반환했습니다.

  • 백그라운드 작업: 이후 UnZipperThread.java라는 별도의 스레드를 생성하여, 실제 .zip 파일 압축 해제, 파일 이동, DL_DATA 테이블에 메타데이터 삽입 작업을 백그라운드에서 수행하도록 위임했습니다.

sequenceDiagram
    participant U as User (Requestor)
    participant C as Controller
    participant FS as Server (File System)
    participant T as UnZipperThread
    participant DB as OracleDB

    U->>C: POST /upload (with .zip file)
    C->>FS: 1. Save .zip to temp storage
    C-->>U: 2. Return HTTP 200 (Upload 접수)
    
    C->>T: 3. Start new Thread(zipFile)
    
    loop Asynchronous Processing
        T->>FS: 4. Read .zip file
        T->>FS: 5. Unzip individual files
        T->>DB: 6. Insert file metadata (DL_DATA)
    end
    
    T-->>C: (Thread completes)

6-3. 👨‍💻 라벨링 수행 및 동시성 제어

(담당: 박아멘)

여러 작업자가 동시에 동일한 프로젝트에 접근할 때, 데이터가 중복으로 분배되거나 작업 중인 데이터가 다른 사용자에게 노출되는 문제를 방지해야 했습니다.

  • 데이터 분배 로직: 작업자가 ‘라벨링 시작’을 누르면, DoLabelingControllerLABELING_DONE 테이블을 참조하여 해당 사용자가 아직 작업하지 않았고, 다른 사용자가 현재 작업 중(STATUS=0)이지 않은 데이터를 1건 조회하여 분배했습니다.

  • 작업 상태 관리: 데이터가 분배되면 LABELING_DONE 테이블에 STATUS를 0(작업중)으로 즉시 업데이트하여 다른 작업자에게 분배되지 않도록 Lock을 걸었습니다.

  • 시연 확인: (슬라이드 시연) 두 개의 다른 브라우저에서 동일 계정으로 동시 접속 시, 각기 다른 이미지가 노출되는 것을 확인했습니다.

6-4. 🗣️ 커뮤니티 및 신고 기능 (AJAX)

(담당: 나준호, 이미주)

  • 커뮤니티 (CRUD): BoardController를 통해 게시글 CRUD 기능을 구현했습니다.

  • AJAX 댓글/대댓글: 페이지 새로고침 없이 동적으로 댓글과 대댓글을 처리하기 위해 jQueryAJAX를 사용했습니다. BoardMapper.xml에서 댓글(COMMENT_REF가 null)과 대댓글(COMMENT_REF가 상위 댓글 ID)을 구분하여 등록 및 조회했습니다.

  • 데이터 신고: 라벨링 작업 중 부적합한 데이터 발견 시, 작업자가 ‘신고’ 버튼을 누르면 ReportController가 이를 DL_REPORT 테이블에 저장합니다. 의뢰자는 관리 페이지에서 신고 내역을 확인하고 해당 데이터를 비활성화할 수 있습니다.

6-5. 🤖 AI 정산 서버 (FastAPI)

(담당: 유성훈)

작업자에 대한 신뢰도 평가 및 정산을 위해 별도의 AI 서버를 구축했습니다.

  • 기술 스택: 메인 Spring 서버와 별개로, Python 기반의 FastAPI로 API 서버를 구축하고 Keras를 활용해 신뢰도 평가 모델을 학습시켰습니다.

  • 신뢰도 평가: (슬라이드 시연) 의뢰자가 ‘정산’ 버튼을 누르면, 작업 완료된 데이터를 AI 서버로 전송합니다. AI 서버는 작업자의 라벨링 결과와 실제 정답을 비교하여 작업자별 신뢰도(정확도)를 평가합니다.

  • 결과 반환: 정산 결과(작업 건수, 신뢰도, 총 보상)는 통계 페이지에 표시되며 CSV 파일로 다운로드할 수 있습니다.

7. 🎯 프로젝트 회고 및 교훈

본 프로젝트는 성공적으로 완료되었으나, 팀 자체 평가에서 논의된 몇 가지 아쉬운 점과 교훈이 있습니다.

  • [설계] 초기 설계의 중요성 (아쉬웠던 점 - 나준호, 신용대):

    프로젝트 사전 설계가 미흡하여 개발 중 DB 스키마와 기능 구조가 자주 변경되었습니다. 이로 인해 불필요한 재작업이 발생했으며, 개발 착수 전 명확한 ERD와 API 명세를 확정하는 것이 전체 개발 효율성을 높인다는 교훈을 얻었습니다.

  • [보안] 데이터 접근 취약점 (아쉬웠던 점 - 박아멘):

    현재 구조는 DL_DATA 테이블의 파일 경로가 외부에 노출될 경우, 인증되지 않은 사용자가 원본 데이터에 직접 접근할 수 있는 잠재적 보안 취약점(IDOR)이 존재했습니다.

    • 개선 방향: 실제 파일 경로를 숨기고, 별도의 DataController를 두어 사용자의 작업 참여 권한을 확인한 뒤 파일 스트림(Stream)을 응답으로 전송하는 방식으로 개선해야 합니다.
  • [기술 스택] DB 호환성 문제 (아쉬웠던 점 - 유성훈):

    초기에는 정산 서버를 Django로 구축하려 했으나, OracleDB 11g 버전과 호환성 이슈가 발생했습니다. Django를 다운그레이드하는 대신 FastAPI로 신속하게 기술 스택을 변경하여 문제를 해결하며 대처 능력을 길렀습니다.

  • [소감] 협업과 소통 (공통):

    팀원 모두가 ‘개발’ 자체보다 ‘협업’의 중요성을 가장 큰 배움으로 꼽았습니다. Git 충돌 해결, 코드 스타일 통일, 명확한 의사소통이 없었다면 레거시 Spring 환경에서의 복잡한 프로젝트를 완성하기 어려웠을 것입니다.