본문 바로가기

카테고리 없음

메타데이터 기반의 동적 오브젝트/테이블 관리 시스템

반응형

1. Object Manager의 핵심 기능 요약

| 기능 | 설명 |
|------|------|
| ✅ 커스텀 오브젝트 생성 | 사용자가 새로운 데이터 객체(예: `__c`)를 정의 |
| ✅ 필드 추가/수정/삭제 | 각 오브젝트에 다양한 타입의 필드(텍스트, 숫자, 날짜 등) 추가 가능 |
| ✅ 관계 설정 | Lookup, Master-Detail 등의 관계 정의 |
| ✅ 메타데이터 저장 | 오브젝트/필드 정보를 별도의 메타 테이블에 저장 |
| ✅ 동적 DDL/DML | 오브젝트 생성 시 DB 테이블 자동 생성 및 CRUD 쿼리 처리 |
| ✅ UI 제공 (React 기반) | 사용자 친화적인 웹 인터페이스 제공 |
| ✅ 접근 제어 (권한) | 특정 오브젝트/필드에 대한 읽기/쓰기 권한 관리 |

---

## 🧱 2. 전체 아키텍처 설계 (React + Spring Boot + MyBatis + MariaDB)

```
[Frontend: React]
       ↓ (REST API)
[Backend: Spring Boot]
       ↓
[MyBatis] → [MariaDB]
```

### 🔸 Frontend (React)
- **목표**:직관적인 UI 제공
- **주요 구성**
  - Object 목록 페이지
  - Object 생성 폼 (이름, 라벨 등)
  - Field 관리 패널 (필드명, 타입, null 허용 여부 등)
  - Relationship 설정 UI
  - 실시간 미리보기 (생성될 테이블 구조)
- **라이브러리 추천**
  - `react-hook-form` / `formik`: 폼 관리
  - `antd` / `material-ui`: 컴포넌트
  - `axios`: 백엔드 API 호출


### 🔸 Backend (Spring Boot)
- **모듈 구성**
  - `object-service`: 오브젝트 메타데이터 관리
  - `field-service`: 필드 메타데이터 관리
  - `relationship-service`: 관계 설정 및 외래키 처리
  - `dynamic-dao`: 동적 SQL 생성 및 실행
  - `metadata-controller`: REST API 엔드포인트

#### 📂 주요 엔티티 설계 (JPA가 아닌 순수 MyBatis 사용 가정)
-- 1. 오브젝트 메타데이터
CREATE TABLE meta_object (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    object_name VARCHAR(100) UNIQUE NOT NULL, -- 실제 테이블 이름 (e.g., custom_account)
    label VARCHAR(100) NOT NULL,
    description TEXT,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME ON UPDATE CURRENT_TIMESTAMP
);

-- 2. 필드 메타데이터
CREATE TABLE meta_field (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    object_id BIGINT NOT NULL,
    field_name VARCHAR(100) NOT NULL, -- 컬럼명
    label VARCHAR(100),
    data_type ENUM('TEXT', 'NUMBER', 'DATE', 'DATETIME', 'BOOLEAN', 'LOOKUP') NOT NULL,
    length INT,
    precision INT,
    scale INT,
    is_required BOOLEAN DEFAULT FALSE,
    default_value VARCHAR(255),
    FOREIGN KEY (object_id) REFERENCES meta_object(id),
    UNIQUE(object_id, field_name)
);

-- 3. 관계 메타데이터 (Lookup 또는 Master-Detail)
CREATE TABLE meta_relationship (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    child_object_id BIGINT NOT NULL,
    parent_object_id BIGINT NOT NULL,
    relationship_type ENUM('LOOKUP', 'MASTER_DETAIL') DEFAULT 'LOOKUP',
    field_name VARCHAR(100), -- 생성될 외래키 컬럼명
    FOREIGN KEY (child_object_id) REFERENCES meta_object(id),
    FOREIGN KEY (parent_object_id) REFERENCES meta_object(id)
);

> 💡 **주의**: 실제 테이블은 `meta_object.object_name` 기반으로 동적으로 생성됨 (ex: `custom_account`, `custom_project`)

## ⚙️ 3. 핵심 로직 구현 방안

### ✅ 1. 오브젝트 생성 시 동적 테이블 생성
- 사용자가 "New Object"를 생성하면:
  - `meta_object`에 레코드 삽입
  - MariaDB에 `CREATE TABLE custom_xxx (...)` 실행
- 예시 (Spring에서 동적 DDL):

```java
@Service
public class DynamicTableService {

    @Autowired
    private SqlSession sqlSession;

    public void createTable(String tableName) {
        String sql = String.format(
            "CREATE TABLE %s (id BIGINT AUTO_INCREMENT PRIMARY KEY)", tableName);
        sqlSession.getConnection().createStatement().execute(sql);
    }

    public void addColumn(String tableName, String columnName, String columnType) {
        String sql = String.format("ALTER TABLE %s ADD COLUMN %s %s",
            tableName, columnName, mapToDbType(columnType));
        sqlSession.getConnection().createStatement().execute(sql);
    }
}
```

> ⚠️ **주의**: DDL은 MyBatis보다 JDBC 직접 사용 권장 (MyBatis는 DML 중심)

---

### ✅ 2. 동적 CRUD 구현 (DML)
- 오브젝트와 필드가 동적으로 결정되므로, 정적 Mapper 사용 불가
- **해결책**: XML 기반 동적 SQL or Java에서 StringBuilder로 쿼리 생성

#### 예: 동적 SELECT (MyBatis XML 활용)

```xml
<select id="findRecords" resultType="map">
    SELECT 
    <foreach collection="fields" item="field" separator=",">
        ${field}
    </foreach>
    FROM ${tableName}
    <where>
        <if test="condition != null">
            ${condition}
        </if>
    </where>
</select>
```

또는 Java에서 `Map<String, Object>` 기반으로 처리:

```java
public List<Map<String, Object>> query(String tableName, Map<String, Object> params) {
    String sql = "SELECT * FROM " + tableName;
    // 파라미터 바인딩은 PreparedStatement 사용
    return jdbcTemplate.queryForList(sql);
}
```

---

### ✅ 3. 관계 처리 (외래키)
- `meta_relationship`에 기반하여 `ALTER TABLE ADD CONSTRAINT ... FOREIGN KEY` 실행
- 예: `custom_opportunity` → `custom_account` 연결

```sql
ALTER TABLE custom_opportunity 
ADD COLUMN account_id BIGINT,
ADD CONSTRAINT fk_account 
FOREIGN KEY (account_id) REFERENCES custom_account(id);
```

---

### ✅ 4. React에서의 동적 폼 생성
- 백엔드에서 `/api/objects/{name}/schema`로 메타데이터 조회
- 그에 맞춰 Form 렌더링

```jsx
// React 예시
useEffect(() => {
  fetch(`/api/objects/${objectName}/schema`)
    .then(res => res.json())
    .then(schema => setFields(schema.fields));
}, []);

return (
  <form>
    {fields.map(field => (
      <input 
        key={field.id}
        type={mapDataTypeToInput(field.data_type)}
        placeholder={field.label}
      />
    ))}
  </form>
);
```

---

## 🔐 4. 보안 및 권한 고려사항

- **오브젝트/필드 접근 제어**:
  - 별도의 `user_permission`, `role`, `field_level_security` 테이블 필요
- **SQL Injection 방지**:
  - 동적 쿼리는 반드시 `PreparedStatement` 사용
  - 사용자 입력은 무조건 검증 및 이스케이프
- **DDL 실행 권한 제한**:
  - 운영 환경에서는 DDL을 개발자 전용 모드에서만 허용

---

## 🔄 5. 생명주기 관리 및 버전 관리 (고급)

- 오브젝트 변경 이력 추적 (Audit Log)
- 스키마 마이그레이션 도구 연동 (Liquibase/Flyway 확장형 사용)
- 메타데이터 내보내기/가져오기 (JSON 형식)

---

## ✅ 6. 기술 스택 적합성 평가

| 기술 | 역할 | 적합성 |
|------|------|--------|
| **React** | 동적 폼, 메타기반 UI | ⭐⭐⭐⭐☆ |
| **Spring Boot** | REST API, 트랜잭션, DI | ⭐⭐⭐⭐⭐ |
| **MyBatis** | 동적 SQL, 메타 기반 쿼리 | ⭐⭐⭐⭐☆ (XML 유연성 있음) |
| **MariaDB** | 스토리지, DDL/DML | ⭐⭐⭐⭐☆ |
| | **단점**: JSON 스토리지 부족 | → MySQL 8.0+ 권장 |

> 💡 대안: **PostgreSQL**은 JSONB, 동적 스키마에 더 유리함

---

## 🚀 7. 추천 아키텍처 개선 방향

1. **Metadata-first 설계**
   - 모든 CRUD는 메타데이터 기반으로 결정
2. **Event-driven 처리**
   - 오브젝트 생성 시 Kafka/Spring Event로 알림
3. **캐싱 (Redis)**
   - 메타데이터는 자주 참조되므로 Redis 캐싱
4. **API Gateway + Microservices (확장 시)**

---

## 📚 8. 참고 자료 및 유사 오픈소스

- **Joget DX**, **ProcessMaker**: Low-code 플랫폼 (메타기반)
- **Hasura**, **PostgREST**: PostgreSQL 기반 동적 API 생성기
- **Apache MetaModel**: 자바에서 동적 데이터 접근 라이브러리
- **Spring Data JDBC**: 정적 ORM이 아닌 유연한 접근

## ✅ 결론

> Object Manager 유사 기능은 React + Spring + MyBatis + MariaDB 조합으로 충분히 구현 가능**하지만, 다음과 같은 점에 주의해야 합니다:

- ✅ **메타데이터 중심 설계**가 핵심
- ✅ **동적 DDL/DML 처리**는 안정성과 보안 강화 필요
- ✅ **UI는 메타데이터 기반으로 동적 렌더링**
- ✅ **관계 및 제약 조건은 외래키 + 메타 테이블로 관리**

---

## 🛠️ 다음 단계 제안

1. `meta_object`, `meta_field` 테이블 생성
2. Spring에서 Object CRUD API 구현 (MyBatis)
3. React에서 Object 생성 폼 개발
4. 오브젝트 생성 시 MariaDB 테이블 자동 생성 테스트
5. Field 추가 → 컬럼 추가 기능 연결
6. 관계 설정 및 외래키 자동 생성
7. 동적 폼 렌더링 및 데이터 저장


반응형