diff --git a/docs/developer/developer-index.md b/docs/developer/developer-index.md index 16be4b8..56a50a8 100644 --- a/docs/developer/developer-index.md +++ b/docs/developer/developer-index.md @@ -17,6 +17,10 @@ This section is designed for: - Architects evaluating ODE architecture - Contributors wanting to improve the codebase +:::tip AI coding assistants +Building **custom applications** (HTML, JS, CSS bundles and JSON forms) without cloning the ODE monorepo? Use the **[custom_app](https://github.com/OpenDataEnsemble/custom_app)** repository on GitHub (`AGENTS.md` and `CONTEXT_*.md` for assistants and authors), together with the main **[documentation](https://opendataensemble.org/docs/)** site. +::: + :::info Not developing? If you're collecting data, see the [Data Collector Guide](/docs/collector/collector-index). If you're designing forms, see the [Implementer Guide](/docs/implementer/implementer-index). diff --git a/docs/guides/custom-applications.md b/docs/guides/custom-applications.md index 6b4bf32..81a2246 100644 --- a/docs/guides/custom-applications.md +++ b/docs/guides/custom-applications.md @@ -10,39 +10,42 @@ Complete guide to building and deploying custom applications that integrate with ## Overview -Custom applications are React applications that run within the Formulus mobile app, providing specialized workflows and user experiences. They allow you to create custom navigation, integrate with the ODE form system, and build specialized interfaces for specific use cases. +Custom applications are **web applications** (HTML, CSS, and JavaScript) that run inside the Formulus mobile app’s WebView. You may author them with **any** stack—plain static files, **Vite**, **React**, **Vue**, **Svelte**, or another bundler—**as long as the build output** can be packaged as described in the [app bundle format](/docs/reference/app-bundle-format) (entry HTML, assets, and `forms/` layout). They provide specialized workflows, custom navigation, integration with the ODE form system, and interfaces tailored to your use case. + +## Scaffolding + +ODE does **not** require a special installer: start from a **standard** project scaffold (for example **`npm create vite@latest`** with React, Svelte, or Solid templates) and then align the **folder layout** with the app bundle spec. Copy-paste commands, a **Vite `outDir` example**, and a post-scaffold checklist are maintained in the **[custom_app](https://github.com/OpenDataEnsemble/custom_app)** repository README on GitHub (AI and author context for the Formulus API and forms live in that repo as well). ## Application Structure -Custom applications follow a standardized structure for consistency and maintainability: +There is **no single mandatory** project layout. The tree below is **one** common pattern (React + Vite + optional `app.config.json` for theming). You can use a simpler folder tree if you prefer hand-written HTML/JS or a different framework, provided the **zip** you upload matches the [bundle format](/docs/reference/app-bundle-format). ``` my-app/ -├── app.config.json # App configuration and theme -├── forms/ # Form definitions -│ ├── survey/ +├── app.config.json # Optional: app metadata and theme (if your template uses it) +├── forms/ # Form definitions (see bundle format) +│ ├── survey/ # One folder per form type (form name) │ │ ├── schema.json # JSON Schema (draft-07) -│ │ └── ui.json # Formulus UI schema -│ └── forms-manifest.json # Form registry -├── src/ -│ ├── components/ # Reusable components -│ ├── screens/ # Main screens -│ ├── utils/ # Utility functions -│ └── theme.js # Theme generation -├── scripts/ # Build and validation scripts -├── package.json -└── vite.config.js +│ │ └── ui.json # JSON Forms UI schema (ODE rules) +│ └── forms-manifest.json # Form registry (if used by your project) +├── src/ # Optional: only if you use a bundler (e.g. React) +│ ├── components/ +│ ├── screens/ +│ ├── utils/ +│ └── theme.js +├── scripts/ +├── package.json # Optional: if you use npm tooling +└── vite.config.js # Optional: example bundler config ``` ## Configuration System ### app.config.json -The `app.config.json` file is the single source of truth for your application's configuration: +If your template uses **`app.config.json`** (common in React-based examples), it can hold application metadata and theme. Plain HTML apps may omit it and configure styling in CSS/JS instead. When present, it is typically the single place for those settings: ```json { - "$schema": "https://ode.dev/schemas/app-config-v1.json", "name": "My Application", "version": "1.0.0", "navigation": { @@ -108,10 +111,12 @@ export function buildTheme(mode = 'light') { ### Form Structure -Each form consists of two files: +Each form is a **directory** named with the **form type** (for example `survey/`). Inside it, two files are required: + +1. **`schema.json`**: [JSON Schema](https://json-schema.org/) (draft-07) defining data shape, validation, and question types (including ODE `format` values). See [Form specifications](/docs/reference/form-specifications). +2. **`ui.json`**: [JSON Forms](https://jsonforms.io/) **UI schema** defining layout (`VerticalLayout`, `Control`, `scope`, rules). ODE follows JSON Forms with project-specific rules—see [Form specifications](/docs/reference/form-specifications). The [app bundle format](/docs/reference/app-bundle-format) describes how these files sit inside the zip. -1. **schema.json**: JSON Schema (draft-07) defining data structure -2. **ui.json**: Formulus UI schema defining form layout and behavior +Synkronus accepts **`forms//schema.json`** and **`ui.json`** at the **bundle root** (with **`forms/`** as a **sibling** of **`app/`**), or the alternate path **`app/forms//...`** where **`forms`** sits **inside** **`app`**. See [App bundle format](/docs/reference/app-bundle-format). ### Example Form diff --git a/docs/guides/quick-start-custom-app.md b/docs/guides/quick-start-custom-app.md index 97d2765..d2e6641 100644 --- a/docs/guides/quick-start-custom-app.md +++ b/docs/guides/quick-start-custom-app.md @@ -50,7 +50,6 @@ my-app/ ```json { - "$schema": "https://ode.dev/schemas/app-config-v1.json", "name": "My First App", "version": "1.0.0", "navigation": { diff --git a/docs/implementer/implementer-index.md b/docs/implementer/implementer-index.md index 2315253..f02a409 100644 --- a/docs/implementer/implementer-index.md +++ b/docs/implementer/implementer-index.md @@ -17,6 +17,10 @@ This section is designed for users who: - Need guidance on deployment and data management - Are responsible for project outcomes +:::tip AI coding assistants +If you use an AI assistant to build **custom applications** (bundles and JSON forms) for ODE, see **[custom_app](https://github.com/OpenDataEnsemble/custom_app)** on GitHub and the **[documentation](https://opendataensemble.org/docs/)** site—no need to clone the full ODE monorepo. +::: + :::info Not collecting data? If you're collecting data with Formulus, see the [Data Collector Guide](/docs/collector/collector-index). If you're developing or extending ODE, see the [Developer Guide](/docs/developer/developer-index). diff --git a/docs/reference/app-bundle-format.md b/docs/reference/app-bundle-format.md index 95b5129..07e3078 100644 --- a/docs/reference/app-bundle-format.md +++ b/docs/reference/app-bundle-format.md @@ -12,27 +12,35 @@ App bundles are ZIP archives containing custom application files, form specifica ## Bundle Structure -An app bundle is a ZIP file with the following structure: +Synkronus validates bundles that use **top-level** folders **`app/`**, **`forms/`**, and optionally **`renderers/`**. The **`app`** directory (your HTML/JS/CSS) and the **`forms`** directory (JSON Forms) are **siblings** at the root of the ZIP—they are **not** nested inside each other in the default layout. ``` app-bundle.zip -├── index.html # Main entry point (required) ├── manifest.json # Bundle metadata (required) -├── assets/ -│ ├── css/ -│ │ └── styles.css -│ ├── js/ -│ │ ├── app.js -│ │ └── formulus-load.js -│ └── images/ -│ └── logo.png -├── forms/ # Form specifications (optional) -│ ├── survey-v1.json -│ └── health-v1.json -└── config/ # Configuration files (optional) - └── settings.json +├── app/ # Web UI (required): sibling of forms/, not parent of it +│ ├── index.html # Main entry point (required) +│ ├── assets/ +│ │ ├── css/ +│ │ ├── js/ +│ │ │ ├── app.js +│ │ │ └── formulus-load.js +│ │ └── images/ +│ └── public/ # Optional: e.g. app.config.json copied into build +├── forms/ # Form specs (optional; see Form specifications) +│ ├── survey/ # Folder name = form type id +│ │ ├── schema.json +│ │ └── ui.json +│ └── health/ +│ ├── schema.json +│ └── ui.json +├── forms/ext.json # Optional: app-level extensions config +└── renderers/ # Optional: custom JSON Forms renderers + └── myRenderer/ + └── renderer.jsx ``` +**Alternate layout (nested forms):** Some projects put form folders under **`app/forms//`** instead of top-level **`forms//`**. In that case **`forms`** is a **subdirectory inside `app`** (path `app/forms/...`). That is **different** from having **`app/`** and **`forms/`** as **two separate top-level folders**. Synkronus accepts both; use one style consistently in a given bundle. + ## Manifest Format The `manifest.json` file defines bundle metadata: @@ -42,7 +50,7 @@ The `manifest.json` file defines bundle metadata: "version": "20250114-123456", "name": "My Custom App", "description": "Description of the custom application", - "entryPoint": "index.html", + "entryPoint": "app/index.html", "createdAt": "2025-01-14T10:00:00Z" } ``` @@ -59,13 +67,13 @@ The `manifest.json` file defines bundle metadata: ## Entry Point -The entry point (`index.html` by default) is the main HTML file loaded when the app bundle is opened. It should: +Validated bundles include **`app/index.html`** (path from the **ZIP root**). The manifest **`entryPoint`** should reference that file (commonly `app/index.html`). The entry HTML should: 1. Include the Formulus load script 2. Initialize the application 3. Use the Formulus JavaScript interface -**Example:** +**Example** (paths below assume assets live under `app/assets/`): ```html @@ -84,38 +92,40 @@ The entry point (`index.html` by default) is the main HTML file loaded when the ## Form Specifications -Form specifications can be included in the `forms/` directory. Each form file should contain: +Use a **one-folder-per-form** layout. The **folder name** is the **form type** identifier (for example `survey`, `registration`). Synkronus validates that each form directory contains both required files. -- Schema definition -- UI schema definition -- Form metadata +**Folder structure:** **`forms//`** at the **root** of the ZIP, as a **sibling** of **`app/`**. -**Example form file:** +### Required files per form + +| File | Role | +|------|------| +| **`schema.json`** | **[JSON Schema](https://json-schema.org/)** (draft-07 in ODE) for the observation payload: properties, types, validation, and ODE-specific **`format`** values for question types. Defines *what* is collected. | +| **`ui.json`** | **[JSON Forms UI schema](https://jsonforms.io/docs/uischema/)** for layout: `VerticalLayout`, `Control` elements, `scope` pointers into the schema, rules, etc. Defines *how* the form is shown. ODE follows JSON Forms with additional rules documented in [Form specifications](/docs/reference/form-specifications). | + +Upstream JSON Forms concepts and UI schema structure are described at **[jsonforms.io](https://jsonforms.io/)**. Always cross-check ODE-specific behavior in [Form specifications](/docs/reference/form-specifications)—not every JSON Forms feature is available in Formulus. + +**Example paths (two files per form, not one combined JSON) — top-level `forms/` (sibling of `app/`):** -```json -{ - "formType": "survey", - "version": "1.0.0", - "schema": { - "type": "object", - "properties": { - "name": { - "type": "string", - "title": "Name" - } - } - }, - "uischema": { - "type": "VerticalLayout", - "elements": [ - { - "type": "Control", - "scope": "#/properties/name" - } - ] - } -} ``` +forms/ +└── survey/ + ├── schema.json + └── ui.json +``` + +**Same form type using nested `app/forms/` instead:** + +``` +app/ +├── index.html +└── forms/ + └── survey/ + ├── schema.json + └── ui.json +``` + +See [Form specifications](/docs/reference/form-specifications) and [Form design](/docs/guides/form-design) for complete examples of `schema.json` and `ui.json` pairs. ## Versioning @@ -143,13 +153,14 @@ synk app-bundle switch 20250114-123456 ### Required Files - `manifest.json`: Bundle metadata -- `index.html`: Main entry point (or file specified in `entryPoint`) +- `app/index.html`: Main entry point (or path given by `entryPoint`) ### Optional Files -- `assets/`: CSS, JavaScript, images, and other assets -- `forms/`: Form specification files -- `config/`: Configuration files +- `app/assets/` (or similar under `app/`): CSS, JavaScript, images, and other assets for the web UI +- `forms//`: Form specifications at **ZIP root** (sibling of `app/`), **or** `app/forms//` if you use the nested layout +- `forms/ext.json`: Optional extensions manifest +- `renderers/`: Optional custom JSON Forms renderers ## File Size Limits @@ -157,7 +168,7 @@ synk app-bundle switch 20250114-123456 |-----------|-------|-------| | **Total bundle size** | 100 MB | Maximum ZIP file size | | **Individual file** | 50 MB | Maximum size per file | -| **Form specification** | 1 MB | Maximum size per form file | +| **Form specification** | 1 MB | Maximum size per form file (`schema.json` / `ui.json`) | ## Upload Process @@ -213,3 +224,4 @@ Mobile devices download app bundles during synchronization: - [Custom Applications Guide](/docs/guides/custom-applications) - [API Reference](/docs/reference/rest-api/overview) - [Form Design Guide](/docs/guides/form-design) +- [custom_app on GitHub](https://github.com/OpenDataEnsemble/custom_app) — AI/agent context (`AGENTS.md`, `CONTEXT_*.md`) and **scaffolding** recipes (`npm create vite@latest`, post-build checklist)