Skip to content

Yes. Below is a modification to your implementation plan that adds an explicit SurveyJS → CDISC ODM-XML interoperability workstream, without derailing the core prototype. The intent is:

  1. Keep SurveyJS JSON as your authoring/runtime format (fast iteration).
  2. Add ODM as an interchange/archival layer (vendor-neutral, future-proof).
  3. Implement the mapping incrementally (minimum viable first, then deepen).

Added Workstream: SurveyJS → ODM Interoperability

Design principle

  • Internal canonical for UI/runtime: SurveyJS JSON (Creator/Runner).
  • Interchange/archival canonical: CDISC ODM-XML.
  • Mapping is versioned, deterministic, and testable.
  • ODM export/import must preserve traceability: form version, item OIDs, code lists, and auditability.

Phase 0 (New): Metadata Standards Baseline

Deliverables

  • Add a small “standards module” with:
  • ODM object model (Pydantic types) sufficient for v1 export.
  • XML serializer/deserializer for ODM.
  • Mapping registry: SurveyJS question types → ODM ItemDefs.

Acceptance criteria

  • Given a stored SurveyJS form version, you can produce a valid ODM XML document representing:
  • Study
  • Protocol + StudyEventDef(s)
  • FormDef(s)
  • ItemGroupDef (minimal)
  • ItemDef(s)
  • CodeList(s) where applicable

Phase 2 (Modified): Form Definition Model Changes for ODM Compatibility

Data model adjustments

FormDefinition

** (or **

FormVersion

)

Add fields to support stable ODM identity across versions:

  • form_oid (stable across versions; e.g., F..)
  • form_version (integer/semver)
  • surveyjs_schema (JSONB)
  • odm_formdef_snapshot (optional XML text; stored at “release” time)
  • mapping_profile (e.g., odm_v1_minimal, odm_v1_extended)
  • released_at, released_by (to support “design lock” semantics)

QuestionMap

** (new table)**

A question-level mapping table that stabilizes OIDs and supports evolution:

  • id
  • form_version_id
  • surveyjs_name (SurveyJS name property for the question)
  • item_oid (stable per question identity; can persist across versions if semantically same)
  • item_name (ODM ItemDef Name; usually same as surveyjs_name)
  • datatype (ODM DataType)
  • codelist_oid (nullable)
  • unit_oid (nullable)
  • is_identifier (for de-id / exports)
  • is_required
  • notes (mapping warnings, manual overrides)

This table is the anchor that prevents “silent flips” when a designer renames a question in SurveyJS.

CodeListMap

** (new table)**

  • codelist_oid
  • surveyjs_choices_hash (so you can detect choice changes)
  • items (JSONB: code + decode)

Phase 3 (Modified): Study Schedule Model → ODM StudyEventDef Mapping

ODM needs study structure expressed via StudyEventDef (visits/events), FormRef, and optionally ItemGroupRef.

New fields / tables

  • Ensure Visit has:
  • event_oid (stable)
  • order_number (ODM OrderNumber)
  • repeating (optional)
  • Ensure VisitFormAssignment has:
  • form_oid reference
  • order_number

Phase 4 (New): ODM Export Service

Service: ****

odm_exporter

Responsibilities

  • Generate ODM-XML from:
  • Study definition (arms/visits/forms)
  • Form versions + mappings
  • Produce deterministic output:
  • stable OIDs
  • consistent ordering
  • Validate output against a lightweight ODM validation step (at minimum: internal structural checks).

API endpoints

  • GET /studies/{study_id}/odm/metadata
  • returns ODM-XML of metadata (Study/Protocol/Events/Forms/Items).
  • GET /studies/{study_id}/odm/metadata?version=latest|released
  • if released, export only released (locked) versions.
  • POST /studies/{study_id}/odm/metadata/release
  • creates an immutable “release snapshot” of ODM for the current study design + form versions.
  • audit log entry: who released, hash of ODM XML.

Internal outputs

  • Store:
  • odm_metadata_xml
  • odm_metadata_sha256
  • released_at/by

Phase 5 (New): ODM Data Export (ClinicalData)

Once you have responses, ODM can also carry data (ClinicalDataSubjectDataStudyEventDataFormDataItemGroupDataItemData).

Minimal viable data export

  • One participant = one SubjectData node
  • Completed visits = StudyEventData
  • Each submitted form = FormData
  • Each question answer = ItemData using ItemOID

API endpoints

  • GET /studies/{study_id}/odm/clinicaldata
  • exports ODM including both metadata + clinical data (or provide two endpoints if you prefer separation).
  • GET /studies/{study_id}/participants/{pid}/odm
  • export a single subject in ODM.

Required mapping rules

  • SurveyJS question name must map to a stable ItemOID
  • Multi-select answers map either to:
  • repeated ItemData entries, or
  • delimited string (avoid if possible; choose a consistent policy and document it).

Audit requirements

  • Export requests should be audited:
  • who exported
  • what scope (study, participant)
  • what version (released snapshot hash)

Phase 6 (New): ODM Import (Optional, but recommended as a stub)

Even if you do not fully support ODM import, implement an ODM intake stub now:

API endpoints

  • POST /studies/{study_id}/odm/import/metadata
  • accepts ODM-XML
  • parses and creates a new “imported” study definition or validates and reports mapping feasibility.

Why do this early

  • It forces you to keep your internal model compatible with external systems.
  • It’s a future pathway for migration or interoperability.

Mapping Specification (Agent-Coder Ready)

1) SurveyJS Form → ODM FormDef

  • SurveyJS: titleFormDef/@Name
  • Internal form_oidFormDef/@OID
  • Each page becomes one ItemGroupDef:
  • Page title → ItemGroupDef Name
  • Stable itemgroup_oid derived from page name/index
  • Each question on the page becomes an ItemDef and referenced via ItemRef inside that ItemGroupDef.

If you want a simpler v1:

  • Create a single ItemGroupDef per form and put all items into it.

3) SurveyJS Questions → ODM ItemDef

Use SurveyJS name as the stable key; never rely on display title.

Type mapping (minimum viable)

  • textstring
  • commenttext
  • booleanboolean
  • radiogrouptext + CodeListRef
  • dropdowntext + CodeListRef
  • checkboxtext + CodeListRef (policy needed for multi-select)
  • ratinginteger
  • expression / calculated → either:
  • not exported (v1), or
  • exported as derived item with flag in metadata notes

Store mapping warnings when:

  • a SurveyJS question lacks a stable name
  • a choice list changes in a released form version
  • a question is deleted (keep old ItemOID reserved; do not reuse)

4) Choice lists → ODM CodeList

  • Each choice list becomes a CodeList with CodeListItem:
  • choice value → CodedValue
  • choice text → Decode/TranslatedText (support multilingual later)

5) Schedule → ODM StudyEventDef + FormRef

  • Visit/event → StudyEventDef with OID, Name, OrderNumber
  • VisitFormAssignment → FormRef with FormOID and OrderNumber

Versioning and “Release” Policy (Critical)

Draft vs Released

  • Draft: designers can edit forms; ODM export is available but marked draft.
  • Released: freeze ODM snapshot hash; form versions are locked for new data collection instances.

Rules

  • Never mutate a released FormVersion.
  • New changes create a new version and require a new release snapshot.
  • Participant tasks are bound to a specific released form version (prevents ambiguity in analysis).

Audit Logging Extensions

Add the following audited events:

  • FORM_MAPPING_AUTOGENERATED
  • FORM_MAPPING_OVERRIDDEN_MANUAL
  • ODM_METADATA_EXPORTED
  • ODM_METADATA_RELEASED
  • ODM_CLINICALDATA_EXPORTED
  • ODM_IMPORT_ATTEMPTED

Each log entry should include:

  • study_id
  • form_version_id(s)
  • odm hash (if export)
  • user_id
  • timestamp
  • warnings count

Testing Strategy (Non-Optional)

  1. Golden files

  2. For a known SurveyJS schema, produce ODM-XML and compare against a committed “golden” ODM output (byte-for-byte or canonicalized XML compare).

  3. Round-trip constraints

  4. SurveyJS → ODM → (optional) rehydrate internal model should preserve:

  5. counts (forms/items)
  6. OID stability
  7. schedule structure

  8. Version drift tests

  9. Update a form (add/remove/rename question) and verify:

  10. old ItemOIDs persist
  11. new ItemOIDs created
  12. deleted questions do not reuse OIDs

Where this fits into your current prototype timeline

  • Implement ODM metadata export immediately after you have:
  • Study + Visit schedule model
  • Form versioning
  • QuestionMap table
  • Implement ODM clinical data export once survey submissions are stored.
  • ODM import can remain a stub until you have a concrete need.

Agent-Coder Prompt (drop-in)

Use this as the first instruction block for your coder agent:

You are implementing an EDC prototype (FastAPI + PostgreSQL) using SurveyJS Creator/Runner for form design and participant-facing surveys. Extend the implementation plan to include CDISC ODM-XML interoperability.

Requirements:
1) Keep SurveyJS JSON as internal authoring/runtime schema.
2) Implement SurveyJS → ODM-XML mapping for study metadata:
   - StudyEventDef for visits, FormDef for forms, ItemGroupDef for pages (or single group), ItemDef for questions, CodeList for choice questions.
3) Add stable OIDs and mapping tables:
   - FormDefinition/FormVersion: form_oid, version, released_at/by, odm_snapshot(optional).
   - QuestionMap: surveyjs_name → item_oid, datatype, codelist_oid, required, identifier flag.
4) Add ODM export endpoints:
   - GET /studies/{id}/odm/metadata
   - POST /studies/{id}/odm/metadata/release (stores immutable snapshot + sha256)
5) Add ODM clinical data export endpoint once responses exist:
   - GET /studies/{id}/odm/clinicaldata
6) All exports and mapping operations must be audit logged with hash, user_id, timestamps.
7) Add golden-file tests for ODM export determinism and version drift behavior.

Deliverables:
- Data model migrations
- ODM exporter module (Pydantic types + XML serialization)
- Mapping service that generates QuestionMap/CodeListMap from SurveyJS schema and stores warnings
- API endpoints + RBAC enforcement
- Tests (golden files + version drift)

If you want the next iteration, I can turn this into a concrete repo-ready structure (folders, modules, Alembic migration checklist, and a minimal ODM XML template generator), but the above is sufficient to modify your existing plan and guide implementation cleanly.