Surveys - Developer Guide
This guide covers the technical architecture, database schema, and implementation details of the Survey feature in Pawtograder.Overview
The survey system allows instructors to create custom surveys, collect student responses, and analyze feedback. It uses SurveyJS for the question builder and renderer.Architecture
Tech Stack
| Layer | Technology |
|---|---|
| Frontend | Next.js 15, React 18, Chakra UI |
| Survey Engine | SurveyJS (survey-core, survey-react-ui, survey-creator-react) |
| Backend | Supabase (PostgreSQL + Row Level Security) |
| State Management | React Hook Form, Refine |
| Date Handling | date-fns, date-fns-tz |
Key Dependencies
Database Schema
Tables
surveys
Main table storing survey definitions.
survey_responses
Stores individual student responses.
survey_assignments
Maps surveys to specific students (when not assigned to all).
survey_templates
Reusable survey templates.
Enum Types
Database Triggers
| Trigger | Table | Purpose |
|---|---|---|
update_surveys_updated_at | surveys | Auto-update updated_at on changes |
update_survey_responses_updated_at | survey_responses | Auto-update updated_at on changes |
update_survey_templates_updated_at | survey_templates | Auto-update updated_at on changes |
set_survey_submitted_at_trigger | survey_responses | Auto-set submitted_at when is_submitted flips to true |
RPC Functions
soft_delete_survey(p_survey_id UUID, p_survey_logical_id UUID)
Atomically soft-deletes a survey and all its responses.
create_survey_assignments(p_survey_id UUID, p_profile_ids UUID[])
Bulk creates survey assignments for specific students.
Row Level Security (RLS)
Survey Policies
| Policy | Role | Access |
|---|---|---|
surveys_select_staff | Instructors, Graders | Read all active surveys in their classes |
surveys_select_students | Students | Read published/closed surveys they’re assigned to |
surveys_insert_instructors | Instructors | Create surveys |
surveys_update_instructors | Instructors | Update surveys |
Response Policies
| Policy | Role | Access |
|---|---|---|
survey_responses_select_owner | Owner | Read own responses |
survey_responses_select_staff | Staff | Read all responses for surveys in their classes |
survey_responses_insert_owner | Owner | Create responses |
survey_responses_update_owner | Owner | Update own responses |
TypeScript Types
File Structure
SurveyJS Integration
Rendering Surveys
Survey JSON Structure
Supported Question Types
| Type | SurveyJS Type | Description |
|---|---|---|
| Short Text | text | Single-line text input |
| Long Text | comment | Multi-line textarea |
| Single Choice | radiogroup | Radio button selection |
| Multiple Choice | checkbox | Checkbox selection |
| Yes/No | boolean | Binary toggle |
Response Handling
Saving Responses
Auto-save on Value Change
Whenallow_response_editing is enabled, responses are auto-saved:
CSV Export
The export functionality includes security protections against CSV injection:Testing
E2E Tests
Survey E2E tests are located attests/e2e/surveys.test.tsx.
Manual Testing
- Create a test class with
npm run seed - Log in as an instructor
- Navigate to Surveys to test CRUD operations
- Log in as a student to test survey taking
Common Development Tasks
Adding a New Question Type
-
Update
SurveyBuilderDataTypes.ts: -
Update the builder UI in
SurveyBuilder.tsx -
Add rendering support in
Survey.tsx(usually automatic via SurveyJS)
Modifying the Database Schema
-
Create a new migration:
-
Write your SQL in
supabase/migrations/[timestamp]_your_migration_name.sql -
Apply locally:
-
Regenerate types:
Adding RLS Policies
Troubleshooting
Survey not appearing for students
- Check survey status is
published - Verify
deleted_atis NULL - If using specific assignments, confirm student is in
survey_assignments - Check RLS policies are not blocking access
Response not saving
- Verify the student’s
profile_idmatches their class enrollment - Check for unique constraint violations (duplicate responses)
- Verify
is_submittedtrigger is working
Visual Builder not updating JSON
- Check browser console for JavaScript errors
- Verify
onChangecallback is properly wired - Check for JSON serialization issues in
serde.ts