Portfolio Overview

데이터 수집·정제·가공 웹 플랫폼 구축 및 운영 경험

2020~2023의 4년간 운영한 데이터 수집/정제/가공 웹 플랫폼(저작도구)의 구축 경험 및 사용 목적을 정리한 페이지입니다. 프로젝트마다 요구조건은 달랐지만, 전체적인 흐름은 프로젝트 시작 > 수집작업자 > 1차정제/가공작업자 > Backend 자동화 > 2차정제/가공작업 > 데이터 취합 후 원천/라벨데이터셋 정리 및 납품, 작업료 정산으로 이어졌습니다.

주 역할은 프로젝트 완수를 위한 저작도구 서비스 구조 기획, 설계, 개발, 운영, 데이터 관리였습니다. 부 역할로는 프로젝트 진척도 관리와 업무 백업을 맡는 준 PM 성격의 역할도 함께 수행했습니다.

4년
운영 기간
1인
웹 구축/운영 중심
PHP
웹 백엔드
Python
로컬 자동화 API
공통 작업 흐름

프로젝트별 요구사항은 달랐지만, 전체적인 서비스 운영 흐름은 유사하게 설계했습니다.

수집 + 정제 + 자동화 + 납품 + 정산
Step 01
프로젝트 시작
공고 등록, 지원 접수, 참여자 선정, 권한 부여, 작업량 분배
Step 02
수집 작업
이미지, 영상, 텍스트, 메타데이터 제출과 작업 가이드 제공
Step 03
1차 정제/가공
육안 검사, OCR 수정, BBox 정리, 레이블 정렬 등 사람 중심 품질 보정
Step 04
Backend 자동화
비식별화, 객체 인식, 파일 처리, 메타 보정, 대량 업로드 자동화
Step 05
2차 정제/검수
자동화 결과의 미비점 수정, 최종 품질 확인, 반려 및 재작업 처리
Step 06
취합 및 납품
원천/라벨 데이터셋 정리, 외부 저장소 업로드, 작업료 정산
웹 서버

웹 서버는 가비아 클라우드 환경의 CentOS 리눅스에 APM 웹서버를 구축해 운영했습니다. 단일 웹서버로 트래픽과 작업량을 감당하면서 성능 병목, 네트워크 I/O 비용, 실시간 장애 대응을 직접 경험했고, 이 과정이 이후 인프라 이해도를 크게 넓혀주었습니다.

데이터 교환

사무실 내 로컬 Ubuntu PC에는 Python FastAPI 서버를, Synology NAS에는 대용량 원시데이터 저장소를 운영했습니다. SMB, FTP, boto3 기반 S3 업로드 등으로 웹서버, 로컬 자동화, 납품 저장소를 연결해 실제 프로젝트 운영을 지원했습니다.

API 자동화

로컬 Ubuntu Python FastAPI 서버는 인력비와 일정 압박을 줄이기 위한 자동화 서버였습니다. 객체인식, 비식별화, DB/메타데이터 보정, 엑셀 처리, SSH 터널링 등 다양한 실무 자동화를 붙이면서 실제 프로젝트에 투입 가능한 정확도까지 끌어올렸습니다.

연도별 주요 과제
2022
AI-Hub / 더바이럴
중점 작업
로컬서버 API 기반 비식별화 자동화 프로세스

객체 인식, 객체 분할, 이미지 설명문, 관계성 인지, 행동 분류 등 다섯 개 세부 과제의 수집/정제 작업을 지원했습니다.

프로세스 요약

(프로젝트 시작) 프로젝트 공고 > 참여자 모집 및 지원 신청 > 작업자 선정 및 권한 부여 > 작업 할당량 분배 > (수집작업자) 이미지, 영상, 텍스트 등 원시데이터 및 메타데이터 제출 > (1차정제작업자) 유효한 데이터인지 육안 검사 > (Backend 자동화) 이미지/영상 사물인식(Yolov5), 안면/자동차 번호판 비식별화 등 자동화 처리 > (2차정제작업자) 자동화처리결과 미비점 수동 비식별화 처리 및 메타데이터 유효성 2차점검 > 데이터 취합 후 원천데이터셋 정리 및 납품, 작업료 정산

확인 가능한 페이지
중점 작업
수집과 정제 구조를 빠르게 전개 가능한 범용 저작도구 활용

패션 데이터 참여 가이드, 수집, 정제 페이지가 남아 있어 당시 공통 구조를 보여주기 좋습니다.

프로세스 요약

참여 가이드 > 수집 작업 > 정제 작업 > 작업 이력 및 정산 흐름으로 이어지는 비교적 전형적인 구조입니다.

2023
AI-Hub / 더바이럴
중점 작업
차트 생성도구, OCR-BBox 매칭, Match/Caption 가공, 검수

차트 생성부터 OCR 결과 정제, 레이블 위치 매칭, 캡션 생성/검수까지 가장 복합적인 작업 흐름을 가진 프로젝트였습니다.

프로세스 요약

(프로젝트 시작) > 수집작업: 웹 이미지 수집, 차트용 데이터 수집/생성 후 Chart.js로 차트이미지 생성, PDF에서 차트 이미지 분리 후 제출 자동화 도구 > 자동화: 입력된 이미지의 OCR 텍스트와 Bounding-box 결과를 저장 > 정제작업: OCR 결과와 Bounding-box의 위치를 연결 및 텍스트 수정, 가공 작업에 필요한 첫 구조를 짜는 작업 > 가공작업1 (Match): 정제된 데이터들의 실제 레이블 위치를 정하는 작업 > 가공작업2 (Caption): Match된 데이터들을 일련의 규칙을 통해 설명문을 자동 생성하고, 올바른 결과인지 판단하는 작업 > 검수 > 데이터 취합 후 라벨데이터셋 정리 및 납품, 작업료 정산

확인 가능한 페이지
중점 작업
장소 승인 기반 수집 구조, 지도 연동, 관광지 위치 제약

관광지 장소를 검색하고 승인된 위치에 대해서만 제출할 수 있도록 설계한 수집 구조가 핵심이었습니다.

프로세스 요약

참여 신청 > 장소 탐색 및 승인 > 수집 작업 > 정제 작업 > 작업 이력 및 정산 흐름으로 이어졌습니다.

확인 가능한 페이지
웹 백엔드 구조

웹 백엔드는 PHP로 단독 구축했습니다. 당시 프레임워크를 쓰지 않았고, DB 연결과 쿼리 빌더 성격의 유틸을 직접 작성해 운영했습니다. 지금 보면 거친 부분도 있지만, 이 경험 덕분에 구조를 스스로 설계하고 타인의 코드를 읽어내는 힘을 많이 얻었습니다.

DB 연결, 쿼리 실행, 문자열 필터링, `select / insert / update` 성격의 직접 작성 유틸이 한 파일에 모여 있던 구조입니다.

<?php
$m_con_todb = "--";
if (!empty($dbcon)) {
    $m_con_todb = $dbcon;
}
$m_con = @(mysqli_connect("localhost", "--", "---", $m_con_todb));

function m_action($sql, $test = false) {
    $con = $GLOBALS["m_con"];
    $res = mysqli_query($con, $sql);
    if ($res === false && $test === true) {
        echo mysqli_error($con);
    }
    return $res;
}

function m_filter($value) {
    return mysqli_real_escape_string($GLOBALS["m_con"], $value);
}

function m_select($search_target_col, $search_table, $search_options = null, $cover = false, $query_test = false) {
    // where / like / join / cond / limit / offset / orderby / adesc / distinct
    // 조합을 받아 SELECT SQL을 직접 구성하던 유틸 함수
}

function m_insert($input, $input_table, $debug = false) {
    // INSERT SQL 직접 생성
}

function m_update($input, $update_table, $target, $target_s = null, $debug = false) {
    // UPDATE SQL 직접 생성
}
?>

프론트와 Ajax 처리 파일을 분리하고, `prc` 값에 따라 include할 백엔드 파일을 맵으로 관리하던 방식입니다.

<?php
$req_group = [];

$req_group["login.php"] = [
    "lgn" => [
        "explan" => "로그인",
        "file" => "../rescue/request/Login/Login.php"
    ],
    "unza" => [
        "explan" => "회원가입",
        "file" => "../rescue/request/Login/Signup.php"
    ]
];

$req_group["Mypage/infomation.php"] = [
    "gmi" => [
        "explan" => "내 입금정보 조회",
        "file" => "../rescue/request/Mypage/Getmypayinfo.php"
    ],
    "prg" => [
        "explan" => "정산 요청",
        "file" => "../rescue/request/Mypage/PriceRequest.php"
    ]
];

$req_group["project/5/label/"] = [
    "pch5l1" => [
        "explan" => "Match 제출",
        "file" => "../rescue/request/Project/label/submit/5-1.php"
    ],
    "pch5l2" => [
        "explan" => "Caption 제출",
        "file" => "../rescue/request/Project/label/submit/5-2.php"
    ]
];

$req_group["project/6/apply"] = [
    "gettourid" => [
        "explan" => "관광지 목록 획득",
        "file" => "../rescue/request/Project/6/apply/gettourid.php"
    ],
    "toapp" => [
        "explan" => "관광지 방문 신청",
        "file" => "../rescue/request/Project/6/apply/tourapply.php"
    ]
];

$req_settings = [];
foreach ($req_group as $reqk => $reqv) {
    foreach ($reqv as $reqvk => $reqvv) {
        $req_settings[$reqvk] = $reqvv;
    }
}
?>

세션 권한 검사 후, 남은 작업을 검색해서 점유하고 작업 페이지를 반환하는 구조였습니다. 작업이 없으면 자동 대기 후 재검색했습니다.

<?php
session_start();

// 권한 확인
$session_permissions = m_select(
    "*",
    "`na-now`.`Workers-projects`",
    [
        "where" => "uid",
        "like" => $_SESSION["na-now"]["uid"]
    ]
);

// 내가 방금 잡던 작업이 남아 있으면 다시 로드
// 없으면 남은 작업량 중 하나를 찾아 status를 내 uid로 점유
// 더 이상 작업이 없으면 잠시 대기 후 재조회

function draw_data($data, $type, $meta = null) {
    switch ("$type") {
        case "0":
            include "../rescue/request/Project/ref/ref-html/1-1.php";
            pt($data);
            break;
        case "1":
            include "../rescue/request/Project/ref/ref-html/1-2.php";
            pt($data);
            break;
    }
    exit;
}

function sql($rand, $re, $missions, $isfix = false) {
    // 작업 검색 -> status 점유 -> 작업 화면 출력
    // 없으면 자동 대기 화면 반환
}

sql($rand, false, $missions, $fix);
?>
Closing

문제를 해결하는 과정 자체를 즐기며 성장한 경험

직접 서버를 세팅하고, 작업 도구를 만들고, 자동화와 운영 문제를 해결하면서 쌓은 경험을 이 페이지에 정리했습니다. 완벽한 구조는 아니었지만, 실제 프로젝트를 끝까지 굴리며 개선해온 과정 자체가 가장 큰 자산이었습니다.