# Survey Service

# Survey Service (Port 8001) {#survey-service-port-8001}


The **survey-service** is the authoring engine for MQUAD. It manages survey definitions, versioning, and the transformation between logical schemas and XLSForm files.


## Database {#database}


**Database:** `survey_db`

| Table | Purpose |
|-------|---------|
| `surveys` | Core survey metadata and current status |
| `survey_versions` | Immutable snapshots of survey schemas |
| `survey_templates` | Pre-defined survey structures for reuse |


## API Endpoints {#api-endpoints}


| Method | Path | Purpose |
|--------|------|---------|
| GET | `/api/v1/surveys` | List surveys |
| POST | `/api/v1/surveys` | Create a new survey |
| GET | `/api/v1/surveys/{id}` | Get survey details and schema |
| POST | `/api/v1/surveys/{id}/publish` | Create a new immutable version |
| POST | `/api/v1/surveys/import-xlsform` | Upload .xlsx and convert to schema |
| GET | `/api/v1/surveys/{id}/export-xlsform` | Generate .xlsx from schema |
| GET | `/api/v1/templates` | List available templates |


## XLSForm Integration {#xlsform-integration}


The service includes a robust XLSForm parser (`pyxform`) integration:
- **Import**: Converts XLSForm rows into a structured JSON schema used by the `form-service`.
- **Export**: Generates standard ODK-compliant XLSForm files for use in ODK Collect.


### Choices Sheet Parsing {#choices-sheet-parsing}


The parser supports the standard XLSForm choices sheet with MQUAD extensions:

**Standard columns:** `list_name`, `name`, `label`, `media_file`

**MQUAD extension columns:**
| Column | Type | Description |
|--------|------|-------------|
| `constraint` | string | Per-choice visibility expression (XPath). Choice is hidden when expression evaluates to false. |

**Extra columns:** Any column beyond the standard set (e.g., `state`, `district`, `region`) is preserved as choice metadata. These extra columns are available as variables in `choice_filter` expressions on survey questions, enabling cascading selects based on choice attributes.

**Constraint normalization during import:**
1. `regex_shortcuts.expand_regex_shortcut()` — Expands `regex=email` style shortcuts to full regex expressions.
2. `constraint_normalizer.normalize_constraint()` — Auto-corrects common syntax: bare `&` becomes `and`, bare `|` becomes `or`, standalone comparisons like `>=10` gain the `.` prefix.

The normalized constraint is stored in `ChoiceSchema.constraint` and serialized into the survey schema JSON.


## Supported Question Types {#supported-question-types}


Verified question types supported by the schema validator:
- `text`, `integer`, `decimal`, `range`
- `select_one`, `select_multiple` (choice-based)
- `date`, `time`, `datetime`
- `image`, `audio`, `video`, `file`
- `geopoint`, `geoshape`, `geotrace`
- `barcode`, `signature`
- `calculate`, `hidden`, `note`
- `calendar_grid` (Advanced matrix type)
- `acknowledge`, `trigger`


## Versioning Logic {#versioning-logic}


1. A survey is created in **Draft** status.
2. Updates modify the draft schema in the `surveys` table.
3. Upon **Publish**, the current draft is copied to the `survey_versions` table with an incremented version number.
4. The survey status changes to **Published**.
5. Once published, the version becomes immutable and can be assigned to multiple projects.
