# Building a survey instrument

This vignette builds an `sframe` instrument from scratch and shows how choice sets, items, scales, reverse coding, attention checks, validation, and `.sframe` serialisation fit together.

## Choice sets

Choice sets define reusable response options. They are referenced by items through `choice_set`.

    agree5 <- sf_choices(
      id = "agree5",
      values = 1:5,
      labels = c(
        "Strongly disagree",
        "Disagree",
        "Neither agree nor disagree",
        "Agree",
        "Strongly agree"
      )
    )

    yes_no <- sf_choices(
      id = "yes_no",
      values = c("yes", "no"),
      labels = c("Yes", "No")
    )

## Items and item types

Items are response variables unless their type is `section_break` or `text_block`. Required items are marked with `required = TRUE`. Item IDs should be stable because response data columns use those IDs.

    intro <- sf_item(
      "intro",
      "Study introduction",
      type = "section_break",
      section_intro = "Please answer the following questions about the service."
    )

    visit_again <- sf_item(
      "visit_again",
      "Would you use this service again?",
      type = "single_choice",
      required = TRUE,
      choice_set = "yes_no"
    )

    sat_1 <- sf_item(
      "sat_1",
      "The service met my expectations.",
      type = "likert",
      required = TRUE,
      choice_set = "agree5",
      scale_id = "satisfaction"
    )

    sat_2 <- sf_item(
      "sat_2",
      "The service was easy to use.",
      type = "likert",
      required = TRUE,
      choice_set = "agree5",
      scale_id = "satisfaction"
    )

    sat_3 <- sf_item(
      "sat_3",
      "The service was frustrating to use.",
      type = "likert",
      required = TRUE,
      choice_set = "agree5",
      scale_id = "satisfaction",
      reverse = TRUE
    )

    age <- sf_item(
      "age",
      "Age in years",
      type = "numeric",
      required = FALSE
    )

    comments <- sf_item(
      "comments",
      "Any other comments?",
      type = "textarea",
      required = FALSE
    )

    attention <- sf_item(
      "attention",
      "For quality control, please select Agree.",
      type = "single_choice",
      required = TRUE,
      choice_set = "agree5"
    )

## Scales, reverse coding, and minimum valid items

Scale definitions record item membership, the scoring method, reverse-coded items, and the minimum number of valid items required to compute a score.

    satisfaction <- sf_scale(
      id = "satisfaction",
      label = "Satisfaction",
      items = c("sat_1", "sat_2", "sat_3"),
      method = "mean",
      min_valid = 2,
      reverse_items = "sat_3"
    )

## Attention checks

Checks keep quality-control logic with the instrument definition.

    attention_check <- sf_check(
      id = "attention_agree",
      item_id = "attention",
      type = "attention",
      pass_values = 4,
      fail_action = "flag",
      label = "Instructional attention check"
    )

## Assemble and validate the instrument

    instr <- sf_instrument(
      title = "Service Feedback Survey",
      version = "0.3.0",
      description = "Short example instrument for a service feedback study.",
      authors = "Research team",
      languages = "en",
      components = list(
        agree5, yes_no,
        intro, visit_again, sat_1, sat_2, sat_3, age, comments, attention,
        satisfaction, attention_check
      )
    )

    validation <- validate_sframe(instr, strict = FALSE)
    validation$valid
    #> [1] TRUE
    validation$problems
    #> character(0)

In production workflows, strict validation returns the validated instrument or stops with a structured error.

    instr <- validate_sframe(instr)
    instr$meta$validated
    #> [1] TRUE

## Write and read `.sframe` files

The `.sframe` file is the portable surveyframe instrument file. It is JSON based, keeps validated metadata, and can be loaded by R, SurveyBuilder, or SurveyStudio.

    path <- tempfile(fileext = ".sframe")
    write_sframe(instr, path, overwrite = TRUE)

    loaded <- read_sframe(path)
    inherits(loaded, "sframe")
    #> [1] TRUE
    loaded$meta$title
    #> [1] "Service Feedback Survey"

## GUI option

The same instrument can also be edited visually.

    launch_builder()
    launch_builder_demo(open = FALSE)