다들 말리는 ERP 개발 - 클로드코드 + Bkit

Lv.1 아침소리 (211.♡.103.115)

2026년 4월 8일 PM 04:54

조회 1,128 공감 0

하... 이거 마르지 않는 샘물이에요.

디버깅 이슈가 거의 없이 기능 추가, 수정이 되니 30년간 직딩하면서 고민하던거 다 때려박는 중입니다.

장비 관리, AS 기능 추가, 결제 포함 근태 관리 및 공유 등등..

일주일만 여기 전념하면 진짜 모든 직딩이 원하는 erp 나올거 같아요.

감히 이렇게 얘기할 수 있는건 대기업 신입 시절부터 개발부서 이면서도 이런 tf에 계속 불려다니면서 맨날 망하는거만 봐서..

대기업 -> 벤쳐 -> 중소수입사 -> 중기업 다니면서 어디서도 해결 못하던건데..

진짜 직원들의 일을 도와주면서 공유하는 시스템을 만들어내고 있습니다.

노션, 팀즈, 다 필요없을 정도로 갈수 있을거 같아요.

방금 작업 하고 있는 클로드코드 화면입니다.


● 완료. 관리 메뉴에 시스템 이력 페이지를 추가했습니다.

구성:

- 백엔드: GET /api/v1/activities — ADMIN 전용, 페이지네이션(30건씩), 유형/검색 필터

- 프론트엔드: /admin/activity-logs — 테이블 형태로 시간, 유형(배지), 프로젝트, 내용, 사용자 표시

- 필터: 유형 드롭다운 (태스크 생성/삭제, 상태변경, 진행률, 일정, 배정, 댓글 등 11종) + 설명 텍스트 검색

- 관리 메뉴: 결재라인 아래 "시스템 이력" 항목 추가

현재 450건의 기존 이력이 바로 조회됩니다. createdAt DESC 인덱스 + 페이지네이션으로 부하는 무시할

수준입니다.

✻ Cooked for 4m 26s

> 시스템 이력에서 사용자를 ID로 표시할 필요있나?

● 맞습니다. 이메일 앞부분 대신 사용자 이름으로 표시하겠습니다. activity_logs의 userId에 실제로 어떤 값이

저장되는지 확인합니다.

● Bash(docker exec erp-ot-postgres psql -U erp_user -d erp_ot -t -A -c "

SELECT DISTINCT \"userId\" FROM project.activity_logs LIMIT 10;")

⎿  cmmx5lkhq000ichn44ceb8s7v

cmmyi7dcl00026314d6x7evzn

user-admin1

… +7 lines (ctrl+o to expand)

● userId는 UUID와 문자열이 혼재합니다. 백엔드에서 사용자 이름을 join해서 내려주겠습니다.

Read 1 file (ctrl+o to expand)

● auth-service에 내부 API로 사용자 이름을 일괄 조회하는 것보다, 같은 쿼리에서 처리하는 게 낫습니다.

activity_logs의 userId로 auth_users를 직접 조회할 수 없으므로(다른 스키마), raw query 또는 프론트에서

사용자 목록을 매핑합니다. 프론트에서 이미 userManagementApi.list()로 사용자 목록을 가져올 수 있으니 그

방식이 가장 간단합니다.

● Update(apps\web\src\app\admin\activity-logs\page.tsx)

⎿  Added 1 line, removed 1 line

2

3 import { useEffect, useState } from "react";

4 import { useRouter } from "next/navigation";

5 -import { activityLogApi, getUser } from "@/lib/api";

5 +import { activityLogApi, userManagementApi, getUser } from "@/lib/api";

6

7 const ACTION_LABELS: Record<string, { label: string; color: string }> = {

8 TASK_CREATED: { label: "태스크 생성", color: "bg-blue-100 text-blue-700" },

● Update(apps\web\src\app\admin\activity-logs\page.tsx)

⎿  Added 11 lines

43 const [actionFilter, setActionFilter] = useState("");

44 const [search, setSearch] = useState("");

45 const [searchInput, setSearchInput] = useState("");

46 + const [userMap, setUserMap] = useState<Map<string, string>>(new Map());

47

48 useEffect(() => {

49 const user = getUser();

50 if (!user || user.role !== "ADMIN") { router.replace("/projects"); return; }

51 + // 사용자 ID→이름 매핑 로드

52 + userManagementApi.list().then((data) => {

53 + const users: any[] = Array.isArray(data) ? data : ((data as any).items ?? []);

54 + const map = new Map<string, string>();

55 + for (const u of users) {

56 + map.set(u.id, u.name);

57 + if (u.email) map.set(u.email, u.name);

58 + }

59 + setUserMap(map);

60 + }).catch(() => {});

61 }, []);

62

63 useEffect(() => {

● Update(apps\web\src\app\admin\activity-logs\page.tsx)

⎿  Added 1 line, removed 1 line

172 <div className="text-[11px] text-gray-400 mt-0.5">태스크: {meta

.taskName}</div>

173 )}

174 </td>

175 - <td className="px-3 py-2 text-xs text-gray-500 whitespace-nowrap">{

-item.userId?.split("@")[0] ?? "-"}</td>

175 + <td className="px-3 py-2 text-xs text-gray-500 whitespace-nowrap">{

+userMap.get(item.userId) ?? "-"}</td>

176 </tr>

177 );

178 })}

● 완료. 사용자 ID/이메일 대신 이름으로 표시하도록 변경했습니다. 페이지 로딩 시 사용자 목록을 한 번

가져와서 ID→이름 매핑을 만들고, 각 이력 행에서 이름으로 보여줍니다.

✻ Worked for 1m 5s

> 시간은 연월일시분초 로..

● Update(apps\web\src\app\admin\activity-logs\page.tsx)

⎿  Added 7 lines, removed 11 lines

20

21 function formatDate(iso: string) {

22 const d = new Date(iso);

23 - const now = new Date();

24 - const diffMs = now.getTime() - d.getTime();

25 - const diffMin = Math.floor(diffMs / 60000);

26 - if (diffMin < 1) return "방금 전";

27 - if (diffMin < 60) return ${diffMin}분 전;

28 - const diffHour = Math.floor(diffMin / 60);

29 - if (diffHour < 24) return ${diffHour}시간 전;

30 - const diffDay = Math.floor(diffHour / 24);

31 - if (diffDay < 7) return ${diffDay}일 전;

32 - return d.toLocaleDateString("ko-KR", { year: "numeric", month: "2-digit", day: "2-digi

-t" })

33 - + " " + d.toLocaleTimeString("ko-KR", { hour: "2-digit", minute: "2-digit" });

23 + const y = d.getFullYear();

24 + const m = String(d.getMonth() + 1).padStart(2, "0");

25 + const dd = String(d.getDate()).padStart(2, "0");

26 + const hh = String(d.getHours()).padStart(2, "0");

27 + const mm = String(d.getMinutes()).padStart(2, "0");

28 + const ss = String(d.getSeconds()).padStart(2, "0");

29 + return ${y}-${m}-${dd} ${hh}:${mm}:${ss};

30 }

31

32 export default function ActivityLogsPage() {

● 완료. 2026-04-08 16:50:06 형식으로 표시됩니다.

> 현재 도커 이미지 크기가 얼마지?

● Bash(docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" | grep -i erp)

⎿  erp_ot-project-service latest 504MB

erp_ot-equipment-service latest 500MB

erp_ot-attendance-service latest 498MB

… +4 lines (ctrl+o to expand)

● ┌────────────────────┬──────────┐

│ 이미지 │ 크기 │

├────────────────────┼──────────┤

│ auth-service │ 535MB │

├────────────────────┼──────────┤

│ project-service │ 504MB │

├────────────────────┼──────────┤

│ equipment-service │ 500MB │

├────────────────────┼──────────┤

│ attendance-service │ 498MB │

├────────────────────┼──────────┤

│ user-service │ 487MB │

├────────────────────┼──────────┤

│ web (Next.js) │ 224MB │

├────────────────────┼──────────┤

│ 합계 │ 약 2.7GB │

└────────────────────┴──────────┘

백엔드 서비스들이 각 500MB 내외로 큰 편입니다. Node.js 베이스 이미지 + Prisma 엔진 + node_modules가

원인입니다. 필요하면 multi-stage 빌드 최적화로 절반 이하로 줄일 수 있습니다.

> 현재 이력은 프로젝트 관련만 있는데 다른 부분도 넣을수 있나? 넣을 수 있다면 어떤 내용이 필요하지?

● 현재 각 서비스에서 이력으로 남길 수 있는 항목을 정리하겠습니다.

현재 상태

- project-service: 이미 activity_logs 테이블에 기록 중 (450건)

추가 가능한 이력

┌────────────────────┬───────────────────────────┬─────────────────────────┬─────────────┐

│ 서비스 │ 이벤트 │ 중요도 │ 구현 난이도 │

├────────────────────┼───────────────────────────┼─────────────────────────┼─────────────┤

│ auth-service │ 로그인 성공/실패 │ 높음 │ 낮음 │

├────────────────────┼───────────────────────────┼─────────────────────────┼─────────────┤

│ │ 사용자 생성/수정/비활성화 │ 높음 │ 낮음 │

├────────────────────┼───────────────────────────┼─────────────────────────┼─────────────┤

│ │ 비밀번호 초기화 │ 높음 │ 낮음 │

├────────────────────┼───────────────────────────┼─────────────────────────┼─────────────┤

│ │ 부서 생성/수정/삭제 │ 중간 │ 낮음 │

├────────────────────┼───────────────────────────┼─────────────────────────┼─────────────┤

│ │ 결재라인 변경 │ 중간 │ 낮음 │

├────────────────────┼───────────────────────────┼─────────────────────────┼─────────────┤

│ │ 권한(role) 변경 │ 높음 │ 낮음 │

├────────────────────┼───────────────────────────┼─────────────────────────┼─────────────┤

│ attendance-service │ 출퇴근 기록 │ 낮음 (이미 별도 테이블) │ - │

├────────────────────┼───────────────────────────┼─────────────────────────┼─────────────┤

│ │ 휴가 신청/승인/반려 │ 중간 │ 낮음 │

├────────────────────┼───────────────────────────┼─────────────────────────┼─────────────┤

│ │ 초과근무 신청/승인 │ 중간 │ 낮음 │

├────────────────────┼───────────────────────────┼─────────────────────────┼─────────────┤

│ equipment-service │ 장비 등록/수정/폐기 │ 중간 │ 낮음 │

├────────────────────┼───────────────────────────┼─────────────────────────┼─────────────┤

│ │ 수리 접수/상태변경 │ 중간 │ 낮음 │

├────────────────────┼───────────────────────────┼─────────────────────────┼─────────────┤

│ │ 센서 배치/회수 │ 낮음 │ 낮음 │

└────────────────────┴───────────────────────────┴─────────────────────────┴─────────────┘

추천: 우선 넣을 것

auth-service 이력이 가장 가치 있습니다:

1. 로그인 이력 — 보안 감사, 마지막 접속 확인

2. 권한/역할 변경 — 누가 언제 누구 권한을 바꿨는지

3. 사용자 생성/비활성화 — 인사 변동 추적

4. 부서/결재라인 변경 — 조직 변경 이력

구현 방식

두 가지 옵션이 있습니다:

┌────────────────────────────────────────┬─────────────────┬───────────────────────────────────────┐

│ 방식 │ 장점 │ 단점 │

├────────────────────────────────────────┼─────────────────┼───────────────────────────────────────┤

│ A. 각 서비스 자체 DB에 기록 │ 간단, 서비스 │ 통합 조회 시 여러 DB 호출 │

│ │ 독립 │ │

├────────────────────────────────────────┼─────────────────┼───────────────────────────────────────┤

│ B. project-service의 activity_logs에 │ 한 곳에서 조회 │ 서비스 간 의존성 (내부 API 또는 │

│ 통합 │ │ RabbitMQ) │

└────────────────────────────────────────┴─────────────────┴───────────────────────────────────────┘

B 방식 + RabbitMQ가 좋습니다. 이미 RabbitMQ가 docker-compose에 있고, 각 서비스가 이벤트를 publish하면

project-service가 consume해서 activity_logs에 저장하면 됩니다. 비동기라 부하 영향도 없습니다.

auth-service 이력부터 넣을까요?

> B방식으로 하자.

● 먼저 현재 RabbitMQ 설정을 확인합니다.

Searched for 1 pattern, read 1 file (ctrl+o to expand)

● project-service만 RABBITMQ_URL이 있네요. auth-service에도 추가해야 합니다.

Reading 1 file… (ctrl+o to expand)

⎿ docker-compose.yml

✻ Compacting conversation… (2m 35s · ↑ 64 tokens · thought for 2s)

⎿  Tip: Use /btw to ask a quick side question without interrupting Claude's current work

댓글 (7)

  • DEFT

    DEFT Lv.1

    04.08 · 121.♡.110.211

    웹어플리케이션으로 만드시는 건가요?. 플랫폼이 궁금합니다.

    저는 microsoft ACCESS와 mysql 갖고 만들고 있거든요.

  • 아침소리 Lv.1 → DEFT 작성자

    04.08 · 211.♡.103.115

    바이브코딩 만으로 개발중입니다. 클로드코드 + bkit 이라는 플러그인 입니다.

    엔터프라이즈 급으로 최초 사양을 만들라고 했더니 도커에 백앤드와 DB를 넣고 프론트앤드로 구성이 된다네요.

    -> 저는 암것도 모릅니다.ㅎㅎㅎ

    디지인이고 뭐고 암것도 모르고 기능만 상세히 정의해서 진행했는데 여기까지 왔네요.

    대략 3주정도 걸렸습니다. 업무 짬짬히 혼자 하면서요..

  • 육류

    육류 Lv.1

    04.08 · 211.♡.79.130

    필요는 한데 만들 시간이 없어서 도전은 못하고 있습니다...

  • 마이너스아이

    마이너스아이 Lv.1

    04.08 · 61.♡.139.51

    저랑 같은 테크 트리를 타고 계시는 군요.

    30년 넘게 하던 일이 있는데 다 때려 넣고 있습니다.

    이제는 심지어 각종 메뉴얼, 제품소개서, 세일즈킷, crm 까지 혼자서 다하고 있습니다. 무섭습니다.

  • 비눗방울

    비눗방울 Lv.1

    04.08 · 223.♡.43.96

    멋지십니다. 기능은 개발하시는 것보다 덜하지만 저도 사내시스템 오픈했습니다. 아주 만족중입니다.
    이제 좀 더 붙여볼 내용을 고민중입니다.^^

  • 남극백곰

    남극백곰 Lv.1

    04.08 · 223.♡.47.77

    이게 뭐죠??? 넘 어지러워요... ㅠㅠ

  • 아리니아빠

    아리니아빠 Lv.1

    04.08 · 121.♡.83.61

    저도 하고 있는데, 만드신 것 보니 그룹웨어 + 워크플로우 관리 다 때려 박아야 하는 고민에 빠졌습니다.

    괜히 봤네요 ㅠㅠ

댓글을 작성하려면 이 필요합니다.