로직 가이드
JavaScript logic은 통제된 DSL 위치에서만 실행됩니다. Survey Link, Workbench preview, Run generate, server persistence, Template Expression, redirect route evaluation은 같은 safe evaluator를 공유합니다.
| 위치 | 목적 | Mutation |
|---|---|---|
if | Question, option, attribute, group, screen-out, quota, jump, redirect route의 compact visibility/inclusion expression. | No |
<condition> | top-level final return이 있는 multi-line boolean condition. | No |
<run-code> | Flow-time answer mutation, auto-punching, diagnostics. | setAnswer, clearAnswer, question-object mutation method로 가능 |
<validation> | Question-local hard/soft validation. | Answer mutation 없음 |
<script> helper | 재사용 가능한 safe predicate/transform. | Answer mutation 없음 |
{{ ... }} Template Expression | 렌더링 시점 text, dynamic non-identity attribute, redirect route URL. | No |
런타임 helper 가용 범위
| Helper | Type | 사용 위치 | 메모 |
|---|---|---|---|
Luxon | DateTime, Duration, Interval namespace | Default survey logic context를 쓰는 모든 JS DSL/Template Expression context. | Date parsing/formatting에 사용합니다. |
$now | 현재 Luxon DateTime | if, <condition>, <run-code>, <validation>, Template Expression, redirect route if, redirect URL template. | $now는 저장 시점이 아니라 runtime 평가 시점 값입니다. |
$params | Survey Link URL parameter object | Survey Link runtime, server persistence, redirect route if, redirect URL template, Template Expression, 그리고 runtime context가 params를 제공하는 Run generate. | mode, isTestMode, vs-sys-*, redirectGroup 같은 system key는 제외됩니다. 중복 parameter는 string array입니다. |
$curr | 현재 question object | Question-local if, <condition>, <run-code>, <validation>, option if, attribute if, option/attribute group if. | 현재 평가 중인 문항을 가리킵니다. top-level share-list, screen-out, quota, jump, redirect scope에는 의도적으로 제공하지 않습니다. |
$quota | Read-only quota snapshot namespace | quota rule이 제공된 if, <condition>, <run-code>, <validation>, screen-out, quota, script-helper runtime context, Survey Link server persistence, Run generate. | Authored code가 database에 직접 접근하지 않고 저장된 quota cell과 현재 응답자의 assignment를 읽게 합니다. |
$status | Redirect terminal status object | Redirect route if 전용. | $status.complete, $status.screenout, $status.quotafull을 제공합니다. |
Question reference와 $curr
다른 문항에 의존하는 로직은 문항 이름을 직접 참조하고, 현재 문항에 속한 로직은 $curr를 사용합니다.
<question type="single" name="Q1">
<run-code>
if ($curr.o1 && $now.year >= 2026) {
setAnswer("SEGMENT", "qualified");
}
</run-code>
<options>
<option value="1">Qualified</option>
<option value="2" if="$curr.o1">Shown only after option 1</option>
</options>
</question>
<question type="text" name="FOLLOWUP" if="SEGMENT.value === 'qualified'">
<description>Follow-up for the qualified segment.</description>
</question>
$curr는 question-scoped입니다. 위 예시에서 runtime이 Q1을 처리하는 동안 $curr.o1은 Q1.o1을 의미합니다. 뒤 문항에서는 Q1.o1 또는 auto-punch된 SEGMENT answer를 명시적으로 참조해야 합니다.
$params와 Template Expression
URL parameter는 Survey Link가 reserved system key를 제거한 뒤 $params로 제공합니다.
<question type="text" name="SOURCE_LABEL" hidden>
<run-code>setAnswer("SOURCE_LABEL", String($params.source || "direct"));</run-code>
</question>
<question type="info" name="INTRO">
<description>Welcome, {{ $params.company || "respondent" }}.</description>
</question>
Template Expression은 read-only입니다. Answer, helper, Luxon, $now, runtime이 제공한 $params를 읽을 수 있지만 answer를 mutate할 수 없습니다.
Expression에서 script helper 사용
Survey HTML DSL의 <script> block은 제한된 top-level function을 if expression, Template Expression, <condition>, <run-code>, <validation>에 노출할 수 있습니다. Helper body는 safe helper sandbox를 통과해야 합니다.
<script name="helpers">
function answerConvert(value) {
return String(value || "").trim().toUpperCase();
}
</script>
<question type="single" name="FOLLOWUP" if="answerConvert(Q1.val()) === 'YES'">
<description>{{ answerConvert(Q1.val()) }} path follow-up</description>
</question>
Helper code는 pure하게 유지하세요. Answer mutation은 <run-code>에서 처리합니다.
$quota helper
$quota는 quota sheet/source id로 접근하는 dynamic read-only namespace입니다. Logic이 실행되는 시점의 persisted quota snapshot을 반영하며, authored code에 service-role database client를 노출하지 않습니다.
$quota.gender_quota.cells
$quota.gender_quota.get("r1")
$quota.gender_quota.getPriorityCells(1, "count")
$quota.gender_quota.getAssignmentCells()
Quota checkpoint 뒤의 hidden question에서 auto-punch할 때 사용할 수 있습니다.
<quota source="concept_quota" />
<question type="single" name="HQ_CONCEPT" hidden>
<run-code>
const ids = $quota.concept_quota.getAssignmentCells();
const first = ids.at(0);
if (first) {
setAnswer("HQ_CONCEPT", String(first).replace("r", ""));
}
</run-code>
<options>
<option value="1">Concept A</option>
<option value="2">Concept B</option>
</options>
</question>
Method contract는 문항 객체를 참고하세요.
Redirect route logic
Redirect route condition은 question visibility와 같은 expression evaluator를 사용하고 redirect 전용 $status helper가 추가됩니다. Route는 source order대로 평가되며 처음 true인 route가 선택됩니다. Route URL Template Expression은 최종 answer, $params, $now, safe helper를 읽을 수 있지만 최종 URL은 absolute http 또는 https여야 합니다.
<redirect>
<group name="partner" title="Partner" default>
<route url="https://example.com/done?source={{ $params.source }}&year={{ $now.year }}" if="$status.complete && Q1.o1" />
<route url="https://example.com/full" if="$status.quotafull" />
</group>
</redirect>
Redirect error는 의도적으로 blocking입니다. Invalid group selection, duplicate route condition, unsafe final URL, redirect Template Expression failure는 모호한 데이터를 저장하지 않도록 response persistence를 차단합니다.
Runtime error policy
- Save-time validation은 unsupported syntax와 unsafe reference를 persistence 전에 차단합니다.
- Runtime condition failure는 가능한 경우 fail-open으로 처리해 관련 없는 문항이 누락되지 않게 합니다.
- Redirect error는 예외입니다. Terminal redirect error는 progression과 persistence를 차단합니다.
- Run-code와 validation error는 catch되어 TEST diagnostics와 runtime console event로 보고됩니다.
- Run generate는 같은 helper surface를 사용하고 반복되는 expression/runtime diagnostics를 중복 제거합니다.