연간 재설정 순차 ID 생성기 - 다중 접두사 지원

Prev Next

To download the Yearly Resetting Sequential ID Generator - Multi-Prefix Support, visit: [tulip](https://<span translate=).co/library/apps/yearly-resetting-sequential-id-generator---multi-prefix-support/">Library

이 글에서는 저희 라이브러리 개발자 중 한 명인 타마스(Tamás)가 라이브러리에서 제공되는 ‘연간 재설정 순차 ID 생성기 - 다중 접두사 지원’ 빌딩 블록 앱의 개발 배경과 결정 과정을 설명합니다.

왜 이런 방식으로 만들었는가

저는 매우 실용적인 문제, 즉 신뢰할 수 있고 재사용하기 쉬우며 여러 앱에 빠르게 배포할 수 있는 방식으로 ID를 생성하기 위해 이 로직 블록을 설계했습니다.제 목표는 ID 자체에 다음 ID를 계산하는 데 필요한 모든 정보가 포함되도록 하는 것이었습니다. ID의 각 부분은 명확한 역할을 가지고 있습니다: * 접두사는 ID가 어떤 시퀀스에 속하는지 나타냅니다 * 연도는 시간의 흐름에 따라 시퀀스를 구분합니다 * 숫자는 해당 연도 내의 순서를 나타냅니다

이러한 구조 덕분에 별도의 재설정 로직을 도입할 필요가 없었습니다. 가장 최근의 기존 ID에는 이미 다음 ID를 생성하는 데 필요한 모든 정보가 포함되어 있습니다. 마지막 ID가 유효한 한, 다음 ID는 항상 예측 가능한 방식으로 계산될 수 있습니다.

연도를 ID에 직접 포함시킨 이유는, 연도가 시간의 흐름에 따라 레코드를 자연스럽게 구분해 주기 때문입니다. 또한 이를 통해 일정한 주기로 재설정하거나 수동으로 업데이트할 필요 없이 매년 번호 매기기가 자동으로 재개될 수 있습니다.

접두사는 서로 다른 순서열 간의 경계 역할을 합니다. 이를 통해 동일한 테이블 내에서 여러 개의 독립적인 번호 매기기 순서열을 운영할 수 있습니다. 접두사를 변경하는 것은 단순히 다른 순서열을 이어가는 것을 의미합니다.

전체 접근 방식이 일관된 ID 구조에 의존하기 때문에 유효성 검사를 추가했습니다. 기존 ID가 예상된 형식을 따르지 않는 경우, 시퀀스를 계속 진행하면 혼란스럽거나 일관성 없는 결과가 발생할 수 있습니다. 차라리 조기에 중단하고 문제를 명확히 파악하여 잘못된 ID가 생성되는 것을 방지하는 편이 낫습니다.

커넥터 기반의 조회 방식을 선택한 이유는, 핵심 로직을 변경하지 않고도 로직 블록이 서로 다른 테이블에서 작동할 수 있도록 하기 위해서입니다. 커넥터가 한 번 구성되면 tableId와 접두사만 지정하면 되며, 동일한 로직 블록을 여러 곳에서 재사용할 수 있습니다.

저에게 있어 목표는 단순히 ID를 생성하는 것이 아니라, ID 형식 자체가 순차 지정 방식을 정의하는 재사용 가능한 패턴을 만드는 것이었습니다. 이것이 바로 로직을 단순하고 예측 가능하며, 여러 앱에서 쉽게 재사용할 수 있게 해주는 비결입니다.

이 로직 블록의 기능

이 로직 블록은 다음 구조에 따라 매년 재설정되는 순차적 ID를 생성합니다:접두사 + 연도 + 순차 번호

예시: TEST20240001, TEST20240002

연도가 바뀌면 번호 매기기가 자동으로 1부터 다시 시작됩니다: TEST20250001

동일한 테이블에 여러 개의 접두사가 존재할 수 있습니다. 각 접두사는 자체적인 독립적인 순서를 유지합니다: ORD20240001, ORD20240002, INV20240001, INV20240002

이 로직 블록은 다음을 보장합니다: * 일관된 ID 형식 * 연간 자동 재설정 * 접두사별 독립적인 번호 매기기 * 형식이 잘못된 과거 ID의 조기 탐지 * 숫자 오버플로우의 조기 탐지

커넥터가 설계에 포함된 이유

다음 ID를 생성하기 전에, 로직 블록은 주어진 접두사에 대한 가장 최근의 기존 ID가 필요합니다. 커넥터는 필터링된 조회를 수행합니다: * ID가 해당 접두사로 시작하는 레코드를 필터링 * _sequenceNumber 기준 내림차순 정렬 * 가장 최근 레코드 반환

접두사가 필터 조건의 일부이므로, 동일한 테이블 내에서도 각 접두사마다 고유한 누적 카운터가 유지됩니다. 이를 통해 시퀀스가 분리되고 예측 가능하게 관리됩니다.

빌드 구조

실제 구현에는 세 개의 트리거가 사용됩니다. 이러한 구조는 의도된 것입니다. 주요 로직을 분리하고 재사용 가능하게 유지하면서도, 로직 블록을 위에서 아래로 쉽게 따라갈 수 있도록 하고 싶었습니다. 따라서 로직을 여러 개의 편집 가능한 트리거에 분산시키는 대신, 다음 세 단계로 구성했습니다:1. 사용자 구성: 입력 단계 2. MAGIC 유효성 검사 + ID 생성 3. 사용자 구성: 출력 단계

이를 통해 사용 편의성과 제어력 사이에서 적절한 균형을 이룹니다. * 첫 번째 트리거에서는 입력값을 정의합니다. * 두 번째 트리거에는 로직 블록이 작동하는 데 일반적으로 편집할 필요가 없는 내부 로직이 포함되어 있습니다. * 세 번째 트리거에서는 생성된 결과로 무엇을 할지 결정합니다.

즉, 일반적으로 핵심 로직 트리거 내부에서 작업할 필요가 없습니다. 사용자는 입력 측과 출력 측만 구성하면 됩니다. 이것이 핵심 설계 결정 사항 중 하나였습니다. 즉, 일반적으로 변경이 필요한 부분만 노출함으로써 로직 블록을 재사용 가능하게 만드는 것이었습니다.

트리거 1 – 사용자 구성: 입력 단계

이 트리거는 사용자가 가장 먼저 상호작용하게 되는 트리거입니다. 이 트리거의 목적은 ID가 생성되기 전에 로직 블록에 필요한 입력 값을 정의하는 것입니다. 실제로 이 트리거는 다음을 정의하는 데 사용됩니다:* 접두사: _configPrefix* ID 길이: _configIdNumberFormat* 커넥터로 전달되는 테이블 ID: tableId

각 값의 의미

_configPrefix: 생성된 모든 ID의 맨 앞에 삽입되는 텍스트입니다. 이를 사용하여 생성할 시퀀스를 정의합니다.

예시:* ORD* INV* TEST

_configPrefix가 ORD인 경우, 로직 블록은 ORD로 시작하는 기존 ID만 확인하고 해당 시퀀스만 이어갑니다. 따라서 이 값은 다음 두 가지 역할을 동시에 수행합니다:* 최종 ID에 표시될 접두사를 정의합니다* 커넥터가 다음 번호를 생성할 때 소스로 사용할 기존 ID를 정의합니다

즉, 동일한 테이블 내에서도 접두사가 다르면 서로 다른 시퀀스가 생성됩니다**._configIdNumberFormat**

이 설정은 ID의 숫자 부분 길이를 정의합니다. 0으로 채워진 문자열로 설정합니다. 예시:000000000000000000

0의 개수는 숫자 부분의 너비를 정의합니다.

예시:0000 → 0001, 0002, 0003 ... 9999 000000 → 000001, 000002 ... 999999

이 값은 실제 숫자를 설정하는 것이 아닙니다. 숫자가 맞춰야 할 형식을 정의합니다. 저는 이 값을 두 가지 목적으로 사용합니다: * 생성된 숫자에 선행 0을 추가하기 위해 * 다음 숫자가 허용된 길이에 여전히 맞는지 확인하기 위해

tableId

이 값은 커넥터가 쿼리해야 할 테이블을 정의합니다.

실제로 이 설정 덕분에 로직 블록을 서로 다른 테이블에서 재사용할 수 있습니다. 동일한 로직 블록을 복사한 후, 구성 트리거에서 이 값만 변경하여 다른 테이블을 지정할 수 있습니다.

로직 블록은 자체적으로 테이블을 검색하지 않습니다. tableId 와 _configPrefix를 커넥터에 전달하면, 커넥터가 해당 테이블에서 일치하는 최신 ID를 반환합니다.

이들을 함께 사용하는 방법

이 세 가지 값은 함께 제너레이터의 동작을 정의합니다:* tableId는 로직 블록이 어디를 조회해야 하는지 알려줍니다* _configPrefix는 어떤 시퀀스를 이어가야 하는지 알려줍니다* _configIdNumberFormat은 숫자 부분이 어떻게 표시되어야 하는지 알려줍니다

실용적인 설정 지침

로직 블록을 구성할 때는 다음 사항을 확인하십시오:* tableId가 올바른 테이블을 가리키는지* _configPrefix가 계속 이어갈 접두사와 일치하는지* _configIdNumberFormat이 적용하려는 숫자 길이와 일치하는지

접두사를 변경하면 더 이상 기존 시퀀스를 이어가지 않게 됩니다. 대신 다른 접두사별 시퀀스를 시작하거나 이어가게 됩니다. 나중에 숫자 형식 길이를 늘리면, 로직 블록은 해당 테이블 및 접두사 범위 내에서 기존 ID를 검증할 때 더 넓은 형식을 기대하게 됩니다.커넥터는 접두사와 일치하는 최신 ID를 가져와 _stateLastId에 저장합니다. 아직 ID가 존재하지 않는 경우, LINK() 는 생성기가 여전히 첫 번째 유효한 ID를 생성할 수 있도록 보장합니다.

커넥터가 설계의 일부인 이유

커넥터는 단순한 기술적 세부 사항이 아닙니다. 이는 재사용 전략의 일부입니다. 저는 커넥터를 사용하여 대상 테이블에서 가장 최근의 기존 ID를 읽어옵니다. 커넥터는 테이블 ID를 입력으로 받아 접두사 필터를 적용하고, 레코드를 _sequenceNumber 기준 내림차순으로 정렬한 후, 가장 최근에 일치하는 레코드를 반환합니다.

이는 두 가지 이유로 중요합니다.

첫째, 이를 통해 로직 블록이 테이블의 실제 상태에서 번호 매기기를 계속할 수 있습니다.

둘째, 이를 통해 로직 블록을 훨씬 쉽게 재사용할 수 있습니다. 버튼을 다른 앱으로 복사하더라도 로직을 다시 작성할 필요가 없습니다. 커넥터를 올바른 테이블로 지정하고 필요한 구성을 제공하기만 하면 됩니다. 이것이 빌드 뒤에 숨겨진 실용적인 패턴입니다: * 버튼을 한 번만 생성 * 커넥터에서 테이블 입력 설정 * 접두사 및 번호 형식 정의 * 필요한 곳 어디에서나 재사용

이는 앱 구축 속도를 높이기 위해 의도적으로 선택한 방식입니다.

로직 블록에서 커넥터는 어떤 역할을 할까요?

여기서 일어나는 과정은 다음과 같습니다:* 커넥터가 테이블 ID를 수신합니다* 커넥터가 접두사를 수신합니다* 커넥터가 접두사를 기준으로 레코드를 필터링합니다* 커넥터가 _sequenceNumber를 기준으로 레코드를 내림차순으로 정렬합니다* 커넥터가 일치하는 최신 ID를 반환합니다

커넥터는 또한 동일한 테이블 내의 여러 엔티티와 같은 매우 중요한 사용 사례도 지원합니다.

동일한 테이블에 다음과 같은 레코드가 포함되어 있다면: ORD20240001 MAT20240011

와 같은 레코드가 있다면, 로직 블록은 이를 하나의 공유 시퀀스로 취급해서는 안 됩니다. 각 접두사는 오직 해당 접두사의 최신 값부터 이어져야 합니다.

따라서 커넥터는 먼저 접두사를 기준으로 필터링합니다. 즉, 다음 값은 다음과 같이 됩니다: ORD → ORD20240002, MAT → MAT20240012

제가 이 모델을 선택한 이유는 서로 다른 엔티티가 같은 테이블에 존재할 수는 있지만, 그렇다고 해서 동일한 순차 번호를 공유해야 한다는 의미는 아니기 때문입니다.

설정 시 주의해야 할 사항 중 하나를 명확히 밝힐 필요가 있습니다. 커넥터에는 인증이 필요하므로, 토큰을 생성하여 커넥터 인증 설정에 추가해야 합니다. 저는 이를 로직 블록 자체의 논리보다는 설정 작업으로 간주하지만, 로직 블록을 실제로 사용할 수 있게 하는 데 있어 여전히 중요한 부분입니다.

트리거 2 – MAGIC: 유효성 검사 + ID 생성

이 트리거는 로직 블록의 핵심 로직입니다. 이 트리거는 다음 세 가지 작업을 순서대로 수행합니다. 1. 가장 최근의 일치하는 ID가 예상된 구조를 갖는지 확인합니다. 2. 다음 번호가 구성된 숫자 길이에 여전히 맞는지 확인합니다. 3. 다음 ID를 생성합니다.

이 단계들은 동일한 결정 흐름에 속하므로 하나의 트리거로 묶었습니다. 새로운 ID를 생성하기 전에 다음 세 가지 질문에 답하고자 합니다: * 이전 ID의 구조가 사용하기에 안전한가? * 다음 숫자가 여전히 형식에 맞을 것인가? * 그렇다면, 다음 ID는 무엇이어야 하는가?

형식 유효성 검사

Expression

REGEX_REPLACE(LINK(Variable._stateLastId.id, Variable._configPrefix + DATETIMETOTEXT(App info.Current Date and Time,'YYYY') + Variable._configIdNumberFormat),'^' + Variable._configPrefix + '[0-9]{4}' + '[0-9]{' + LEN(Variable._configIdNumberFormat) + '}$','ok')

이 expression 의 기능

이 expression 는 최신 ID가 로직 블록이 기대하는 정확한 구조와 일치하는지 확인합니다. 작동 순서는 다음과 같습니다. 1. 커넥터가 값을 반환하면 LINK(...)는 Variable._stateLastId.id를 가져옵니다. 2. 아직 ID가 존재하지 않는 경우, LINK(...)는 다음으로 구성된 대체 값을 사용합니다: * Variable._configPrefix * DATETIMETOTEXT(...,'YYYY') * Variable._configIdNumberFormat3. 이 대체 값은 처음 생성된 ID일 때에도 유효성 검사가 평가할 수 있는 유효한 구조를 갖도록 포함됩니다.4. Variable._configPrefix는 ID가 반드시 시작해야 하는 정확한 접두사를 정의합니다.5. DATETIMETOTEXT(...,'YYYY') 는 정규식 내부에서 일치 값으로 사용되지는 않지만, 대체 값 구조의 일부이므로 대체 값이 실제 ID 형식을 갖도록 합니다.6. LEN(Variable._configIdNumberFormat) 은 숫자 부분이 포함해야 하는 자릿수를 정의합니다.7. REGEX_REPLACE(...) 는 전체 문자열을 다음 패턴에 따라 검사합니다: * 접두사 * 연도를 나타내는 정확히 4자리 숫자 * 숫자 부분을 나타내는 정확히 N자리 숫자8. 전체 문자열이 패턴과 일치하면, 전체 값이 ‘ok’로 대체됩니다.9. 일치하지 않으면 원래 값은 변경되지 않습니다.10. 그런 다음 트리거는 결과가 ‘ok’와 동일한지 확인합니다. 그렇지 않으면 실행이 중지됩니다.

따라서 이 expression 는 계산을 위한 값을 추출하는 것이 아닙니다. 이 트리거의 역할은 수치 연산이 적용되기 전에 ID가 예상된 구조를 갖는지 확인하는 것입니다.

이 방식을 선택한 이유

수치 연산을 수행하기 전에 전체 ID 구조를 검증하기로 했습니다. 트리거의 나머지 부분이 다음과 같은 고정된 위치를 가정하기 때문에 이렇게 구축했습니다:* 시작 부분의 접두사* 접두사 바로 뒤의 연도* 연도 바로 뒤의 숫자

이전 ID가 이러한 규칙을 따르지 않는다면, 이를 기준으로 ID를 증가시키는 것은 신뢰할 수 없게 됩니다.

또한, 처음 생성된 ID에 별도의 유효성 검사 로직이 필요하지 않도록 여기에서 LINK(...) 대체 처리를 포함하기로 했습니다. 이전 ID가 존재하든 없든 동일한 유효성 검사 경로가 작동합니다. 저는 형식이 잘못된 ID를 수정하려고 시도하기보다는 의도적으로 트리거를 중지합니다. 자동 수정은 데이터 문제를 은폐할 수 있으며, 겉보기에는 유효해 보이지만 잘못된 입력을 기반으로 생성된 시퀀스를 만들 수 있습니다.

오버플로우 방지

Expression

LEN(IF(MID(LINK(Variable._stateLastId.id, Variable._configPrefix + Variable._configIdNumberFormat), LEN(Variable._configPrefix), 4) = DATETIMETOTEXT(App info.Current Date and Time,'YYYY'),RIGHT(Variable._configIdNumberFormat+ TOTEXT(TEXTTOINTEGER(REGEX_REPLACE(LINK(Variable._stateLastId.id, Variable._configPrefix + Variable._configIdNumberFormat),'^' + Variable._configPrefix + '[0-9]{4}','')) + 1), LEN(Variable._configIdNumberFormat)), RIGHT(Variable._configIdNumberFormat + '1', LEN(Variable._configIdNumberFormat))))

expression 의 기능

이 expression 는 다음 숫자 부분이 어떻게 될지 계산한 다음 그 길이를 측정합니다. 작동 순서는 다음과 같습니다. 1. LINK(...)는 마지막 ID가 존재할 경우 이를 사용합니다. 존재하지 않으면 Variable._configPrefix + Variable._configIdNumberFormat으로 대체합니다. 2. MID(..., LEN(Variable._configPrefix), 4)는 접두사 바로 뒤의 4자리를 읽어옵니다. 이 부분은 이전 ID의 연도 부분으로 간주됩니다. 3. DATETIMETOTEXT(...,'YYYY') 는 비교를 위해 현재 연도를 제공합니다. 4. IF(...)는 숫자 부분이 계속 이어져야 할지, 아니면 재설정되어야 할지 결정합니다: * 같은 연도 → 증가 * 다른 연도 → 15부터 시작. 증분 분기에서는 REGEX_REPLACE(...) 가 이전 ID의 시작 부분에서 접두사와 4자리 연도를 제거하여 숫자 부분만 남게 합니다.6. TEXTTOINTEGER(...) + 1은 해당 숫자 텍스트를 숫자로 변환하고 1을 더합니다.7. TOTEXT(...)는 새로운 숫자를 다시 텍스트로 변환합니다.8. Variable._configIdNumberFormat + ...는 구성된 0-포맷을 값 앞에 추가합니다.9. RIGHT(..., LEN(Variable._configIdNumberFormat))는 필요한 자릿수만 유지합니다.10. 재설정 분기에서는 RIGHT(Variable._configIdNumberFormat + '1', LEN(...)) 이 새 연도에 허용되는 첫 번째 숫자를 생성합니다.11. LEN(...) 은 결과 숫자 부분의 길이를 측정합니다.

트리거는 이 길이를 Variable._configIdNumberFormat에서 허용된 길이와 비교합니다. 다음 숫자 부분이 너무 길어질 경우, 실행이 중지됩니다.

이 방법을 선택한 이유

번호가 허용 길이를 초과할 시점을 추측하기 위해 별도의 수식을 사용하는 대신, ID가 실제로 생성되는 방식과 동일한 방식으로 다음 번호를 계산하기로 했습니다.

오버플로우 검사가 실제 ID 생성 규칙과 정확히 동일하게 따르기를 원했기 때문에 이러한 방식으로 구축했습니다. 이렇게 하면 나중에 유효성 검사 로직과 생성 로직이 서로 어긋날 가능성을 줄일 수 있습니다.

이 단계에서 중단하는 것이 계속 진행하는 것보다 안전합니다. 다음 숫자 값이 설정된 길이에 더 이상 맞지 않는다면, 생성된 ID는 사용자가 설정한 구조를 위반하게 될 것입니다.

예를 들어, 숫자 형식이 0000인 경우 9999는 유효하지만 10000은 유효하지 않습니다. 저는 이 논리 블록이 레코드 생성 후가 아니라 생성 전에 이를 감지하기를 원합니다.

ID 생성 로직

Expression

Variable._configPrefix + DATETIMETOTEXT(App info.Current Date and Time,'YYYY')+ IF(MID(LINK(Variable._stateLastId.id, Variable._configPrefix + Variable._configIdNumberFormat),LEN(Variable._configPrefix),4) = DATETIMETOTEXT(App info.Current Date and Time,'YYYY'),RIGHT(Variable._configIdNumberFormat+ TOTEXT(TEXTTOINTEGER(REGEX_REPLACE(LINK(Variable._stateLastId.id, Variable._configPrefix + Variable._configIdNumberFormat),'^' + Variable._configPrefix + '[0-9]{4}','')) + 1), LEN(Variable._configIdNumberFormat)), RIGHT(Variable._configIdNumberFormat + '1', LEN(Variable._configIdNumberFormat)))

expression 의 기능

이 expression 는 최종 ID를 생성합니다. 작동 순서는 다음과 같습니다. 1. Variable._configPrefix는 ID의 시작 부분에 구성된 접두사를 추가합니다. 2. DATETIMETOTEXT(App info.Current Date and Time,'YYYY') 는 현재 연도를 4자리 숫자로 추가합니다. 3. LINK(...)는 커넥터가 반환한 마지막 ID가 있는 경우 이를 사용합니다. 커넥터가 ID를 반환하지 않으면 Variable._configPrefix + Variable._configIdNumberFormat을 대체 구조로 사용합니다.4. MID(..., LEN(Variable._configPrefix), 4)는 접두사 바로 뒤의 4자리를 읽어옵니다. 이 4자리는 이전 ID의 연도 부분으로 간주됩니다.5. 여기서 다시 DATETIMETOTEXT(...,'YYYY') 를 사용하여, expression 가 이전 ID가 현재 연도에 속하는지 여부를 판단할 수 있게 합니다.6. IF(...) 는 다음 두 가지 가능한 경로를 제어합니다: * 같은 연도 → 번호 매기기 계속 * 다른 연도 → 1로 재설정7. 동일 연도 분기에서는 REGEX_REPLACE(...) 가 이전 ID의 시작 부분에서 접두사와 4자리 연도를 제거하여 숫자 부분만 남게 합니다.8. TEXTTOINTEGER(...) + 1 **은 해당 숫자 값에 1을 더합니다.9. TOTEXT(...) 는 더해진 값을 다시 텍스트로 변환합니다.10. Variable._configIdNumberFormat + ...는 구성된 0-포맷을 새 값 앞에 추가합니다.11. RIGHT (..., LEN(Variable._configIdNumberFormat)) 는 필요한 자릿수만 유지하므로 숫자 부분은 항상 고정된 길이를 갖습니다.12. 재설정 분기에서는 RIGHT (Variable._configIdNumberFormat + '1', LEN(...))**가 새로운 연도 순서의 첫 번째 숫자를 생성합니다.13. 접두사, 현재 연도 및 서식 처리된 숫자가 결합되어 최종 ID가 생성됩니다.

따라서 최종 출력은 항상 다음과 같은 구조를 갖습니다:접두사 + 연도 + 고정 길이 숫자

이 방식을 선택한 이유

다음 ID를 테이블에 있는 가장 최근의 실제 ID에서 전적으로 도출하도록 선택했습니다. 이전 ID에는 이미 로직에 필요한 모든 정보가 포함되어 있기 때문에 이러한 방식으로 구축했습니다:* 해당 시퀀스가 속한 접두사* 해당 연도* 마지막 숫자 값

즉, 별도의 카운터 테이블이나 저장된 연도 필드, 또는 정기적인 연간 초기화 작업이 필요하지 않습니다.

또한 구조를 예측 가능하게 유지하고 유효성 검증을 더 쉽게 할 수 있도록 고정 길이 형식을 선택했습니다.

대신, 이 expression 는 엄격한 ID 구조에 의존해야 한다는 단점이 있습니다. 그렇기 때문에 유효성 검사 단계가 먼저 이루어집니다. 다양한 느슨한 입력 형식을 지원하는 것보다 엄격하고 가독성 높은 계약이 이 경우 더 유용하기 때문에 저는 이러한 타협점을 수용했습니다.

트리거 3 – 사용자 구성: 출력 단계

이것은 로직 블록의 마지막 트리거입니다. 그 목적은 _stateOutput에 유효한 값이 포함되면 생성된 ID에 대해 어떤 처리가 이루어져야 하는지를 정의하는 것입니다.

여기서 중요한 점은 이 단계가 의도적으로 사용자에게 맡겨져 있다는 것입니다.

_stateOutput이 비어 있지 않다면, 로직 블록이 다음에 무엇을 수행할지 결정할 수 있습니다. 현재 설정에서 이 트리거는 다음 단계를 설명하는 안내 메시지를 표시합니다: * 구성된 테이블을 앱에 추가 * 메시지 단계를 ‘레코드 생성(Create Record)’ 트리거로 대체 * _stateOutput을 새 레코드 ID로 사용

사용 사례에 따라 출력 동작이 달라질 수 있으므로 이렇게 구성했습니다.

다음과 같은 작업을 원할 수 있습니다:* 즉시 레코드를 생성하기* 먼저 ID를 다른 변수에 저장하기* 더 긴 워크플로우 내에서 ID 사용하기* 테이블에 기록하기 전에 추가 조건 검증하기

단일한 고정된 출력 동작을 강제로 적용하는 대신, 출력 단계를 구성 가능하게 유지했습니다.

이것이 바로 로직 블록의 양쪽 끝에 사용자용 구성 옵션이 존재하는 이유입니다:* 입력 구조는 구성 가능* 출력 동작은 구성 가능* 핵심 로직은 중간에 위치

변수 명명 방식

내부 변수에는 언더스코어 접두사를 사용합니다:* _configPrefix* _configIdNumberFormat* _stateLastId* _stateOutput

이를 통해 구성 값과 내부 처리 변수를 빠르게 구별할 수 있습니다.

설계 경계

로직 블록은 다음과 같은 구조를 가정합니다:접두사 + 연도 + 숫자. 각 접두사는 자체적인 독립적인 순서를 유지합니다.

로직 블록은 여러 접두사에 걸쳐 하나의 공유 카운터를 지원하지 않습니다.

ID 내에서 연도 또는 숫자 부분이 이동되는 경우, expressions도 그에 따라 조정되어야 합니다.

구축 결정 사항 요약

전체 로직 블록을 그 이면에 있는 핵심 결정 사항으로 요약하면 다음과 같습니다. * 빠른 재사용을 원했기 때문에 로직 블록은 구성 기반입니다. * 테이블이 신뢰할 수 있는 정보의 원천이 되기를 원했기 때문에, 다음 ID는 항상 최신 실제 레코드를 기반으로 합니다. * 로직의 유지보수성을 확보하고자 했으므로, 계산은 한 곳에 중앙 집중화되었습니다.* 하나의 테이블 내 여러 엔티티가 원활하게 작동하기를 원했으므로, 각 접두사마다 독립적인 시퀀스를 갖습니다.* ID 구조가 시간이 지나도 일관성을 유지하기를 원했으므로, 연도가 ID의 일부이며 연도가 변경되면 시퀀스가 자동으로 재설정됩니다.* 테이블이 잘못된 패턴으로부터 보호되기를 원했기 때문에, 레코드가 생성되기 전에 형식 유효성 검사 및 오버플로 검사를 통해 잘못된 ID를 차단합니다.* 트리거 흐름이 가독성을 유지하기를 원했기 때문에, 역할을 구성, 유효성 검사, 생성, 출력이라는 명확한 단계로 분리했습니다.

이것이 바로 로직 블록이 현재와 같은 형태를 띠게 된 이유입니다. 이는 단순한 ID 생성기가 아닙니다. ID 구조에 연도별 분할을 직접 내장하면서, 단순성, 재사용성, 데이터 보호 간의 균형을 맞추려는 제어된 ID 생성을 위한 재사용 가능한 패턴입니다.

참여하기

커뮤니티에 참여하여 개선 사항을 공유하고, 추가 단위를 제안하며, 문제를 보고하거나 아키텍처 결정 사항에 대해 논의해 보세요.