Changes in version 0.3.1 This is a patch release. It fixes the static-survey to Google Sheets to R collection loop, repairs a serialisation defect, and improves the first-time user experience. There are no new exported functions, no new statistical methods, and no new bundled datasets. Bug fixes Data collection round-trip - export_static_survey() now renders the header logo and institution name from render$header, so exported surveys match the Shiny renderer and the builder preview. - export_static_survey() now falls back to the instrument's render$google_sheets_endpoint when endpoint_url is not supplied, so a Google Sheets endpoint set in the builder is honoured on export. - The static survey now posts the respondent identifier under the column name respondent_id, matching the Google Apps Script collector and read_responses(). The collection round-trip now preserves the identifier. - export_google_sheet() now includes matrix sub-item columns (item_id__sub) in the Apps Script header row, so matrix answers are stored in the Sheet. - read_sheet_responses() now declares started_at as a meta column and no longer raises a warning on every read. - Survey logos now keep their original MIME type (image/png, image/jpeg, image/gif), so JPEG and GIF logos display correctly in the builder, the Shiny renderer, and the static export. Serialisation - write_sframe() now strips list-level names from the item, choice, scale, branching, check, and model collections before serialisation. Instruments built with Map() or other helpers that attach element names (for example, using item IDs as names) previously serialised those collections as keyed JSON objects rather than arrays. This produced a hash mismatch and an integrity error on read_sframe(). Saved instruments now round-trip correctly regardless of how the component lists were constructed. User experience - Every exported function that takes an instrument now reports a clear, actionable message when passed something that is not an sframe object. The message points the user to sf_instrument() and read_sframe() instead of showing a raw inherits() assertion failure. - reliability_report() no longer prints psych internal warnings to the console. McDonald's omega is skipped silently for scales with fewer than three items, where the statistic is not meaningful. - The error message from run_analysis_plan() when no analysis plan is present now describes both the programmatic route (instrument$analysis_plan) and the visual SurveyBuilder route. Documentation - Rewrote the main vignette (surveyframe.Rmd) as an end-to-end worked example: design the questionnaire, export it as a hosted survey with a Google Sheets backend, collect responses, score them, run the analysis plan, and render a report. The results section uses simulated responses so the vignette builds offline; a single read_sheet_responses() call connects the same workflow to live responses. The questionnaire and concept are adopted from Sharafuddin, Madhavan, and Wangtueai (2024, Administrative Sciences, 14(11), 273, doi:10.3390/admsci14110273), with generic destination wording so the example transfers to any tourism services context. - Updated the supporting vignettes to reflect the research-design-first workflow where the instrument holds the questions, the analysis plan, and the measurement model. - sf_instrument() examples now include a complete analysis_plan block. - The README now leads with install.packages("surveyframe"), adds a short path for users who already have a response CSV, and points to browseVignettes("surveyframe"). Changes in version 0.3.0 (2026-05-27) New features Analysis planning, survey statistics, and model syntax - Added a role-based analysis-plan structure while preserving old variables/test analysis blocks. New plans can store family, method, roles, options, hypotheses, decision_rule, reporting_references, status, and requires_data. - Added common survey analysis helpers: descriptives_report(), missing_data_report(), assumption_report(), posthoc_report(), validity_report(), and sample_size_plan(). - Expanded run_analysis_plan() to dispatch the v0.3 method registry, including descriptives, missing data, sparse-table tests, related-sample tests, Kendall and partial correlations, two-way ANOVA, ANCOVA, repeated ANOVA, ordinal and multinomial logistic regression, mediation, moderation, and model-syntax output. - Added a model specification layer: sf_construct(), sf_path(), sf_covariance(), sf_indirect(), sf_model(), validate_model(), model_json(), add_model(), efa_solution(), efa_syntax(), cfa_lavaan_syntax(), sem_lavaan_syntax(), seminr_syntax(), and model_report_template(). Syntax generation does not require lavaan or seminr. - cfa_syntax() remains available as a backward-compatible wrapper around cfa_lavaan_syntax(). - SurveyBuilder Analyse mode now uses a three-panel Plan/Run/Report workspace with variable metadata badges, role-based variable assignment, method options, output preview, reporting references, and a table-based model builder. Significance level is shown only for inferential methods. Static HTML survey export - Added export_static_survey(). This produces a single, self-contained HTML file that runs the survey in any modern browser without a Shiny server or an internet connection. All thirteen item types are fully rendered (Likert, single choice, multiple choice, matrix, numeric, text, long text, date, slider, rating, ranking, section break, text block). Branching logic, required-field validation, a progress bar, welcome and thank-you pages are all handled in client-side JavaScript. On submission the browser downloads a per-respondent CSV file. An optional endpoint_url argument adds a parallel JSON POST to any serverless endpoint (Google Apps Script, Netlify function, etc.). The exported file is suitable for hosting on GitHub Pages, Netlify, or any static file server, and can also be shared directly as an e-mail attachment and opened from disk. The SHA-256 hash written into .sframe files by write_sframe() and by the SurveyBuilder HTML is computed using the same canonicalisation algorithm, so instruments round-trip correctly between the browser and R. Interactive response dashboard - Added launch_dashboard(). Opens a five-panel Shiny dashboard for exploring collected response data alongside the instrument definition, without modifying either. The panels are: | Panel | Content | |---|---| | Overview | Response count, date range, instrument metadata | | Items | Per-item bar charts, histograms, and frequency tables | | Scales | Scale score distributions with mean overlay | | Quality | Attention-check pass rates | | Raw data | Scrollable response table with CSV download | When called without arguments the dashboard loads the bundled tourism services demo. When called with a user-supplied instrument and no responses argument, it opens in metadata-only mode showing instrument structure. - Added sframe_demo_data(), sframe_input_types_demo_data(), launch_builder_demo(), launch_studio_demo(), and launch_dashboard_demo() for CRAN-safe examples, training, and local GUI testing. - Added a bundled input-types demo instrument and simulated response dataset for testing SurveyBuilder, SurveyStudio, the dashboard, and all supported item controls. - launch_studio() now accepts preloaded instruments, response data frames, CSV response paths, initial screen selection, host, port, and browser control. SurveyStudio reads these preloaded values during startup. Shiny survey module - Added survey_module_ui() and survey_module_server(). These allow a survey to be embedded inside a larger Shiny application as a first-class module. survey_module_server() returns a reactive that holds NULL until the form is submitted, then returns the response as a named list keyed by item ID. ui <- fluidPage(survey_module_ui("s1")) server <- function(input, output, session) { resp <- survey_module_server("s1", instrument = instr) observeEvent(resp(), { saveRDS(resp(), "response.rds") }) } An optional on_submit callback fires immediately on submission, before any observeEvent() elsewhere in the app. Extended analysis plan tests run_analysis_plan() now implements four additional tests used by the SurveyBuilder's test dropdown: - anova_one: One-way ANOVA with eta-squared effect size. When the result is significant and there are more than two groups, Tukey HSD post-hoc output is included in the result object. - t_test_pair: Paired-samples t-test with Cohen's d_z. - wilcoxon_pair: Wilcoxon signed-rank test with r effect size. - regression_logistic_binary: Binary logistic regression with McFadden R-squared and an overall model chi-square test. The full coefficient table is returned for interpretation. All four runners produce an APA-formatted summary string and an interpretation prompt field to guide write-up. Bug fixes - write_sframe() validates the instrument and writes the validated object, preserving meta$validated = TRUE in the saved .sframe file. - .sframe serialisation now includes a models field and continues to read older .sframe files where models is absent. - read_responses() no longer requires display-only items such as section_break and text_block to appear as response columns. - validate_sframe() now checks model references, analysis-plan roles, invalid model IDs, duplicate model IDs, and model indicator/path integrity. - The package title and description were tightened for CRAN submission and avoid overclaiming. - launch_builder(open = TRUE) opens the SurveyBuilder HTML in the system's default browser via utils::browseURL(). - R/studio_builder.R contains three fully implemented internal functions (sframe_builder_empty_state, sframe_builder_state_from_instrument, sframe_builder_validate_draft) used by SurveyStudio startup and draft validation. - SHA-256 hashing in the SurveyBuilder HTML includes a pure-JavaScript fallback for environments where crypto.subtle is unavailable on file:// origins, including common Firefox file:// configurations. Saving a .sframe file from the builder now always succeeds. - The SurveyBuilder's rqSuggest box now appears with an icon and a plain-language recommendation when two or more variables are selected in the RQ modal. - The undo and redo buttons in the SurveyBuilder topbar are now correctly disabled when their respective history stacks are empty. Security hardening - export_google_sheet() now writes Google Apps Script using JSON-encoded JavaScript literals instead of interpolating instrument metadata directly into executable code. The generated endpoint also rejects missing, over-large, and non-object JSON POST bodies. - SurveyStudio upload handlers now validate uploaded .sframe and .csv files by extension, size, and text-content checks before passing them to import functions. - read_sframe() now validates the top-level .sframe payload structure before hash verification and object reconstruction. - Internal HTML report generation now applies escaping consistently to report titles, instrument metadata, citations, and effect labels. - Quarto report rendering now cleans temporary render directories and RDS files with on.exit() even when rendering fails. Documentation - validate_sframe(), score_scales(), codebook_report(), cfa_syntax(), and launch_builder(open = FALSE) have fully runnable examples. - Reworked the vignette set into a coherent workflow covering instrument building, response analysis, reliability and validity, EFA/CFA/SEM/PLS syntax generation, and GUI usage. - Added cran-comments.md with platform list, dependency justification, bundled-asset description, and a \dontrun{} use justification table. - launch_builder_demo() now injects the demo instrument JSON directly into a temporary copy of survey_builder.html. The demo questions, scales, and analysis plan are visible immediately on launch — no manual Load .sframe step is needed. - launch_studio_demo() and launch_dashboard_demo() now pass launch.browser = TRUE so the browser always opens automatically. - inst/shiny/dashboard/app.R: replaced library(shiny) with a requireNamespace check and explicit shiny:: namespace prefixes for CRAN policy compliance. - db_quality_ui(): class = flag_class added to tags$tr() so quality rows are colour-coded by flag status. - db_data_ui(): download-button background colour now uses sprintf("...%s...", THEME) instead of background:var(--cp,#2563eb) so the button respects the active dashboard theme. - db_overview_ui(): date parsing is now delegated to dashboard_parse_date() for robust, error-free date display. - render_report() and render_results(): HTML report tables now use APA formatting — horizontal rules only, no vertical borders, no row shading. A significance footnote is appended automatically when a p-value column is detected. - demo/survey.R: complete UX rewrite with section headers, contextual pause prompts, "In the browser: ->" guidance, ask_yn() yes/no prompts, and a conversational mode for static survey export. All output is ASCII-safe. - dashboard_parse_date() completely rewritten. No longer throws Error in as.POSIXlt.character: character string is not in a standard unambiguous format. Now tries six explicit format templates in priority order (ISO 8601 Z-suffix, ISO 8601 no-tz, space datetime, date-only, UK dd/mm/yyyy, US mm/dd/yyyy) with tryCatch on each, plus a wrapped fallback. Non-matching strings return NA instead of an error. - Dashboard Items and Scales tabs: outputOptions(output, "item_chart", suspendWhenHidden = FALSE) and outputOptions(output, "scale_chart", suspendWhenHidden = FALSE) added. Response distribution and Scale score distribution charts now render as soon as the user switches to those tabs instead of appearing blank. Future direction: v0.4 - MCDM and DEMATEL fall outside v0.3 scope. Planned v0.4 work includes MCDM input fields, AHP pairwise-comparison matrices, DEMATEL direct influence matrices, TOPSIS/VIKOR/PROMETHEE/ELECTRE planning, MCDM data validation and consistency checks, DEMATEL thresholding and causal diagram export, advanced SEM and PLS-SEM execution, higher-order constructs, multi-group SEM planning, a diagram-based model builder, complex survey design weighting, JASP/jamovi-friendly exports, and report-writer integration after the data and model schemas stabilise. Changes in version 0.1.0 - Initial release. - Core S3 object system: sf_instrument(), sf_item(), sf_choices(), sf_scale(). - Serialisation: write_sframe(), read_sframe() with SHA-256 integrity checking. - Shiny survey renderer: render_survey(). - Static SurveyBuilder HTML: launch_builder(). - Response reader: read_responses().