Skip to content

Surveys System - Create, Participate & Analyze Surveys#74

Open
ghanshyam2005singh wants to merge 3 commits into
alphaonelabs:mainfrom
ghanshyam2005singh:feat/survey-system
Open

Surveys System - Create, Participate & Analyze Surveys#74
ghanshyam2005singh wants to merge 3 commits into
alphaonelabs:mainfrom
ghanshyam2005singh:feat/survey-system

Conversation

@ghanshyam2005singh

@ghanshyam2005singh ghanshyam2005singh commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

This PR introduces a complete Surveys System that allows community members to create surveys, collect responses, and analyze results through an interactive dashboard.

Features

Survey Directory

  • Browse all public surveys
  • Search surveys
  • View question counts
  • Owner-specific actions

Survey Creation

  • Create surveys with multiple question types
  • Support for:
    • Multiple Choice
    • Checkbox
    • Text
    • True/False
    • Scale
  • Question validation
  • Public visibility controls

Survey Participation

  • Dynamic survey rendering
  • Required question validation
  • Progress tracking
  • Response submission workflow

Survey Results & Analytics

  • Participant statistics
  • Completion rate metrics
  • Engagement analytics
  • Question-level insights
  • Text response viewing
  • Automatic summary generation

Export Functionality

  • CSV export for survey responses
  • Response timestamps included

Database

Added migration:

  • migrations/0010_add_surveys.sql

New tables:

  • surveys
  • survey_questions
  • survey_options
  • survey_responses
  • survey_answers

All relationships use appropriate cascading deletes.

Backend

Added modular survey implementation:

  • src/surveys.py
  • src/api/surveys.py

New endpoints:

  • GET /api/surveys
  • POST /api/surveys
  • GET /api/surveys/:id
  • POST /api/surveys/:id/responses
  • GET /api/surveys/:id/results
  • GET /api/surveys/:id/export
  • DELETE /api/surveys/:id

Frontend

Added pages:

  • public/surveys.html
  • public/survey-create.html
  • public/survey.html
  • public/survey-results.html

Security

  • Authentication required for survey creation
  • Ownership validation for deletion
  • Response validation
  • Permission checks on protected actions

Testing

Added comprehensive API coverage for:

  • Survey creation
  • Validation rules
  • Permissions
  • Response submission
  • Analytics generation
  • Export functionality
  • Deletion workflows

Added an end-to-end Surveys system for browsing public surveys, creating surveys with validation, taking surveys with required-question enforcement and progress tracking, and viewing analytics/results with CSV export.

Key updates:

  • New frontend pages: surveys.html (searchable/paginated listing with owner actions + delete), survey-create.html (survey builder with multiple question types, drag-and-drop reordering, required flags, and local draft autosave), survey.html (dynamic survey rendering + required validation + duplicate-response handling), and survey-results.html (participant metrics, per-question insights/charts, text response viewing, and CSV export).
  • Backend: new /api/surveys endpoints for listing, creating, viewing, submitting responses, fetching results/analytics, exporting to CSV, and deleting surveys, with authentication/ownership/visibility checks and standardized error handling.
  • Core survey logic: validation of payloads and submitted answers (including option-based questions, checkbox multi-select, required fields, and scale/true-false constraints), duplicate submission prevention, analytics computation (completion/engagement metrics and question-level stats), and CSV generation with CSV-safety for exported content.
  • Data model: new database migration 0010_add_surveys.sql introducing surveys, survey_questions, survey_options, survey_responses, and survey_answers tables (with cascading deletes and supporting indexes).
  • Worker/router updated to expose the new survey API routes.
  • Added API test suite covering authz/authn, visibility rules, create/submit validation, duplicate submissions, analytics output shapes/metrics, deletion permissions, and CSV export behavior.

Impact:

  • Enables a complete survey authoring and participation workflow with owner-only management, rich result analytics, and downloadable exports.
  • Users can only take a given survey once (per authenticated user), with clear UI states for loading/error/empty/duplicate outcomes.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@ghanshyam2005singh, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 33 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository: alphaonelabs/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 01376259-72ce-4cb9-8c53-337db116f3b0

📥 Commits

Reviewing files that changed from the base of the PR and between 66deabf and f2ea4da.

📒 Files selected for processing (4)
  • public/survey-create.html
  • public/surveys.html
  • src/surveys.py
  • tests/test_api_surveys.py

Walkthrough

Adds a full survey system: backend survey storage and analytics, API handlers and routing, four client pages for creating, taking, listing, and reviewing surveys, navbar navigation updates, and API coverage tests.

Changes

Survey feature implementation

Layer / File(s) Summary
Survey core data logic
src/surveys.py
Implements shared helpers, validation, CRUD, analytics, deletion, and CSV export for surveys.
HTTP API handlers and worker routing
src/api/surveys.py, src/worker.py
Adds request handlers for surveys and wires the new routes into the worker dispatcher.
Backend API test suite
tests/test_api_surveys.py
Adds tests for survey creation, listing, retrieval, submission, results, deletion, and export handlers.
Survey creation page
public/survey-create.html
Adds the client-side survey builder, draft autosave, validation, and publish flow.
Survey-taking page
public/survey.html
Adds the survey form UI, answer tracking, progress updates, and response submission flow.
Survey results and analytics page
public/survey-results.html
Adds results fetching, chart rendering, summary analytics, and CSV export.
Survey listing page and navigation
public/surveys.html, public/partials/navbar.html
Adds searchable survey listing, delete confirmation, and navbar survey links.

Estimated code review effort: 4 (Complex) | ~75 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Worker
  participant SurveysAPI
  participant SurveysCore
  participant D1

  User->>Worker: Request /api/surveys/*
  Worker->>SurveysAPI: Dispatch api_* handler
  SurveysAPI->>SurveysCore: Call core survey function
  SurveysCore->>D1: Read or write survey data
  D1-->>SurveysCore: Rows or write result
  SurveysCore-->>SurveysAPI: JSON payload or CSV text
  SurveysAPI-->>User: HTTP response
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: a new surveys system for creating, taking, and analyzing surveys.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 18

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@public/survey-create.html`:
- Line 123: The toast container used by showToast is missing an accessibility
live region, so screen readers won’t announce success/error messages. Update the
`#toast-container` in survey-create.html to use an appropriate aria-live setting
(and related accessible attributes if needed) so dynamic toast updates are
announced. Make the same accessibility fix anywhere else the same toast
container pattern appears in the template.
- Around line 125-141: The confirm modal is missing accessible dialog behavior
in the modal markup and its open/close helpers. Update `#confirm-modal` with
dialog semantics such as `role="dialog"`, `aria-modal="true"`, and
`aria-labelledby` tied to the title, then adjust `showConfirmModal` and
`closeConfirmModal` to manage focus properly. Move focus to the confirm button
when opening, restore focus to the trigger when closing, and add an Escape key
handler that calls `closeConfirmModal()`. Keep the same behavior consistent for
the other confirm modal instance referenced in the template.
- Around line 261-321: The question reordering UI in questionCardHtml/onDrop
only supports mouse drag-and-drop and leaves keyboard-only users with no way to
change order. Add an accessible fallback in the same question card, such as
“move up” and “move down” buttons near the drag handle, and wire them to the
same splice-based reorder logic used by onDrop/renderQuestions/saveDraft so the
behavior stays consistent. Ensure the controls are focusable, labeled, and work
for each question key in questions.
- Around line 85-88: Add accessible names and state semantics to the icon-only
controls in the survey template: update the public survey toggle in the
togglePublic/public-toggle markup to expose an explicit accessible label plus
switch semantics (aria-label, role="switch", and aria-checked reflecting state),
and add an aria-label (or equivalent accessible name) to the remove-option
button and the remove-question trash button so screen reader users can identify
each action even without visible text; use the existing public-toggle,
remove-option, and remove-question button elements as the targets for these
changes.
- Around line 137-138: Add type="button" to the confirm modal buttons in the
markup handled by the modal actions so they do not default to submit behavior.
Update the Cancel button with onclick="closeConfirmModal()" and the confirm
button with id="confirm-modal-confirm-btn" to match the other buttons in this
file that already set type="button", keeping the change localized to the modal
button elements in the survey creation page.
- Around line 72-79: Associate the “Survey Title” and “Description” labels with
their respective inputs by wiring each label’s for attribute to the matching id
on the input/textarea in the survey create template. Update the existing
label/input pairs in the survey form so the labels point to survey-title and
survey-description, preserving the current field structure while making the
accessibility relationship explicit.
- Around line 373-383: clearDraft() resets the isPublic flag but leaves the
public toggle UI out of sync, so the switch can still दिख as private after the
draft is cleared. In the clearDraft confirm callback, update the same
knob/button classes used by togglePublic() and loadDraft() for
`#public-toggle-knob` and `#public-toggle` so the visual state matches the new
isPublic = true value before rendering the toast.

In `@public/survey-results.html`:
- Around line 8-10: Pin the external assets in public/survey-results.html to
exact CDN versions and add SRI plus crossorigin attributes. Update the existing
Tailwind, Font Awesome, and Chart.js tags so they no longer use floating aliases
like Chart.js `@4`, and ensure each tag includes a matching integrity hash and
crossorigin="anonymous". Use the current script/link tags in survey-results.html
as the locations to update.
- Around line 199-211: The Pie/Bar toggle buttons in questionCardHtml currently
expose state only through the active class, so update the rendered buttons to
include aria-pressed and make toggleChartType() keep that attribute synced with
the selected chart type. Use the existing data-chart-toggle, data-type, and
chart-toggle-btn hooks to find and update the active/inactive buttons whenever
the chart mode changes.

In `@public/survey.html`:
- Around line 296-308: Duplicate-submission handling in the survey submit flow
is tied to backend wording instead of a stable signal. Update the response
handling in the survey submission logic (the fetch/res.json path that checks
res.ok) to branch on a backend-provided error code rather than testing
data.error text. Have the API return a consistent code such as
already_submitted, and in the survey UI use that code to show the
duplicate-state view while keeping the generic error path for all other
failures.
- Around line 154-201: The survey question renderer in questionHtml is
interpolating q.id raw into inline onclick/onchange handlers and data-*
attributes, so it needs the same escaping used for q.text and o.text. Update
every q.id insertion in the multiple_choice, checkbox, true_false, scale,
textarea, and wrapper attributes to pass through esc() before concatenation,
keeping the handler strings and attributes safe if the identifier shape ever
changes.
- Around line 170-188: Add aria-pressed support to the true/false and scale
toggle buttons so screen readers can detect the selected state. Update
setToggleAnswer to keep aria-pressed="true" on the active button and "false" on
the others while still applying the selected class, and make sure the button
markup in the true_false and scale render branches includes the attribute.

In `@public/surveys.html`:
- Around line 56-60: The search field in the `id="search"` input is missing an
accessible label, so add an `aria-label` to that input in `public/surveys.html`;
the magnifying-glass icon should remain decorative and not be used as the label.
Update the existing search input markup so assistive technologies announce it
properly, using the `search` input element as the target.
- Around line 95-111: The confirm modal in confirm-modal should be made
accessible by exposing it as a real dialog and handling keyboard dismissal.
Update the modal container and related open/close logic around
closeConfirmModal() and the confirm button to add dialog semantics (role and
aria-modal), focus the primary action when opened, trap focus inside the modal,
and close it on Escape. Also add explicit type attributes to both buttons in the
modal so the Cancel and Delete actions are unambiguous.
- Around line 168-200: The search is currently limited to the first 50 items
because `loadSurveys()` always fetches a fixed `limit=50` and `renderList()`
only filters the in-memory `allSurveys` array. Update `loadSurveys`/`renderList`
so the search box drives server-backed queries using the existing `GET
/api/surveys` parameters (`q`, `limit`, `offset`) instead of only client-side
filtering. Add debounced input handling to re-fetch on search text changes, and
wire pagination or “load more” via `offset` so all surveys remain reachable.

In `@src/api/surveys.py`:
- Around line 94-109: The CSV export response is reaching into the private
core._CORS constant from api_export_survey, which couples another module to an
internal detail. Expose the CORS headers through a public API in core (for
example a CORS_HEADERS constant or a helper like csv_response), and update
api_export_survey to use that public symbol instead of spreading core._CORS
directly. Keep the response construction consistent with the existing
json_resp/ok/err pattern.

In `@src/surveys.py`:
- Around line 546-577: The delete_survey cascade is not atomic, so a failure in
the middle can leave partial/orphaned survey data behind. Update delete_survey
to execute the DELETE statements through env.DB.batch([...]) instead of running
each prepare(...).run() separately, and keep the existing survey_id/user_id
checks in place before the batch. Use the delete_survey function and its current
DELETE queries as the main place to refactor the cascade.
- Around line 605-624: The CSV export in the survey answers flow writes
untrusted user input directly into cells, which can trigger spreadsheet
formulas. Update the export logic around answers_by_response and the
writer.writerow calls to sanitize any text value before writing it to CSV,
especially answer_text and other free-form fields. Neutralize values that begin
with formula-triggering prefixes such as =, +, -, or @ so they are treated as
plain text when opened in Excel or Sheets.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: alphaonelabs/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: be583b21-1aee-4ed4-b82f-7b6a9cb32f1c

📥 Commits

Reviewing files that changed from the base of the PR and between 997b01e and 20d36d6.

⛔ Files ignored due to path filters (1)
  • migrations/0010_add_surveys.sql is excluded by !**/migrations/**
📒 Files selected for processing (9)
  • public/partials/navbar.html
  • public/survey-create.html
  • public/survey-results.html
  • public/survey.html
  • public/surveys.html
  • src/api/surveys.py
  • src/surveys.py
  • src/worker.py
  • tests/test_api_surveys.py

Comment thread public/survey-create.html
Comment thread public/survey-create.html Outdated
Comment thread public/survey-create.html Outdated
Comment thread public/survey-create.html Outdated
Comment thread public/survey-create.html Outdated
Comment thread public/surveys.html Outdated
Comment thread public/surveys.html
Comment thread src/api/surveys.py Outdated
Comment thread src/surveys.py
Comment thread src/surveys.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

♻️ Duplicate comments (1)
public/survey-create.html (1)

256-265: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

moveQuestion is dead code — keyboard reorder fallback still not wired up.

This adds the splice-based reorder logic previously suggested as a keyboard-accessible alternative to drag-and-drop, but per the summary it's unused — no "move up"/"move down" button in questionCardHtml calls it. The underlying accessibility gap (keyboard-only users can't reorder questions) remains unresolved; only the helper skeleton was added.

Wire moveQuestion(q._key, -1) / moveQuestion(q._key, 1) to two small buttons in questionCardHtml alongside the drag handle.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@public/survey-create.html` around lines 256 - 265, The reorder helper
moveQuestion is currently unused, so keyboard-only reordering still does not
work. Update questionCardHtml to add two small “move up” and “move down” buttons
that call moveQuestion(q._key, -1) and moveQuestion(q._key, 1) respectively, and
place them alongside the existing drag handle so the splice-based fallback is
actually reachable.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@public/survey-create.html`:
- Line 404: The clearDraft flow is calling an undefined syncPublicToggle()
helper, which causes a ReferenceError before the rest of the reset logic runs.
Update clearDraft to reuse the existing public-toggle state update logic already
used elsewhere in the survey creation flow, or extract that logic into a shared
helper and call it here. Make sure the reset continues through questions
re-rendering and the success toast after the toggle state is updated.
- Around line 155-156: The HTML in the survey-create page has duplicate IDs for
site-footer and toast-container, which makes DOM lookups ambiguous. Update the
markup so each ID is unique across the document, and ensure showToast() targets
the intended toast container by using the single canonical toast-container
element. Verify any related footer or toast initialization code still references
the corrected IDs.

In `@public/surveys.html`:
- Around line 78-84: The new Load more button in the surveys page is missing an
explicit button type and currently defaults to submit, so update the button
element in the surveys markup to use type="button" while keeping the existing id
and onclick behavior on load-more-btn.

In `@src/surveys.py`:
- Around line 36-38: The CSV formula-injection guard in _CSV_FORMULA_PREFIXES is
incomplete because it only covers =, +, -, and @; extend the check in the survey
export sanitizer to also treat tab, carriage return, and line feed as dangerous
leading characters. Update the logic that uses _CSV_FORMULA_PREFIXES so values
starting with those whitespace/control characters are rejected or escaped
consistently with the existing spreadsheet formula protections.
- Around line 103-107: The err helper currently uses an implicitly optional code
parameter, which should be made explicit to match the codebase and satisfy Ruff.
Update the err function signature to use Optional[str] for code, and add the
corresponding Optional import in src/surveys.py so the type annotation is clear
and consistent.

---

Duplicate comments:
In `@public/survey-create.html`:
- Around line 256-265: The reorder helper moveQuestion is currently unused, so
keyboard-only reordering still does not work. Update questionCardHtml to add two
small “move up” and “move down” buttons that call moveQuestion(q._key, -1) and
moveQuestion(q._key, 1) respectively, and place them alongside the existing drag
handle so the splice-based fallback is actually reachable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: alphaonelabs/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: e26708b1-dfc0-408b-a4da-a8b13cf74b32

📥 Commits

Reviewing files that changed from the base of the PR and between 20d36d6 and 66deabf.

📒 Files selected for processing (6)
  • public/survey-create.html
  • public/survey-results.html
  • public/survey.html
  • public/surveys.html
  • src/api/surveys.py
  • src/surveys.py

Comment thread public/survey-create.html Outdated
Comment thread public/survey-create.html
Comment thread public/surveys.html
Comment thread src/surveys.py Outdated
Comment thread src/surveys.py Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant