Database (Import & Survey Metadata Cache)
Two tables covering candidate import history and the survey metadata cache.
Answer data is not stored in Postgres
Survey answers are read straight from Databricks Unity Catalog (cs.cs_dm.dm_answers_<survey_id>). The only thing Postgres holds is databricks_surveys, which backs the survey list. See Databricks integration.
The metadata cache is not wired to application tables
databricks_surveys caches external data and holds no foreign keys to projects or anything else. The only link is the logical one through the string stored in projects.survey_id.
import_logs
Overview
Execution history of TSV / survey imports, including a breakdown of counts and per-row errors.
Table Definition
| Logical name | Physical name | Column | Type | PK | Relation | Unique | Nullable | Default | Notes |
|---|---|---|---|---|---|---|---|---|---|
| Import log | import_logs |
id |
integer | ✓ | auto-increment | ||||
project_id |
integer | projects:id (cascade) | |||||||
import_type |
import_type | manual_tsv / manual_survey / auto_survey |
|||||||
survey_id |
varchar(50) | ✓ | Target survey for survey imports | ||||||
status |
import_status | 'pending' |
pending / processing / completed / partial / failed |
||||||
imported_count |
integer | 0 |
Rows imported successfully | ||||||
skipped_count |
integer | 0 |
Rows skipped (e.g. by filter) | ||||||
error_count |
integer | 0 |
Rows that errored | ||||||
duplicate_count |
integer | 0 |
Rows skipped as duplicates | ||||||
error_details |
json | ✓ | ImportError[] type |
||||||
payload |
json | ✓ | The request that ran the import (mapping, filter) | ||||||
source_file_timestamp |
timestamp | ✓ | Left over from the S3 CSV era; no longer written | ||||||
started_at |
timestamp | ✓ | Processing start | ||||||
completed_at |
timestamp | ✓ | Processing end | ||||||
created_at |
timestamp | now() |
Row creation |
Relations
project_id→projects.id(onDelete: cascade)
Indexes
- Primary key (
id) - INDEX:
idx_il_project_id(project_id)
Notes
- Imports are asynchronous. The API creates the row as
pending/processingand returns immediately; progress is polled throughGET /projects/{id}/candidates/import/{importId}/status - The work itself runs as an ECS Fargate task (
src/batch/import.ts) - A partially successful run ends as
partial payloadkeeps the mapping and filter verbatim, so the same conditions can be reproduced later- The
import_typevalues weremanual_s3/auto_s3during the S3 integration era. Existing rows were migrated withALTER TYPE ... RENAME VALUE
databricks_surveys
Overview
Cache of survey metadata. src/batch/databricks-meta-sync.ts aggregates cs.cs_dwh in Databricks and refreshes this table daily.
The aggregation scans roughly 68M answer rows and takes about 15 seconds, which is far too slow to run per request, so it is materialised here. The survey list and detail screens read only this table.
Table Definition
| Logical name | Physical name | Column | Type | PK | Relation | Unique | Nullable | Default | Notes |
|---|---|---|---|---|---|---|---|---|---|
| Survey metadata | databricks_surveys |
id |
integer | ✓ | auto-increment | ||||
survey_id |
varchar(50) | ✓ | External survey ID | ||||||
survey_name |
varchar(500) | Survey name | |||||||
collector_name |
varchar(500) | ✓ | Collector name | ||||||
total_respondents |
integer | 0 |
Total respondents | ||||||
completed_respondents |
integer | 0 |
Respondents who completed | ||||||
question_count |
integer | 0 |
Number of questions | ||||||
earliest_response_at |
timestamp | ✓ | First response | ||||||
latest_response_at |
timestamp | ✓ | Last response | ||||||
synced_at |
timestamp | Last refresh |
Indexes
- Primary key (
id) - UNIQUE:
survey_id - INDEX:
idx_dbs_synced_at(synced_at)
Notes
projects.survey_idpoints at thissurvey_id, but there is no foreign key- The statistics (
total_respondentsand friends) are a snapshot from the last refresh - The refresh is an upsert: rows for surveys that disappear from Databricks are kept
- The per-survey endpoints (
/api/v1/surveys/{surveyId}and below) use the presence of a row here to decide on a 404, so that an unknown ID does not turn into a Databricks "table does not exist" error (502) - This table is the renamed
s3_surveysfrom the S3 integration era; its columns are unchanged
Removed Tables
The three tables that cached S3 CSVs in Postgres have been dropped.
| Former table | Why it went away |
|---|---|
s3_answers |
Cached the answers themselves. Superseded by reading dm_answers_<survey_id> in Databricks directly |
s3_panels |
Cached respondent information. Databricks already joins it onto the answers |
s3_sync_logs |
Execution history of the sync batch, which no longer exists |
The related enums s3_sync_status / s3_sync_type were dropped as well.