|
| 1 | +# Storage Finder README |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +The Storage Finder is an interactive web application that helps users choose the most appropriate NYU storage service for their research data based on their specific requirements. Users answer a series of questions about their data characteristics, usage patterns, and compliance needs, and the application filters and highlights suitable storage options. |
| 6 | + |
| 7 | +## Data Sources |
| 8 | + |
| 9 | +### Current Implementation |
| 10 | + |
| 11 | +The storage finder uses static JSON files located in `src/data/storage-finder/`: |
| 12 | + |
| 13 | +- `facet-tree.json` - Contains the questions (facets) and their answer choices |
| 14 | +- `service-list.json` - Contains the storage services and their characteristics |
| 15 | + |
| 16 | +### Original Data Source |
| 17 | + |
| 18 | +The data structure is designed to be compatible with Drupal-based content management systems. Ideally, this data would be downloaded from a Drupal endpoint that provides: |
| 19 | + |
| 20 | +- **Facets taxonomy** - A two-level hierarchy representing questions and answer choices |
| 21 | +- **Services content type** - Storage services with their matching criteria and detailed information |
| 22 | +- **Service paragraphs** - Structured data fields for service comparison |
| 23 | + |
| 24 | +For organizations wanting to use a Drupal instance to manage this data: |
| 25 | + |
| 26 | +1. Set up the Finder module in Drupal following the original Cornell documentation |
| 27 | +2. Configure your questions, answer choices, and services through the Drupal admin interface |
| 28 | +3. Download the data from the Drupal REST API endpoints: |
| 29 | + - **Facet Tree**: `http://your-drupal-site.com/rest/facettree` |
| 30 | + - **Service List**: `http://your-drupal-site.com/rest/servicelist` |
| 31 | +4. Save the downloaded JSON files to `src/data/storage-finder/`: |
| 32 | + - Save facet tree data as `facet-tree.json` |
| 33 | + - Save service list data as `service-list.json` |
| 34 | + |
| 35 | +## Adding or Modifying Data |
| 36 | + |
| 37 | +> [!IMPORTANT] |
| 38 | +> Adding services and questions through the Drupal interface may be easier and provides a better user experience. If you have access to a Drupal instance with the Finder module, it is recommended to manage your data there. However, if you must modify the JSON files directly, follow the steps below carefully. |
| 39 | +
|
| 40 | +### Adding a New Question (Facet) |
| 41 | + |
| 42 | +To add a new question to the storage finder: |
| 43 | + |
| 44 | +1. **Edit `facet-tree.json`**: |
| 45 | + |
| 46 | + ```json |
| 47 | + { |
| 48 | + "id": "unique-id", // Must be globally unique across all facets and choices |
| 49 | + "name": "Your new question text?", // The question displayed to users |
| 50 | + "control_type": "radio", // "radio" (exclusive selection) or "checkbox" (multiple selections) |
| 51 | + "parent": "0", // Always "0" for top-level questions |
| 52 | + "weight": "order-number", // Controls display order; lower numbers appear first (e.g., "-1" appears before "0") |
| 53 | + "selected": false, // Always false for new questions |
| 54 | + "description": "Optional HTML description with help text", // If provided, an info button appears next to the question; clicking it opens a dialog with this content |
| 55 | + "choices": [ |
| 56 | + { |
| 57 | + "id": "choice-id-1", // Must be globally unique across all facets and choices |
| 58 | + "name": "First answer choice", // The answer text displayed to users |
| 59 | + "control_type": "radio", // Should match parent's control_type |
| 60 | + "parent": "unique-id", // Must match the parent question's id |
| 61 | + "weight": "0", // Controls display order within the question; lower numbers appear first |
| 62 | + "selected": false, // Always false for new choices |
| 63 | + "description": null // Optional: HTML description for this specific choice |
| 64 | + }, |
| 65 | + { |
| 66 | + "id": "choice-id-2", |
| 67 | + "name": "Second answer choice", |
| 68 | + "control_type": "radio", |
| 69 | + "parent": "unique-id", |
| 70 | + "weight": "1", |
| 71 | + "selected": false, |
| 72 | + "description": null |
| 73 | + } |
| 74 | + ] |
| 75 | + } |
| 76 | + ``` |
| 77 | + |
| 78 | +2. **Update existing services** in `service-list.json` by adding the appropriate choice IDs to their `facet_matches` arrays. |
| 79 | + |
| 80 | +> [!WARNING] |
| 81 | +> When you add a new question, **all existing services** must be updated to include at least one choice ID from the new question in their `facet_matches` arrays. Otherwise, those services will be filtered out and hidden when users answer the new question. |
| 82 | +
|
| 83 | +#### Control Types |
| 84 | + |
| 85 | +- **`radio`** - Only one choice can be selected (exclusive). Users can select a different option by clicking it. |
| 86 | +- **`checkbox`** - Multiple choices can be selected (inclusive). Users can select multiple options from the same question. |
| 87 | + |
| 88 | +### Adding a New Storage Service |
| 89 | + |
| 90 | +To add a new storage service: |
| 91 | + |
| 92 | +1. **Edit `service-list.json`**: |
| 93 | + |
| 94 | + ```json |
| 95 | + { |
| 96 | + "id": "unique-service-id", // Must be unique across all services |
| 97 | + "title": "Service Name", // The service name displayed to users |
| 98 | + "facet_matches": ["choice-id-1", "choice-id-2"], // Array of choice IDs this service matches |
| 99 | + "summary": null, // Currently unused, set to null |
| 100 | + "field_data": { // Service details displayed in comparison table |
| 101 | + "field_eligibility": { |
| 102 | + "value": "Who can use this service", // HTML content displayed in the table |
| 103 | + "label": "Eligibility", // Column header text |
| 104 | + "weight": 1 // Controls row display order; lower numbers appear first |
| 105 | + }, |
| 106 | + "field_limitations": { |
| 107 | + "value": "Any limitations or restrictions", |
| 108 | + "label": "Limitations", |
| 109 | + "weight": 2 |
| 110 | + }, |
| 111 | + "field_use_case": { |
| 112 | + "value": "Typical use cases", |
| 113 | + "label": "Use Case", |
| 114 | + "weight": 3 |
| 115 | + }, |
| 116 | + "field_storable_files": { |
| 117 | + "value": "Types of files that can be stored", |
| 118 | + "label": "Storable Files", |
| 119 | + "weight": 4 |
| 120 | + }, |
| 121 | + "field_permission_settings": { |
| 122 | + "value": "Permission and access control info", |
| 123 | + "label": "Permission Settings", |
| 124 | + "weight": 5 |
| 125 | + }, |
| 126 | + "field_links": { |
| 127 | + "value": "Relevant links and resources", |
| 128 | + "label": "Links", |
| 129 | + "weight": 6 |
| 130 | + }, |
| 131 | + "field_synchronous_access": { |
| 132 | + "value": "Real-time access capabilities", |
| 133 | + "label": "Synchronous Access", |
| 134 | + "weight": 7 |
| 135 | + }, |
| 136 | + "field_alumni_access": { |
| 137 | + "value": "Access after graduation/leaving", |
| 138 | + "label": "Alumni Access", |
| 139 | + "weight": 8 |
| 140 | + }, |
| 141 | + "field_backup": { |
| 142 | + "value": "Backup and recovery information", |
| 143 | + "label": "Backup", |
| 144 | + "weight": 9 |
| 145 | + } |
| 146 | + } |
| 147 | + } |
| 148 | + ``` |
| 149 | + |
| 150 | +2. **Ensure facet_matches accuracy**: The `facet_matches` array must contain at least one choice ID from each question the user answers. |
| 151 | + |
| 152 | + **Example**: If a service is for "Public/Low Risk" data (ID "5"), "Faculty" users (ID "28"), and can be used for any purpose from "For what purpose will you be using this storage?" (IDs "33", "32", "35", "34", "36"), then include: `["5", "28", "33", "32", "35", "34", "36"]`. This example is not comprehensive—you must also add choice IDs from all other questions in `facet-tree.json` to ensure the service remains available regardless of what users select. |
| 153 | + |
| 154 | +> [!WARNING] |
| 155 | +> For each question in `facet-tree.json`, you must include at least one matching choice ID in `facet_matches`, otherwise the service will be filtered out and hidden when users answer that question. |
| 156 | +
|
| 157 | +### Modifying Service Fields |
| 158 | + |
| 159 | +To add, remove, or modify the fields shown in the service comparison table: |
| 160 | + |
| 161 | +1. **Update the field structure** in `service-list.json` for all services |
| 162 | +2. **Modify the TypeScript interface** in `storage-finder.tsx`: |
| 163 | + |
| 164 | + ```typescript |
| 165 | + interface ServiceFieldData { |
| 166 | + [key: string]: FieldData; |
| 167 | + field_your_new_field: FieldData; |
| 168 | + // ... other fields |
| 169 | + } |
| 170 | + ``` |
| 171 | + |
| 172 | +> [!TIP] |
| 173 | +> All services must have the same `field_data` structure for the comparison table to display correctly. If you add a new field, make sure to add it to every service in `service-list.json`. |
| 174 | +
|
| 175 | +### Data Structure Details |
| 176 | + |
| 177 | +#### Facet Structure |
| 178 | + |
| 179 | +- **id**: Unique identifier for the question |
| 180 | +- **name**: The question text displayed to users |
| 181 | +- **control_type**: "radio" or "checkbox" |
| 182 | +- **parent**: "0" for top-level questions |
| 183 | +- **weight**: Controls display order |
| 184 | +- **description**: Optional HTML help text |
| 185 | +- **choices**: Array of possible answers |
| 186 | + |
| 187 | +#### Choice Structure |
| 188 | + |
| 189 | +- **id**: Unique identifier for the choice |
| 190 | +- **name**: Answer text displayed to users |
| 191 | +- **parent**: ID of the parent question |
| 192 | +- **weight**: Controls display order within the question |
| 193 | + |
| 194 | +#### Service Structure |
| 195 | + |
| 196 | +- **id**: Unique identifier for the service |
| 197 | +- **title**: Service name |
| 198 | +- **facet_matches**: Array of choice IDs this service is compatible with |
| 199 | +- **field_data**: Object containing service details for comparison table |
| 200 | + |
| 201 | +## Troubleshooting |
| 202 | + |
| 203 | +### Common Issues |
| 204 | + |
| 205 | +**Services not filtering correctly:** |
| 206 | + |
| 207 | +- Verify `facet_matches` arrays contain correct choice IDs |
| 208 | +- Check that choice IDs in questions match those referenced in services |
| 209 | + |
| 210 | +**New questions not appearing:** |
| 211 | + |
| 212 | +- Ensure the question has a unique ID |
| 213 | +- Verify `parent` is set to "0" for top-level questions |
| 214 | +- Check `weight` for proper ordering |
| 215 | + |
| 216 | +**Comparison table missing data:** |
| 217 | + |
| 218 | +- Confirm all services have the same `field_data` structure |
| 219 | +- Verify field names match the TypeScript interfaces |
| 220 | +- Check for JSON syntax errors |
| 221 | + |
| 222 | +## Inspiration |
| 223 | + |
| 224 | +This storage finder was inspired by the **Finder Module** originally created by: |
| 225 | + |
| 226 | +> Cornell Data Management Service Group and Cornell Information Technologies Custom Development Group (2018). Finder Module. Drupal 8. [https://github.com/CU-CommunityApps/CD-finder](https://github.com/CU-CommunityApps/CD-finder) |
| 227 | +
|
| 228 | +--- |
| 229 | + |
| 230 | +Last updated: October 2025 |
0 commit comments