데이터 셋업
소개
Netuno에서 애플리케이션 개발은 먼저 데이터베이스 구축에서 시작되며, 폼과 필드를 구성하는 과정을 거칩니다.
팀으로 작업하거나 애플리케이션 개발을 다른 환경으로 옮겨야 할 때는 코드와 함께 데이터베이스 백업을 생성해야 합니다.
따라서 대상 환경에서는 데이터베이스를 다시 구성해야 하며, 그렇게 해야 애플리케이션이 원래 개발된 대로 실행될 수 있습니다.
이 과정의 문제는 데이터베이스가 변경될 때마다 항상 새 백업을 만들어야 한다는 점을 기억해야 하는 노력입니다. 개발에 참여하는 사람이 많을수록, 그리고/또는 애플리케이션을 배포할 환경이 많을수록 이 과정은 더 복잡해집니다.
Netuno는 이 문제를 해결하기 위해 애플리케이션 셋업 시스템을 제공합니다. 이 시스템은 데이터베이스 구조(스키마)를 자동으로 생성하며, 추가로 스크립트를 통해 초기 데이터 로딩을 수동으로 프로그래밍할 수 있습니다.
또한 데이터베이스 서버 유형을 변경해도 셋업이 정상적으로 실행되고 애플리케이션에 문제가 없도록 보장합니다. 즉, 애플리케이션을 H2DataBase에서 개발하고 자동 생성된 스키마를 통해 애플리케이션의 데이터베이스 연결을 PostgreSQL 또는 MariaDB로 변경할 수 있습니다. 새 데이터베이스에서 애플리케이션을 처음 실행하면 데이터베이스 서버 유형 변경과 관계없이 모든 것이 재구성됩니다.
따라서 이미 수행된 개발에 영향을 주지 않고 데이터베이스를 완전히 변경할 수 있습니다.
셋업 프로그래밍 파일은 애플리케이션 폴더 내 다음 위치에 있습니다:
server/setup
셋업 구성
애플리케이션의 환경 설정 파일 위치:
/apps/MY_APP/config/_development.json/apps/MY_APP/config/_production.json
다음 설정을 통해 'setup' 동작을 조작할 수 있습니다:
...
"setup": {
"enabled": true,
"schema": {
"auto_create": true,
"execution": true
},
"scripts": {
"execution": true
}
},
...
enabled: boolean > 기본값 true
셋업이 활성화되어 있는지 여부를 정의하며, 애플리케이션이 처음 실행될 때 데이터 셋업 작업의 실행을 활성화 또는 비활성화합니다.
schema.auto_create: boolean > 기본값 true
폼이나 필드가 생성 또는 변경될 때마다 Netuno가 데이터베이스 스키마 파일을 생성해야 하는지 여부를 알 수 있게 합니다.
schema.execution: boolean > 기본값 true
애플리케이션 첫 실행 시 수행되는 셋업 작업 중 스키마를 실행할지 여부를 제어합니다.
scripts.execution: boolean > 기본값 true
애플리케이션 첫 실행 시 수행되는 셋업 작업 중 추가 스크립트의 실행을 활성화 또는 비활성화합니다.
스키마
Netuno 웹 인터페이스에서 폼과 필드를 생성하거나 변경하는 동안 setup 폴더 안에 다음과 같은 형태로 스키마 파일이 생성됩니다:
- JavaScript
- TypeScript
- Python
- Ruby
- Kotlin
- Groovy
server/setup/_schema-FORM_NAME.js
server/setup/_schema-FORM_NAME.ts
server/setup/_schema-FORM_NAME.py
server/setup/_schema-FORM_NAME.rb
server/setup/_schema-FORM_NAME.kts
server/setup/_schema-FORM_NAME.groovy
여기서 애플리케이션에 존재하는 각 폼마다 _schema-*** 파일이 하나씩 생성됩니다.
이 파일들은 Netuno가 자동으로 생성하므로 수동으로 변경해서는 안 됩니다.
따라서 이 파일들의 내용을 변경하면 다음 스키마 생성 시 자동으로 대체되며, 파일에 직접 수행한 변경 사항은 손실됩니다.
데이터베이스 스키마 자동 생성이 실행되려면 schema.auto_create 설정이 활성화되어 있고 setup 폴더가 server 폴더 안에 존재하는지 확인해야 합니다.
스크립트
맞춤형으로 프로그래밍된 코드 스크립트는 setup 폴더에 있으며 _로 시작하지 않는 파일입니다.
이 스크립트의 주요 목적은 애플리케이션이 올바르게 동작하는 데 필요한 최소 정보가 데이터베이스에 포함되도록 데이터를 로드하는 것입니다.
따라서 애플리케이션이 다른 환경에서 재구성되면 초기 데이터가 자동으로 로드되어 바로 사용할 준비가 됩니다.
이러한 데이터 로딩 작업을 수행하려면 _db 리소스의 함수를 사용해야 합니다.
__스크립트__는 스키마 실행 후에 _로 시작하지 않는 파일 이름의 영숫자 순서대로 실행됩니다.
실행 순서를 정의하려면 파일 이름을 숫자 시퀀스로 시작하는 것이 가장 좋습니다. 따라서 사용자 지정 스크립트는
_로 시작하지 않는 파일 이름 순서대로 실행됩니다.
사용자 지정 데이터 삽입
데이터베이스에서 조회를 수행해 삽입 가능 여부를 확인하는 작업을 줄이기 위해 Netuno는 insertIfNotExists 함수를 제공합니다.
이 함수는 데이터가 데이터베이스에 정의된 그대로 존재하는지 확인하고, 존재하지 않으면 생성을 수행합니다.
사용 예로 영토 유형 폼의 코드 및 이름 필드를 로드할 수 있습니다. 여기서 테이블 이름은 __territory_type__이고 code 및 name 열을 가집니다. 이를 위해서는 다음 내용으로 파일을 생성하면 됩니다:
- JavaScript
- TypeScript
- Python
- Ruby
- Kotlin
- Groovy
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "1001")
.set("name", "대륙")
);
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "1002")
.set("name", "군도")
);
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "2003")
.set("name", "해양")
);
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "3004")
.set("name", "항공")
);
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "1001")
.set("name", "대륙")
);
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "1002")
.set("name", "군도")
);
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "2003")
.set("name", "해양")
);
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "3004")
.set("name", "항공")
);
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "1001")
.set("name", "대륙")
)
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "1002")
.set("name", "군도")
)
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "2003")
.set("name", "해양")
)
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "3004")
.set("name", "항공")
)
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "1001")
.set("name", "대륙")
)
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "1002")
.set("name", "군도")
)
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "2003")
.set("name", "해양")
)
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "3004")
.set("name", "항공")
)
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "1001")
.set("name", "대륙")
)
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "1002")
.set("name", "군도")
)
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "2003")
.set("name", "해양")
)
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "3004")
.set("name", "항공")
)
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "1001")
.set("name", "대륙")
)
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "1002")
.set("name", "군도")
)
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "2003")
.set("name", "해양")
)
_db.insertIfNotExists("territory_type", _val.map()
.set("code", "3004")
.set("name", "항공")
)
처리 주기
이미 설명한 것처럼 셋업은 애플리케이션 첫 실행 시에만 실행됩니다.
실행 순서는 다음과 같습니다:
_start- 초기화 파일을 실행하며, 모든 종류의 사용자 지정 프로그래밍을 포함할 수 있습니다:- JavaScript
- TypeScript
- Python
- Ruby
- Kotlin
- Groovy
MY_APP/server/setup/_start.js
MY_APP/server/setup/_start.ts
MY_APP/server/setup/_start.py
MY_APP/server/setup/_start.rb
MY_APP/server/setup/_start.kts
MY_APP/server/setup/_start.groovy
_cleanup- 폼, 보고서 및 해당 필드를 프로그래밍 방식으로 제거합니다:- JavaScript
- TypeScript
- Python
- Ruby
- Kotlin
- Groovy
MY_APP/server/setup/_cleanup.js
MY_APP/server/setup/_cleanup.ts
MY_APP/server/setup/_cleanup.py
MY_APP/server/setup/_cleanup.rb
MY_APP/server/setup/_cleanup.kts
MY_APP/server/setup/_cleanup.groovy
_schema-*- _schema- 접두사가 붙은 모든 스크립트를 실행하며, 폼, 보고서 및 해당 필드 생성 명령을 포함합니다:- JavaScript
- TypeScript
- Python
- Ruby
- Kotlin
- Groovy
MY_APP/server/setup/_schema-auto_generated_structure.jsMY_APP/server/setup/_schema-category.jsMY_APP/server/setup/_schema-product.jsMY_APP/server/setup/_schema-customer.js
MY_APP/server/setup/_schema-auto_generated_structure.tsMY_APP/server/setup/_schema-category.tsMY_APP/server/setup/_schema-product.tsMY_APP/server/setup/_schema-customer.ts
MY_APP/server/setup/_schema-auto_generated_structure.pyMY_APP/server/setup/_schema-category.pyMY_APP/server/setup/_schema-product.pyMY_APP/server/setup/_schema-customer.py
MY_APP/server/setup/_schema-auto_generated_structure.rbMY_APP/server/setup/_schema-category.rbMY_APP/server/setup/_schema-product.rbMY_APP/server/setup/_schema-customer.rb
MY_APP/server/setup/_schema-auto_generated_structure.ktsMY_APP/server/setup/_schema-category.ktsMY_APP/server/setup/_schema-product.ktsMY_APP/server/setup/_schema-customer.kts
MY_APP/server/setup/_schema-auto_generated_structure.groovyMY_APP/server/setup/_schema-category.groovyMY_APP/server/setup/_schema-product.groovyMY_APP/server/setup/_schema-customer.groovy
001-other_scripts- 사용자 지정 프로그래밍 스크립트 파일을 실행합니다._로 시작하지 않는 모든 파일이며, 필요한 초기 데이터 삽입 또는 기타 사용자 지정 개발을 포함할 가능성이 높습니다. 예:- JavaScript
- TypeScript
- Python
- Ruby
- Kotlin
- Groovy
MY_APP/server/setup/001-insert_custom_data.jsMY_APP/server/setup/002-category.jsMY_APP/server/setup/003-product.jsMY_APP/server/setup/004-customer.js
MY_APP/server/setup/001-insert_custom_data.tsMY_APP/server/setup/002-category.tsMY_APP/server/setup/003-product.tsMY_APP/server/setup/004-customer.ts
MY_APP/server/setup/001-insert_custom_data.pyMY_APP/server/setup/002-category.pyMY_APP/server/setup/003-product.pyMY_APP/server/setup/004-customer.py
MY_APP/server/setup/001-insert_custom_data.rbMY_APP/server/setup/002-category.rbMY_APP/server/setup/003-product.rbMY_APP/server/setup/004-customer.rb
MY_APP/server/setup/001-insert_custom_data.ktsMY_APP/server/setup/002-category.ktsMY_APP/server/setup/003-product.ktsMY_APP/server/setup/004-customer.kts
MY_APP/server/setup/001-insert_custom_data.groovyMY_APP/server/setup/002-category.groovyMY_APP/server/setup/003-product.groovyMY_APP/server/setup/004-customer.groovy
- _end - 마무리 파일을 실행하며, 모든 종류의 사용자 지정 프로그래밍을 포함할 수 있습니다:
- JavaScript
- TypeScript
- Python
- Ruby
- Kotlin
- Groovy
MY_APP/server/setup/_end.js
MY_APP/server/setup/_end.ts
MY_APP/server/setup/_end.py
MY_APP/server/setup/_end.rb
MY_APP/server/setup/_end.kts
MY_APP/server/setup/_end.groovy
즉, start 및 end 스크립트에서 사용자 지정 코드를 생성하여 셋업 전에 또는 셋업이 완료될 때 실행하는 것이 타당한 일부 작업을 수행할 수 있습니다.
이 처리 주기는 애플리케이션이 처음 실행될 때마다 실행된다는 점을 다시 강조해야 합니다. 따라서 데이터 생성 전에 데이터 존재 여부를 반드시 확인해야 합니다.
환경에 따라 MY_APP/config/_development.json 또는 MY_APP/config/_production.json 파일에서 이 프로세스 실행을 허용하려면 다음 설정이 활성화되어 있는지 확인하세요:
-
모든 셋업 작업 실행을 완전히 활성화 또는 비활성화합니다:
setup.enabled = true|false -
_schemas- 실행을 활성화 또는 비활성화합니다:
setup.schema.execution = true|false -
스크립트 실행을 활성화 또는 비활성화합니다:
setup.scripts.execution = true|false
정리
폼과 필드 제거를 프로그래밍하려면 _cleanup.js 스크립트를 사용해야 합니다. 이렇게 하면 프로젝트 파일을 동기화하는 모든 환경에서 셋업 실행 시 구조가 존재하는 경우 제거됩니다.
정리 스크립트 예:
- JavaScript
- TypeScript
- Python
- Ruby
- Kotlin
- Groovy
// zone 폼을 제거합니다:
_form.dropIfExists("zone");
// area 폼에서 subarea_id 필드를 제거합니다:
_form.dropFieldIfExists("area", "subarea_id");
// zone 폼을 제거합니다:
_form.dropIfExists("zone");
// area 폼에서 subarea_id 필드를 제거합니다:
_form.dropFieldIfExists("area", "subarea_id");
# zone 폼을 제거합니다:
_form.dropIfExists("zone")
# area 폼에서 subarea_id 필드를 제거합니다:
_form.dropFieldIfExists("area", "subarea_id")
# zone 폼을 제거합니다:
_form.dropIfExists("zone")
# area 폼에서 subarea_id 필드를 제거합니다:
_form.dropFieldIfExists("area", "subarea_id")
// zone 폼을 제거합니다:
_form.dropIfExists("zone")
// area 폼에서 subarea_id 필드를 제거합니다:
_form.dropFieldIfExists("area", "subarea_id")
// zone 폼을 제거합니다:
_form.dropIfExists("zone")
// area 폼에서 subarea_id 필드를 제거합니다:
_form.dropFieldIfExists("area", "subarea_id")
DBML
Netuno가 데이터 셋업을 실행할 때마다 다음 파일이 생성됩니다:
server/setup/_db-schema.dbml
이 파일은 인공지능과 함께 사용할 수 있는 전체 데이터 구조를 담고 있습니다.
인공지능은 DBML 내용을 기반으로 데이터 구조를 이해하고 정확한 SQL 쿼리를 생성할 수 있습니다.
이 파일을 프롬프트에 첨부로 사용하고 복잡한 SQL 쿼리를 생성해 달라고 요청해 보세요. 좋은 결과를 얻을 수 있을 것입니다.
결론
Netuno에서 애플리케이션 셋업 프로세스의 주요 기능은 다음과 같습니다:
- _schema-: 모든 폼과 보고서 구조를 해당 필드와 함께 자동으로 생성하여, 특히 애플리케이션이 비어 있는 새 데이터베이스에서 실행될 때 애플리케이션 데이터베이스 구조의 일관성을 보장합니다.
- 스크립트: 애플리케이션이 처음 실행될 때마다 필수 데이터가 미리 로드되어 있도록 데이터베이스 작업을 수행합니다.
이렇게 Netuno는 데이터베이스 유형을 변경하더라도 애플리케이션이 새 환경에서 동작하도록 하며, 데이터베이스 백업 및 복원 없이도 애플리케이션이 올바르게 동작하도록 보장합니다.
추가로 자동 및 수동으로 생성된 모든 구성 코드를 예를 들어 GIT로 버전 관리할 수 있습니다.