Initial commit

This commit is contained in:
Nathan Schneider
2025-03-23 21:44:39 -06:00
commit 521c782c42
56 changed files with 8295 additions and 0 deletions

44
.gitignore vendored Normal file

@ -0,0 +1,44 @@
# Hugo default output directory
/public/
# Generated files by hugo
/resources/_gen/
/assets/jsconfig.json
hugo_stats.json
# Temporary lock file while building
/.hugo_build.lock
# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# IDE specific files
.idea
.vscode
*.swp
*.swo
# Node modules if you're using npm
node_modules/
# Environment variables
.env
# Log files
*.log
# Local Netlify folder
.netlify
# Build files
dist/
# Temporary files
*~
\#*\#

49
.gitlab-ci.yml Normal file

@ -0,0 +1,49 @@
image: registry.gitlab.com/pages/hugo:latest
variables:
GIT_SUBMODULE_STRATEGY: recursive
stages:
- build
- deploy
build:
stage: build
script:
- hugo --minify
artifacts:
paths:
- public
only:
- master
pages:
stage: deploy
script:
- echo "Deploying to GitLab Pages..."
artifacts:
paths:
- public
only:
- master
# Self-hosted deployment using rsync
# Uncomment and configure this job for deploying to your own server
# deploy:
# stage: deploy
# image: alpine:latest
# before_script:
# - apk add --no-cache openssh-client rsync
# - eval $(ssh-agent -s)
# - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
# - mkdir -p ~/.ssh
# - chmod 700 ~/.ssh
# - echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
# - chmod 644 ~/.ssh/known_hosts
# script:
# - rsync -avuz --delete public/ $SSH_USER@$SSH_HOST:$DEPLOY_PATH
# only:
# - master
# environment:
# name: production
# url: https://your-domain.com

63
CLAUDE.md Normal file

@ -0,0 +1,63 @@
# Dispute Protocol Builder
This is a prototype website, built in Hugo, to enable communities to develop customizable protocols for dispute resolution processes. It guides users through an accessible process that provides best practices while allowing for customization.
## Project Structure
- **Static Site Generator**: Hugo
- **Main Builder Interface**: `/themes/dispute-protocol-theme/layouts/_default/builder.html`
- **JavaScript Files**:
- `/static/js/builder.js`: Main application logic
- `/static/js/data/modules.js`: Predefined module options
- `/static/js/data/templates.js`: Complete protocol templates
- `/static/js/data/template-mapper.js`: Maps raw content to module references
## Content Organization
- **Components**: Building blocks of a protocol, defined in `/data/components/*.yaml`
- **Modules**: Reusable text blocks for specific fields, defined in `modules.js`
- **Templates**: Complete predefined protocols combining multiple modules
## Data Model
The application maintains a hierarchical data model:
- **Stages** → **Components****Fields**
- Each field can be populated with content from a **Module**
## Core Features
1. **Black & white UI**: Clean, accessible interface with vertical accordion sections
2. **Template selection**: Users can start with a predefined protocol template
3. **Module selection**: Users can choose from multiple pre-written modules for each field
4. **Customization**: Direct text editing in fields
5. **Export options**: Markdown, PDF, and JSON formats
6. **Import capability**: Load previously saved protocols
## Module System
Modules are the heart of the customization system:
- Each module has: `id`, `title`, `componentId`, `fieldId`, and `content`
- Modules are categorized by type (principles, participants, filing, etc.)
- Custom modules are generated from templates via `template-mapper.js`
- Module selector dropdowns display available options for each field
## Recent Improvements
1. **Template mapping**: Fixed custom module generation to create descriptive titles
2. **Module presentation**: Removed category labels from dropdowns
3. **Module coverage**: Added comprehensive modules for all components
4. **Name formatting**: Enhanced logic to extract meaningful titles from content
## Deployment
- Deployable from a self-hosted GitLab server
- Data is maintained in YAML files for components and stages
- Module content is defined in JavaScript for easy client-side use
## Key Files to Modify
- `/static/js/data/modules.js`: Add, edit or remove module options
- `/static/js/data/template-mapper.js`: Adjust how custom modules are generated
- `/static/js/data/templates.js`: Define new protocol templates
- `/static/js/builder.js`: Modify core interface functionality
- `/static/css/main.css`: Adjust styling and responsive behavior

167
GITLAB_DEPLOYMENT.md Normal file

@ -0,0 +1,167 @@
# Deploying from a Self-Hosted GitLab Server
This guide provides detailed instructions for deploying the Dispute Protocol application from a self-hosted GitLab server.
## Prerequisites
- A self-hosted GitLab server (GitLab Community Edition or Enterprise Edition)
- GitLab Runner installed and configured on your server
- Basic familiarity with GitLab CI/CD
## Deployment Options
The project includes a `.gitlab-ci.yml` file that supports two deployment methods:
1. **GitLab Pages** - For hosting directly on your GitLab instance
2. **Custom Server Deployment** - For deploying to an external web server
## Option 1: Deploying to GitLab Pages
GitLab Pages provides an easy way to host static websites directly from your GitLab repository.
### Configuration Steps:
1. Ensure GitLab Pages is enabled on your self-hosted GitLab instance:
- Go to Admin Area > Settings > Pages
- Enable GitLab Pages and configure the domain settings
2. The existing `.gitlab-ci.yml` file already includes the necessary configuration for GitLab Pages. When you push to the `master` branch, the site will be automatically built and deployed.
3. Access your site at `https://[group-or-username].gitlab-instance.com/dispute-protocol`
## Option 2: Deploying to a Custom Web Server
For more control, you can deploy to your own web server using rsync over SSH.
### Configuration Steps:
1. In your GitLab repository, go to **Settings > CI/CD > Variables**
2. Add the following variables:
- `SSH_PRIVATE_KEY`: The private SSH key for connecting to your deployment server
- `SSH_KNOWN_HOSTS`: Output of `ssh-keyscan your-server.com`
- `SSH_USER`: Username on your deployment server
- `SSH_HOST`: Hostname or IP address of your deployment server
- `DEPLOY_PATH`: Path on your server where the site should be deployed
3. Edit the `.gitlab-ci.yml` file and uncomment the `deploy` job
4. Update the `url` parameter in the environment section with your actual domain
5. Push your changes to the `master` branch to trigger the deployment
### How to generate SSH_KNOWN_HOSTS value:
```bash
ssh-keyscan -H your-server.com
```
### How to generate and configure SSH keys:
1. Generate a new SSH key pair (without a passphrase for automated use):
```bash
ssh-keygen -t ed25519 -C "gitlab-deploy" -f gitlab-deploy-key
```
2. Add the public key to your server's authorized_keys:
```bash
cat gitlab-deploy-key.pub >> ~/.ssh/authorized_keys
```
3. Copy the private key content (including BEGIN and END lines) and paste it into the `SSH_PRIVATE_KEY` variable in GitLab
## Web Server Configuration
### Nginx Configuration
```nginx
server {
listen 80;
server_name your-domain.com;
root /path/to/deployment;
index index.html;
location / {
try_files $uri $uri/ =404;
}
# Optional: Enable gzip compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
}
```
### Apache Configuration
Create a .htaccess file in your deployment directory:
```apache
# Enable rewriting
RewriteEngine On
# If the requested resource doesn't exist as a file or directory
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Rewrite to index.html
RewriteRule ^(.*)$ /index.html [L]
# Cache control for static assets
<FilesMatch "\.(css|js|png|jpg|jpeg|gif|ico)$">
Header set Cache-Control "max-age=604800, public"
</FilesMatch>
```
## Manual Deployment
If you prefer to deploy manually without GitLab CI/CD, you can use the included scripts:
### Testing the Build Locally
Before deploying, you can test the build locally using the included `build-test.sh` script:
```bash
./build-test.sh [port]
```
Example:
```bash
./build-test.sh 8080
```
This will build the site and start a temporary web server on the specified port (default: 8080), allowing you to verify that everything works correctly before deployment.
### Deploying to a Remote Server
To deploy to your own server manually, use the included `deploy.sh` script:
```bash
./deploy.sh [username] [server] [deploy-path]
```
Example:
```bash
./deploy.sh deploy-user example.com /var/www/dispute-protocol
```
This script will build the site and then use rsync to deploy it to your server.
## Troubleshooting
### CI/CD Pipeline Fails
1. Check the pipeline logs for detailed error messages
2. Verify that the GitLab Runner is properly configured and running
3. Ensure the SSH key has the correct permissions on the target server
4. Try running the build and deploy steps manually to identify issues
### Site Not Accessible After Deployment
1. Check web server logs for errors
2. Verify file permissions in the deployment directory
3. Ensure the web server configuration is correct
4. Check that the domain DNS is pointing to the correct server

21
LICENSE Normal file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Community Dispute Protocol Builder
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

196
README.md Normal file

@ -0,0 +1,196 @@
# Community Dispute Protocol Builder
A Hugo-based web application that helps communities create structured processes for resolving conflicts and disputes.
Created as a prototype by Nathan Schneider with Claude Code.
## Features
- Interactive protocol builder with multi-stage process
- Pre-defined modules for common dispute resolution approaches
- Complete protocol templates for different facilitation styles
- Export protocols as Markdown, PDF, or JSON
- Import previously created protocols (JSON format)
- Responsive design for desktop and mobile
## Setup and Installation
1. Make sure you have [Hugo](https://gohugo.io/installation/) installed
2. Clone this repository
3. Run the local development server:
```bash
cd dispute-protocol
hugo server -D
```
4. Access the site at http://localhost:1313/
## Customizing the Dispute Protocol
### Adding or Modifying Stages
Edit the file `data/stages/stages.yaml` to modify the stages of the dispute resolution process.
```yaml
- id: new-stage
title: New Stage Name
description: Description of this stage
order: 7 # This determines the order in which stages appear
```
### Adding or Modifying Components
Components are grouped by stage. Create or edit files in the `data/components/` directory, naming the file after the stage ID.
For example, to add components to a stage with ID "new-stage", create `data/components/new-stage.yaml`:
```yaml
- id: new-component
title: New Component Title
description: Description of what this component addresses
stageId: new-stage
order: 1
fields:
- id: newComponentField
type: text
label: Field Label
placeholder: Placeholder text...
required: true
```
### Adding Pre-defined Modules
Modules provide pre-written content that users can select for specific fields. There are two places where modules are defined:
1. **YAML Definition (source of truth):** Create or edit files in the `data/modules/` directory.
```yaml
- id: new-module
title: New Module Title
componentId: new-component
fieldId: newComponentField
content: |
This is the pre-defined content that will be inserted when
the user selects this module. It can include multiple lines.
```
2. **JavaScript Implementation:** The frontend uses modules defined in `static/js/data/modules.js`. When adding new modules to the YAML files, you should also add them to this JavaScript file to make them available in the builder interface.
```javascript
const moduleData = {
module_category: [
{
id: "new-module",
title: "New Module Title",
componentId: "new-component",
fieldId: "newComponentField",
content: `This is the pre-defined content that will be inserted when
the user selects this module. It can include multiple lines.`
}
]
};
```
**Important:** Make sure the `componentId` and `fieldId` values match exactly with the component and field IDs defined in the `data/components/` directory.
### Using Protocol Templates
The application includes complete protocol templates that pre-fill all components with consistent content. Three templates are provided:
1. **Peer-to-Peer Protocol**: A self-facilitated process where participants work together directly to resolve disputes without a formal facilitator.
2. **Chosen Facilitator Protocol**: A process where participants mutually select a facilitator who may not have specialized skills but can help guide the discussion.
3. **Facilitation Council Protocol**: A structured process with a trained council of facilitators who manage the dispute resolution process.
Users can select a template from the dropdown at the top of the builder page to automatically populate all fields. They can then customize the content as needed for their community's specific requirements.
#### Adding New Protocol Templates
To add a new protocol template, edit the file `static/js/data/templates.js`. Each template follows this structure:
```javascript
{
id: "template-id",
title: "Template Name",
description: "Brief description of this template approach",
data: {
stages: {
// Full protocol data structure with content for all stages and components
}
}
}
```
## Deployment
### Building for Production
To build the site for production:
```bash
hugo --minify
```
The generated site will be in the `public` directory, which you can deploy to any static hosting service.
### Deploying from a Self-Hosted GitLab Server
This project includes GitLab CI/CD configuration for easy deployment. The included `.gitlab-ci.yml` file supports two deployment options:
1. **GitLab Pages** - Automatically deployed when you push to the master branch
2. **Custom Server Deployment** - Deploy to your own server using rsync
#### Setting Up Custom Server Deployment
1. In your GitLab repository, go to **Settings > CI/CD > Variables**
2. Add the following variables:
- `SSH_PRIVATE_KEY`: Your private SSH key for the deployment server
- `SSH_KNOWN_HOSTS`: Output of `ssh-keyscan your-server.com`
- `SSH_USER`: Username on your deployment server
- `SSH_HOST`: Hostname or IP of your deployment server
- `DEPLOY_PATH`: Path on your server where the site should be deployed
3. Uncomment the `deploy` job in `.gitlab-ci.yml`
4. Update the `url` parameter in the environment section with your actual domain
5. Push your changes to the master branch to trigger the deployment
#### Web Server Configuration
For Nginx, use a configuration similar to this:
```nginx
server {
listen 80;
server_name your-domain.com;
location / {
root /path/to/deployment;
index index.html;
try_files $uri $uri/ =404;
}
}
```
For Apache, create a .htaccess file in your deployment directory:
```apache
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.html [L]
```
## Technologies Used
- Hugo static site generator
- JavaScript for interactive features
- jsPDF for PDF generation
## License
This project is licensed under the MIT License - see the LICENSE file for details.

6
archetypes/default.md Normal file

@ -0,0 +1,6 @@
---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
---

41
build-test.sh Executable file

@ -0,0 +1,41 @@
#!/bin/bash
# Test build script for the Dispute Protocol site
# This script builds the site and runs a temporary server to check it works
set -e
# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m' # No Color
# Configuration
BUILD_DIR="public"
PORT=${1:-8080}
# Check if Hugo is installed
if ! command -v hugo &> /dev/null; then
echo -e "${RED}Error: Hugo is not installed. Please install Hugo first.${NC}"
echo "Visit https://gohugo.io/installation/ for installation instructions."
exit 1
fi
echo -e "${YELLOW}Building site...${NC}"
hugo --minify
# Check if build succeeded
if [ ! -d "$BUILD_DIR" ]; then
echo -e "${RED}Error: Build failed. The '$BUILD_DIR' directory doesn't exist.${NC}"
exit 1
fi
echo -e "${GREEN}Build completed successfully!${NC}"
echo -e "${YELLOW}Starting a temporary server on port $PORT...${NC}"
echo -e "${YELLOW}Press Ctrl+C to stop the server.${NC}"
cd $BUILD_DIR
python3 -m http.server $PORT
exit 0

41
config.toml Normal file

@ -0,0 +1,41 @@
baseURL = '/'
languageCode = 'en-us'
title = 'Community Dispute Protocol'
theme = 'dispute-protocol-theme'
# Enable relative URLs for easier deployment in different environments
relativeURLs = true
canonifyURLs = false
# Output configuration
[outputs]
home = ["HTML", "RSS"]
# Configure static resources
[params]
# Custom CSS
customCSS = ["css/main.css"]
# Custom JS
customJS = ["js/builder.js", "js/data/modules.js", "js/data/templates.js"]
# Site description
description = "A tool for communities to develop customized dispute resolution protocols"
# Footer text
footer = "Powered by Hugo and hosted on GitLab"
# Menu configuration
[menu]
[[menu.main]]
name = "Home"
url = "/"
weight = 1
[[menu.main]]
name = "Builder"
url = "/builder/"
weight = 2
[[menu.main]]
name = "About"
url = "/about/"
weight = 3

8
content/_index.md Normal file

@ -0,0 +1,8 @@
---
title: "Community Dispute Protocol Builder"
date: 2023-07-10
draft: false
---
Welcome to the Community Dispute Protocol Builder. This tool helps communities create structured processes for resolving conflicts and disputes.

95
content/about.md Normal file

@ -0,0 +1,95 @@
---
title: "About"
date: 2023-07-10
draft: false
---
# About the Community Dispute Protocol Builder
The Dispute Protocol Builder is a collaborative tool designed to help communities develop customized frameworks for addressing and resolving conflicts. Rather than imposing a one-size-fits-all solution, this tool empowers communities to create protocols that reflect their unique values, culture, and specific needs.
## Why Create a Dispute Protocol?
Every community experiences conflicts. Whether in neighborhoods, workplaces, cooperatives, online spaces, or cultural groups, disagreements and tensions are inevitable. Having a thoughtful, agreed-upon process for addressing these conflicts provides numerous benefits:
- **Prevents escalation** of small issues into major conflicts
- **Creates consistency** and predictability during challenging times
- **Ensures fairness and transparency** in how issues are addressed
- **Reduces harm** during the resolution process
- **Builds community capacity** to handle future conflicts
- **Strengthens relationships** by demonstrating commitment to healthy conflict engagement
- **Embodies community values** in practical, actionable ways
- **Provides guidance** when emotions are running high
Without a clear protocol, communities often default to ad-hoc approaches that can amplify harm, reinforce power imbalances, or leave conflicts unresolved.
## How the Builder Works
The Protocol Builder guides you through creating a comprehensive dispute resolution framework using a modular approach:
### 1. Start from Templates or Build from Scratch
Begin with one of our pre-designed templates based on restorative justice, transformative justice, or consensus-based approaches—or start with a blank slate and build your own custom protocol.
### 2. Customize Each Stage
The builder walks you through six key stages of dispute resolution:
1. **Preparation**: Establishing core values, principles, and participant roles
2. **Initiation**: Defining how disputes are raised, acknowledged, and entered into the process
3. **Exploration**: Investigating and understanding the facts, perspectives, and underlying needs
4. **Deliberation**: Discussing potential solutions and working toward agreements
5. **Resolution**: Finalizing, documenting, and implementing solutions
6. **Follow-up**: Evaluating outcomes, ensuring accountability, and making improvements
### 3. Mix and Match Modules
For each component within these stages, you can select from pre-written modules or craft your own content. This modular approach lets you:
- Choose elements that align with your community's values
- Adapt the protocol based on your community's capacity and resources
- Create a coherent process that addresses your specific needs
- Ensure nothing important is overlooked
### 4. Export and Share
When your protocol is complete, export it as:
- A formatted PDF to share with your community
- A Markdown document for easy editing and version control
- A JSON file that can be imported back into the builder for future updates
## Design Principles
The Dispute Protocol Builder is designed around these core principles:
- **Accessibility**: Simple, clear language and an intuitive interface make this tool usable by anyone, regardless of technical expertise or familiarity with conflict resolution terminology.
- **Flexibility**: Every component is customizable to accommodate diverse community contexts and needs.
- **Comprehensiveness**: The tool addresses all aspects of dispute resolution, from initial values to final implementation.
- **Educational**: Pre-written modules offer best practices drawn from various dispute resolution traditions.
- **Privacy-Focused**: All work happens locally in your browser—no data is sent to our servers.
## Who Is This For?
This tool is designed for any group that wants to improve how they handle internal conflicts:
- **Intentional Communities and Cooperatives**
- **Neighborhood Associations**
- **Activist Groups and Collectives**
- **Small Businesses and Worker Cooperatives**
- **Faith Communities**
- **Online Communities and Forums**
- **Educational Institutions**
- **Non-Profit Organizations**
- **Artistic and Cultural Collectives**
## Get Started
<div class="cta-container">
Ready to create your community's dispute protocol?
<a href="/builder" class="cta-button">Start Building Your Protocol</a>
</div>

8
content/builder.md Normal file

@ -0,0 +1,8 @@
---
title: "Protocol Builder"
date: 2023-07-10
draft: false
layout: "builder"
---
Use this interactive builder to create your community's dispute resolution protocol.

8
content/modules.md Normal file

@ -0,0 +1,8 @@
---
title: "Modules Library"
description: "Browse all available modules for the Dispute Protocol Builder"
layout: "modules"
draft: false
---
This page displays all available modules in the Dispute Protocol Builder, organized by Stage and Component. You can see which Templates use each module.

@ -0,0 +1,23 @@
- id: appeal_criteria
title: "What are the criteria for a permissible appeal?"
description: "Standards for allowing an appeal of a resolution"
stageId: appeal
order: 1
fields:
- id: appealCriteriaText
type: text
label: "What are the criteria for a permissible appeal?"
placeholder: "Describe what circumstances justify an appeal of a resolution..."
required: true
- id: appeal_process
title: "What happens when an appeal occurs?"
description: "Process for handling appeals"
stageId: appeal
order: 2
fields:
- id: appealProcessText
type: text
label: "What happens when an appeal occurs?"
placeholder: "Describe the process that follows when an appeal is initiated..."
required: true

@ -0,0 +1,59 @@
- id: dispute_assessment
title: "How to assess the state of the dispute?"
description: "Methods for evaluating the current status of a dispute"
stageId: assessment
order: 1
fields:
- id: disputeAssessmentText
type: text
label: "How is the state of the dispute assessed?"
placeholder: "Describe methods used to evaluate the current status of a dispute..."
required: true
- id: values_adherence
title: "Are community values being followed?"
description: "Evaluating whether the process is aligned with community values"
stageId: assessment
order: 2
fields:
- id: valuesAdherenceText
type: text
label: "How do you ensure community values are being followed?"
placeholder: "Describe how you evaluate whether the process adheres to community values..."
required: true
- id: jurisdiction
title: "Is the dispute within the jurisdiction of this process?"
description: "Determining whether this is the appropriate forum for the dispute"
stageId: assessment
order: 3
fields:
- id: jurisdictionText
type: text
label: "How do you determine if a dispute falls within this process's jurisdiction?"
placeholder: "Describe how you determine whether this process is appropriate for a given dispute..."
required: true
- id: non_participation
title: "What happens when someone fails to participate?"
description: "Handling non-participation in the process"
stageId: assessment
order: 4
fields:
- id: nonParticipationText
type: text
label: "What happens when someone fails to participate?"
placeholder: "Describe procedures for handling situations where someone refuses to participate..."
required: true
- id: process_change
title: "What if the process needs to be changed?"
description: "Adapting the process when necessary"
stageId: assessment
order: 5
fields:
- id: processChangeText
type: text
label: "What if the process needs to be changed?"
placeholder: "Describe how the process can be adapted if it's not working effectively..."
required: true

@ -0,0 +1,23 @@
- id: reporting
title: "Reporting"
description: "Methods for reporting conflicts or disputes"
stageId: become_aware
order: 1
fields:
- id: reportingText
type: text
label: "How are conflicts or disputes reported?"
placeholder: "Describe the mechanisms for reporting conflicts..."
required: true
- id: monitoring
title: "Monitoring"
description: "Proactive monitoring for potential conflicts"
stageId: become_aware
order: 2
fields:
- id: monitoringText
type: text
label: "How does your community monitor for potential conflicts?"
placeholder: "Describe approaches to monitoring for potential conflicts..."
required: true

@ -0,0 +1,11 @@
- id: delegation_options
title: "Where can the dispute be delegated if this process is inadequate?"
description: "Alternative processes for disputes that cannot be handled by this process"
stageId: delegation
order: 1
fields:
- id: delegationOptionsText
type: text
label: "Where can the dispute be delegated if this process is inadequate?"
placeholder: "Describe alternative processes for disputes that cannot be handled internally..."
required: true

@ -0,0 +1,35 @@
- id: deliberation_process
title: "How do participants deliberate about the dispute?"
description: "Methods for deliberation during the dispute process"
stageId: deliberation
order: 1
fields:
- id: deliberationProcessText
type: text
label: "How do participants deliberate about the dispute?"
placeholder: "Describe the format and structure of deliberations..."
required: true
- id: additional_voices
title: "Who, beyond the main participants, can be heard?"
description: "Including additional perspectives in the deliberation"
stageId: deliberation
order: 2
fields:
- id: additionalVoicesText
type: text
label: "Who, beyond the main participants, can be heard?"
placeholder: "Describe whose voices are included in deliberations beyond the main parties..."
required: true
- id: deliberation_conclusion
title: "When is the deliberation over?"
description: "Criteria for concluding the deliberation phase"
stageId: deliberation
order: 3
fields:
- id: deliberationConclusionText
type: text
label: "When is the deliberation over?"
placeholder: "Describe how you determine when deliberation is complete..."
required: true

@ -0,0 +1,23 @@
- id: filing
title: Filing a Complaint
description: Process for submitting a dispute
stageId: initiation
order: 1
fields:
- id: filingProcess
type: text
label: Filing Process
placeholder: Describe how disputes are submitted...
required: true
- id: notification
title: Notification Process
description: How parties are informed of the dispute
stageId: initiation
order: 2
fields:
- id: notificationMethod
type: text
label: Notification Method
placeholder: Describe how involved parties are notified...
required: true

@ -0,0 +1,71 @@
- id: process_start
title: "How does the process begin?"
description: "The mechanism for initiating the dispute process"
stageId: intake
order: 1
fields:
- id: processStartText
type: text
label: "How does the process begin?"
placeholder: "Describe how disputes are initiated in your community..."
required: true
- id: rules_access
title: "Where does the community keep its rules?"
description: "Location and accessibility of community rules and guidelines"
stageId: intake
order: 2
fields:
- id: rulesAccessText
type: text
label: "Where does the community keep its rules?"
placeholder: "Describe where community rules are documented and how they can be accessed..."
required: true
- id: information_access
title: "Who has access to information about the process?"
description: "Transparency and confidentiality policies"
stageId: intake
order: 3
fields:
- id: informationAccessText
type: text
label: "Who has access to information about the process?"
placeholder: "Describe who can access information about ongoing dispute processes..."
required: true
- id: participant_inclusion
title: "How are other participants brought into the process?"
description: "Methods for notifying and including relevant parties"
stageId: intake
order: 4
fields:
- id: participantInclusionText
type: text
label: "How are other participants brought into the process?"
placeholder: "Describe how relevant parties are notified and included in the process..."
required: true
- id: participation_requirement
title: "Is participation in the process required or voluntary for involved parties?"
description: "Expectations regarding participation"
stageId: intake
order: 5
fields:
- id: participationRequirementText
type: text
label: "Is participation required or voluntary?"
placeholder: "Describe whether participation is mandatory or optional for involved parties..."
required: true
- id: participation_commitments
title: "What commitments does participation involve?"
description: "Expectations of participants in the process"
stageId: intake
order: 6
fields:
- id: participationCommitmentsText
type: text
label: "What commitments does participation involve?"
placeholder: "Describe what participants are committing to when they engage in the process..."
required: true

@ -0,0 +1,23 @@
- id: principles
title: Guiding Principles
description: Core values that guide the dispute resolution process
stageId: preparation
order: 1
fields:
- id: principlesText
type: text
label: Principles
placeholder: List the guiding principles for your dispute resolution process...
required: true
- id: participants
title: Participants
description: Roles and responsibilities in the dispute resolution process
stageId: preparation
order: 2
fields:
- id: participantsRoles
type: text
label: Roles and Responsibilities
placeholder: Define the roles involved in your dispute resolution process...
required: true

@ -0,0 +1,35 @@
- id: values
title: "Values"
description: "Core values that guide the dispute resolution process"
stageId: prepare
order: 1
fields:
- id: valuesText
type: text
label: "What values guide your dispute resolution process?"
placeholder: "List the values that inform your approach to conflict..."
required: true
- id: agreements
title: "Agreements"
description: "Agreements about how conflicts will be handled"
stageId: prepare
order: 2
fields:
- id: agreementsText
type: text
label: "What agreements do community members make about handling conflicts?"
placeholder: "Describe the agreements community members make about how conflicts will be handled..."
required: true
- id: skills
title: "Skills"
description: "Skills needed for handling disputes effectively"
stageId: prepare
order: 3
fields:
- id: skillsText
type: text
label: "What skills do community members need for handling disputes?"
placeholder: "Describe the skills that community members should develop..."
required: true

@ -0,0 +1,35 @@
- id: community_values
title: "What values does the community hold in disputes?"
description: "Core values that guide the dispute resolution process"
stageId: process
order: 1
fields:
- id: communityValuesText
type: text
label: "What values does the community hold in disputes?"
placeholder: "Describe the core values that guide your community's approach to conflicts..."
required: true
- id: facilitation
title: "How is the process facilitated?"
description: "Methods of facilitation during the dispute process"
stageId: process
order: 2
fields:
- id: facilitationText
type: text
label: "How is the process facilitated?"
placeholder: "Describe who facilitates the process and how they are selected/trained..."
required: true
- id: ground_rules
title: "What are the ground-rules of the process?"
description: "Basic rules of conduct during the dispute process"
stageId: process
order: 3
fields:
- id: groundRulesText
type: text
label: "What are the ground-rules of the process?"
placeholder: "Describe the rules of engagement that all participants must follow..."
required: true

@ -0,0 +1,23 @@
- id: resolution_process
title: "How does resolution of the dispute occur?"
description: "Methods for reaching a resolution"
stageId: resolution
order: 1
fields:
- id: resolutionProcessText
type: text
label: "How does resolution of the dispute occur?"
placeholder: "Describe the process by which disputes are resolved..."
required: true
- id: resolution_failure
title: "What if a resolution cannot be reached?"
description: "Handling situations where resolution is not achieved"
stageId: resolution
order: 2
fields:
- id: resolutionFailureText
type: text
label: "What if a resolution cannot be reached?"
placeholder: "Describe what happens when parties cannot come to a resolution..."
required: true

@ -0,0 +1,27 @@
- id: participant-goal-assessment
title: "Participant Goal Assessment"
componentId: dispute_assessment
fieldId: disputeAssessmentText
content: |
The dispute is assessed by focusing on the goals of all participants:
1. Each participant articulates what they hope to achieve through the process
2. Participants identify areas of common ground and shared interests
3. The facilitator helps frame the dispute in terms of compatible and competing goals
4. Participants rate the importance of different goals to help prioritize
5. Assessment continues throughout the process as goals may evolve
6. Resolution options are evaluated against the stated goals of participants
- id: fact-assessment
title: "Fact Assessment"
componentId: dispute_assessment
fieldId: disputeAssessmentText
content: |
The dispute is assessed through a structured fact-finding process:
1. Facilitators interview all parties separately to gather initial accounts
2. Documentary evidence and other materials are collected and cataloged
3. Areas of factual agreement and disagreement are identified
4. Where possible, neutral verification of disputed facts is sought
5. A written summary of established facts is created and shared with participants
6. The dispute assessment is updated as new information becomes available

@ -0,0 +1,41 @@
- id: police-report
title: "Refer to Police Report"
componentId: delegation_options
fieldId: delegationOptionsText
content: |
In cases where this process is inadequate, disputes may be referred to law enforcement:
1. Situations involving immediate danger or criminal behavior are referred to police
2. The community does not attempt to handle issues of criminal law internally
3. Support is offered to community members who need to file police reports
4. Community members may request an advocate to accompany them
5. The community maintains relationships with local law enforcement liaisons
6. Community process may resume after legal proceedings if appropriate
- id: internal-process
title: "Refer to Another Internal Process"
componentId: delegation_options
fieldId: delegationOptionsText
content: |
In cases where this process is inadequate, disputes may be referred to other internal processes:
1. The community maintains several conflict resolution pathways for different situations
2. Disputes involving multiple community groups are referred to the inter-group resolution committee
3. Disputes requiring specialized knowledge may be referred to relevant working groups
4. Cases requiring more structured intervention may be referred to the elder council
5. Mediation services are available as an alternative to the standard process
6. The community maintains clear guidelines for which process is appropriate for different situations
- id: external-process
title: "Refer to External Process"
componentId: delegation_options
fieldId: delegationOptionsText
content: |
In cases where this process is inadequate, disputes may be referred to external resolution services:
1. The community maintains partnerships with professional mediation services
2. Complex cases may be referred to specialized conflict resolution organizations
3. Cases involving legal questions may be referred to legal aid services
4. The community maintains a fund to help members access external services when needed
5. A list of recommended external resources is maintained and regularly updated
6. The community liaison helps ensure smooth handoff to external processes

21
data/modules/filing.yaml Normal file

@ -0,0 +1,21 @@
- id: written-filing
title: Written Filing Process
componentId: filing
fieldId: filingProcess
content: |
1. Complainant fills out a standard form describing the dispute
2. Form includes sections for: parties involved, description of the issue, desired outcome
3. Submission can be made via email, website, or physical drop-off
4. Complainant receives confirmation of receipt
5. Submission is reviewed for completeness within 48 hours
- id: verbal-filing
title: Verbal Filing Process
componentId: filing
fieldId: filingProcess
content: |
1. Complainant schedules a meeting with a designated intake person
2. During the meeting, the intake person documents the dispute details
3. The intake person reviews the documented information with the complainant
4. Once approved, the complaint is officially filed
5. Complainant receives a copy of the documented complaint

104
data/modules/intake.yaml Normal file

@ -0,0 +1,104 @@
- id: incident-report-form
title: "Incident Report Form"
componentId: process_start
fieldId: processStartText
content: |
The dispute process begins when a community member fills out an incident report form. This form includes:
1. Details about the parties involved in the dispute
2. A description of what happened, including dates and times
3. Any relevant evidence or documentation
4. A description of the outcome the person is seeking
The form can be submitted electronically through our community portal or as a paper form to the designated community coordinator.
- id: strong-confidentiality
title: "Strong Confidentiality"
componentId: information_access
fieldId: informationAccessText
content: |
Our community practices strong confidentiality in dispute processes:
1. Only the designated facilitator(s) and directly involved parties have access to full information
2. All participants must sign confidentiality agreements
3. Records are kept secure and are accessible only to the dispute resolution committee
4. Only general statistics and anonymized outcomes may be shared with the broader community
5. Breaches of confidentiality may result in removal from the process
- id: strong-transparency
title: "Strong Transparency"
componentId: information_access
fieldId: informationAccessText
content: |
Our community practices strong transparency in dispute processes:
1. Basic information about active disputes is available to all community members
2. Proceedings are documented and records are available for community review
3. Regular updates on the status of disputes are shared at community meetings
4. Only personal identifying information and sensitive details are redacted
5. All decisions and their rationales are published internally
- id: notification-message
title: "Notification Message"
componentId: participant_inclusion
fieldId: participantInclusionText
content: |
Additional participants are brought into the process through a formal notification message:
1. The facilitator sends a written notification to all identified relevant parties
2. The notification includes the nature of the dispute, the process that will be followed, and their role
3. Recipients are given information about how to respond and participate
4. The notification includes resources to help participants understand the process
5. Participants have 7 days to acknowledge receipt and confirm their participation
- id: summons
title: "Summons"
componentId: participant_inclusion
fieldId: participantInclusionText
content: |
Additional participants are brought into the process through a formal summons:
1. The dispute committee issues an official summons to all identified relevant parties
2. The summons clearly states that participation is required according to community agreements
3. It specifies the date, time, and method of required appearance
4. The summons outlines potential consequences of non-participation
5. Delivery of the summons is documented to ensure proper notification
- id: voluntary-participation
title: "Voluntary Participation"
componentId: participation_requirement
fieldId: participationRequirementText
content: |
Participation in our dispute resolution process is entirely voluntary:
1. All parties must consent to participate in the process
2. Any party may withdraw from the process at any time
3. No negative consequences result from declining to participate
4. Alternative means of resolution are suggested for those who decline
5. The community respects individuals' autonomy in choosing whether to engage
- id: required-participation
title: "Required Participation"
componentId: participation_requirement
fieldId: participationRequirementText
content: |
Participation in our dispute resolution process is required for all community members:
1. By joining our community, members agree to participate in the dispute process when necessary
2. Participation is mandatory for all named parties in a dispute
3. Failure to participate may result in consequences as outlined in our community agreement
4. Only in exceptional circumstances may exemptions be granted
5. Repeated refusal to participate may result in review of community membership
- id: stake-based-participation
title: "Stake-based Participation"
componentId: participation_commitments
fieldId: participationCommitmentsText
content: |
Participants in the dispute process must place a meaningful stake into the process:
1. Each participant contributes a small financial deposit (adjusted based on ability to pay)
2. Deposits are returned when parties fulfill all process commitments
3. Participants commit a specified amount of time to the process
4. Participants agree to adhere to all ground rules and procedural guidelines
5. All parties agree to implement the resolution in good faith

@ -0,0 +1,21 @@
- id: direct-notification
title: Direct Notification Process
componentId: notification
fieldId: notificationMethod
content: |
1. All parties are notified in writing within 72 hours of a filed complaint
2. Notification includes a copy of the complaint and next steps
3. Parties confirm receipt of notification
4. If no confirmation is received within 48 hours, a secondary contact method is used
5. All notifications maintain privacy and confidentiality standards
- id: facilitated-notification
title: Facilitated Notification Process
componentId: notification
fieldId: notificationMethod
content: |
1. A neutral facilitator contacts all parties individually
2. The facilitator explains the process and shares the complaint details
3. Parties have an opportunity to ask questions about the process
4. The facilitator documents that notification has occurred
5. Follow-up written summary is provided to all parties

@ -0,0 +1,33 @@
- id: community-circle
title: Community Circle Model
componentId: participants
fieldId: participantsRoles
content: |
1. Facilitator: Guides the process, ensures fairness, and helps maintain focus
2. Affected Parties: Those directly impacted by the dispute
3. Support Persons: Friends, family, or advocates who support affected parties
4. Community Members: Representatives who bring wider perspective
5. Resource People: Those with relevant expertise to inform the process
- id: mediation-model
title: Mediation Model
componentId: participants
fieldId: participantsRoles
content: |
1. Mediator: Neutral third party who facilitates the process
2. Disputants: Primary parties involved in the conflict
3. Advocates: Optional support persons who may speak on behalf of disputants
4. Witnesses: Those who provide information relevant to the dispute
5. Implementers: Those responsible for helping carry out any agreements
- id: council-model
title: Council Model
componentId: participants
fieldId: participantsRoles
content: |
1. Council Members: A designated group responsible for hearing disputes
2. Complainant: Person bringing the dispute
3. Respondent: Person responding to the complaint
4. Witnesses: Those providing testimony or evidence
5. Advisors: Those who support the council with expertise
6. Community Observers: Those who may witness proceedings for transparency

@ -0,0 +1,32 @@
- id: restorative
title: Restorative Justice Principles
componentId: principles
fieldId: principlesText
content: |
1. Focus on harm and needs of those affected
2. Address obligations resulting from harm
3. Use inclusive, collaborative processes
4. Involve all stakeholders (victims, offenders, community)
5. Work toward repairing harm and healing relationships
- id: transformative
title: Transformative Justice Principles
componentId: principles
fieldId: principlesText
content: |
1. Seek to address immediate safety, healing, and agency
2. Work to transform the conditions that allowed violence to occur
3. Build community accountability systems
4. Focus on community-based responses without relying on punitive systems
5. Acknowledge interconnection of all forms of violence
- id: consensus
title: Consensus-Based Principles
componentId: principles
fieldId: principlesText
content: |
1. All members have equal input in decision-making
2. Seek solutions that address everyone's fundamental concerns
3. Prioritize listening and understanding diverse perspectives
4. Work toward outcomes that all parties can accept
5. Focus on collaborative problem-solving over adversarial positions

65
data/modules/process.yaml Normal file

@ -0,0 +1,65 @@
- id: participant-facilitation
title: "Participant Facilitation"
componentId: facilitation
fieldId: facilitationText
content: |
The dispute process is facilitated by the participants themselves:
1. Participants take turns leading different parts of the conversation
2. A written guide provides structure to ensure all voices are heard
3. All participants receive basic training in productive dialogue techniques
4. Time limits and speaking guidelines ensure fair participation
5. Any participant can call for a break or reset if the process becomes unproductive
- id: peer-facilitation
title: "Peer Facilitation"
componentId: facilitation
fieldId: facilitationText
content: |
The dispute process is facilitated by peers from within the community:
1. A pool of trained peer facilitators is maintained within the community
2. Facilitators are selected who have no direct involvement in the dispute
3. Peer facilitators receive regular training in conflict resolution techniques
4. Typically, two peer facilitators work together on each case
5. Peer facilitators help maintain structure but do not make decisions
- id: trained-facilitation
title: "Trained Facilitation (e.g. mediator)"
componentId: facilitation
fieldId: facilitationText
content: |
The dispute process is facilitated by professionally trained mediators:
1. Professional mediators with formal certification lead the process
2. Mediators are selected from outside the community to ensure neutrality
3. Mediators have specific training in the type of conflict being addressed
4. The community maintains a roster of approved mediators
5. Mediators are paid for their services according to a pre-established rate
- id: facilitation-committee
title: "Facilitation Committee"
componentId: facilitation
fieldId: facilitationText
content: |
The dispute process is facilitated by a standing committee:
1. A dedicated committee of 5-7 members oversees all dispute processes
2. Committee members serve rotating terms and receive ongoing training
3. For each dispute, a subgroup of 2-3 committee members is assigned
4. Committee members with conflicts of interest must recuse themselves
5. The committee follows established procedures and maintains records of all cases
- id: nonviolent-communication
title: "Nonviolent Communication"
componentId: ground_rules
fieldId: groundRulesText
content: |
Our dispute process follows the principles of Nonviolent Communication (NVC):
1. Participants focus on observations rather than evaluations or judgments
2. Participants express feelings using "I" statements rather than blaming others
3. Participants identify needs that are or are not being met by the situation
4. Participants make clear, actionable requests rather than demands
5. Facilitators help participants translate judgmental language into NVC format
6. Active listening is practiced, with participants reflecting back what they've heard

@ -0,0 +1,41 @@
- id: participant-consensus
title: "Participant Consensus"
componentId: resolution_process
fieldId: resolutionProcessText
content: |
Resolution occurs through consensus of all involved participants:
1. Participants collaboratively develop possible solutions
2. All parties must agree to the final resolution
3. Consensus does not mean everyone's first choice, but a solution everyone can accept
4. Multiple rounds of proposal and revision may be necessary
5. Facilitators help test solutions against participants' stated needs
6. Once consensus is reached, the agreement is documented in writing
- id: facilitator-adjudication
title: "Facilitator Adjudication"
componentId: resolution_process
fieldId: resolutionProcessText
content: |
Resolution occurs through a decision made by the facilitator(s):
1. After full deliberation, the facilitator(s) makes a binding decision
2. The decision is based on community guidelines and the specifics of the case
3. Facilitators provide a written explanation of their decision and reasoning
4. All parties agree in advance to abide by the facilitator's decision
5. Decisions establish precedent for future similar cases
6. Decisions may be appealed only on specific grounds
- id: jury-adjudication
title: "Jury Adjudication"
componentId: resolution_process
fieldId: resolutionProcessText
content: |
Resolution occurs through a decision made by a jury of community peers:
1. A jury of 5-7 community members is randomly selected
2. Jury members receive an orientation to their role and responsibilities
3. After hearing all perspectives, the jury deliberates privately
4. The jury reaches a decision by two-thirds majority
5. The jury provides a written explanation of their decision
6. All community members agree in advance to respect jury decisions

34
data/stages/stages.yaml Normal file

@ -0,0 +1,34 @@
- id: intake
title: "Intake"
description: "How disputes enter the process"
order: 1
- id: process
title: "Process"
description: "How the dispute resolution operates"
order: 2
- id: assessment
title: "Assessment"
description: "Evaluating the state of the dispute"
order: 3
- id: deliberation
title: "Deliberation"
description: "Discussing the dispute"
order: 4
- id: resolution
title: "Resolution"
description: "Determining outcomes for the dispute"
order: 5
- id: appeal
title: "Appeal"
description: "Process for reconsidering dispute decisions"
order: 6
- id: delegation
title: "Delegation"
description: "Alternative processes when this one is inadequate"
order: 7

47
deploy.sh Executable file

@ -0,0 +1,47 @@
#!/bin/bash
# Dispute Protocol Deployment Script
# This script builds and deploys the dispute protocol site to a remote server
set -e
# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m' # No Color
# Configuration
SSH_USER=${1:-$USER}
SSH_HOST=${2:-"example.com"}
DEPLOY_PATH=${3:-"/var/www/dispute-protocol"}
BUILD_DIR="public"
# Check if Hugo is installed
if ! command -v hugo &> /dev/null; then
echo -e "${RED}Error: Hugo is not installed. Please install Hugo first.${NC}"
echo "Visit https://gohugo.io/installation/ for installation instructions."
exit 1
fi
echo -e "${YELLOW}Building site...${NC}"
hugo --minify
# Check if build succeeded
if [ ! -d "$BUILD_DIR" ]; then
echo -e "${RED}Error: Build failed. The '$BUILD_DIR' directory doesn't exist.${NC}"
exit 1
fi
echo -e "${YELLOW}Deploying to $SSH_USER@$SSH_HOST:$DEPLOY_PATH...${NC}"
# Create directory if it doesn't exist
ssh $SSH_USER@$SSH_HOST "mkdir -p $DEPLOY_PATH"
# Deploy using rsync
rsync -avz --delete $BUILD_DIR/ $SSH_USER@$SSH_HOST:$DEPLOY_PATH
echo -e "${GREEN}Deployment completed successfully!${NC}"
echo -e "${YELLOW}NOTE: Make sure your web server is configured correctly to serve the site.${NC}"
exit 0

1359
static/css/main.css Normal file

File diff suppressed because it is too large Load Diff

970
static/js/builder.js Normal file

@ -0,0 +1,970 @@
document.addEventListener('DOMContentLoaded', function() {
console.log('DOM loaded - initializing builder');
// Initialize preview mode state
let previewModeActive = false;
// Preview Mode Toggle
const previewToggle = document.getElementById('preview-toggle');
if (previewToggle) {
console.log('Preview toggle found, adding event listener');
document.addEventListener('click', function(e) {
// Hacky way: find any click anywhere near the toggle and check status
if (e.target.closest('.toggle-switch') || e.target.id === 'preview-toggle') {
// Give time for the checkbox to update
setTimeout(function() {
previewModeActive = previewToggle.checked;
console.log('Preview toggle changed to:', previewModeActive);
// Add a direct style change to visually confirm toggle works
document.querySelector('.toggle-label').style.color = previewModeActive ? 'blue' : '';
togglePreviewMode(previewModeActive);
}, 50);
}
});
} else {
console.error('Preview toggle element not found!');
}
// Function to toggle preview mode
function togglePreviewMode(active) {
console.log('Toggle preview mode called with active =', active);
// Use inline styles for preview mode
// This directly styles elements without relying on classes
const styleId = 'preview-mode-style';
let styleElement = document.getElementById(styleId);
if (active) {
// Create style element if it doesn't exist
if (!styleElement) {
styleElement = document.createElement('style');
styleElement.id = styleId;
document.head.appendChild(styleElement);
}
// Find all textareas with content to mark for display
const contentTextareas = [];
document.querySelectorAll('textarea').forEach(textarea => {
if (textarea.value && textarea.value.trim()) {
// Get the ID for later targeting
contentTextareas.push('#' + textarea.id);
// Mark parents for visibility
const field = textarea.closest('.field');
if (field) field.classList.add('has-content');
const component = textarea.closest('.component-card');
if (component) component.classList.add('has-content');
const stage = textarea.closest('.stage-section');
if (stage) stage.classList.add('has-content');
// Ensure stage is expanded
if (stage) {
const stageBody = stage.querySelector('.stage-body');
if (stageBody) stageBody.style.display = 'block';
}
}
});
// Apply direct CSS to create preview mode
styleElement.textContent = `
/* Hide module selectors and empty fields */
.module-selector { display: none !important; }
.field:not(.has-content) { display: none !important; }
/* Hide empty components and sections */
.component-card:not(.has-content) { display: none !important; }
.stage-section:not(.has-content) { display: none !important; }
/* Hide template selector */
.protocol-template-selector { display: none !important; }
/* Expand all sections */
.stage-body { display: block !important; }
/* Make textareas read-only appearance */
textarea {
border: none !important;
background-color: transparent !important;
padding: 0 !important;
min-height: unset !important;
height: auto !important;
resize: none !important;
pointer-events: none !important;
outline: none !important;
box-shadow: none !important;
}
/* Only show filled textareas */
textarea:not(${contentTextareas.join(',')}) {
display: none !important;
}
/* Clean styling for components */
.component-header {
background-color: transparent !important;
border-bottom: none !important;
padding-bottom: 0 !important;
}
.component-short-label { display: none !important; }
/* Improved typography for preview mode */
.component-header h3 {
font-size: 1.4rem !important;
margin-bottom: 1rem !important;
color: #000 !important;
border-bottom: 1px solid #eee !important;
padding-bottom: 0.5rem !important;
}
`;
// Replace textareas with divs for better display in preview mode
updatePreviewContent();
// Make other fields read-only
document.querySelectorAll('#community-name, #protocol-summary').forEach(el => {
el.setAttribute('readonly', 'readonly');
});
} else {
// Remove preview styles
if (styleElement) {
styleElement.textContent = '';
}
// Remove preview content divs and show textareas again
document.querySelectorAll('.preview-content').forEach(div => {
const textareaId = div.dataset.forTextarea;
if (textareaId) {
const textarea = document.getElementById(textareaId);
if (textarea) {
textarea.style.display = '';
}
}
div.parentNode.removeChild(div);
});
// Make fields editable again
document.querySelectorAll('textarea, #community-name, #protocol-summary').forEach(el => {
el.removeAttribute('readonly');
});
// Remove content markers
document.querySelectorAll('.has-content').forEach(el => {
el.classList.remove('has-content');
});
// Reset any display properties that were directly set
document.querySelectorAll('.stage-body').forEach(el => {
el.style.display = '';
});
}
}
// Function to mark components and stages that have content
function markComponentsWithContent() {
// First reset all markers
document.querySelectorAll('.has-content').forEach(el => {
el.classList.remove('has-content');
});
// Mark fields with content
document.querySelectorAll('textarea').forEach(textarea => {
if (textarea.value && textarea.value.trim()) {
const field = textarea.closest('.field');
if (field) field.classList.add('has-content');
const component = textarea.closest('.component-card');
if (component) component.classList.add('has-content');
const stage = textarea.closest('.stage-section');
if (stage) stage.classList.add('has-content');
}
});
// Show all expanded sections that have content
document.querySelectorAll('.stage-section.has-content').forEach(stage => {
const stageBody = stage.querySelector('.stage-body');
if (stageBody) {
stageBody.style.display = 'block';
const toggleBtn = stage.querySelector('.toggle-btn');
if (toggleBtn) {
toggleBtn.textContent = '-';
}
}
});
}
// Load module data
let allModules = {};
try {
// Check if moduleData is defined (from modules.js)
if (typeof moduleData !== 'undefined') {
allModules = moduleData;
console.log('Module data loaded from modules.js');
}
} catch (e) {
console.error('Error loading module data:', e);
allModules = {};
}
// Load and process template data
let templates = [];
try {
// Check if raw templates are defined (from templates.js)
if (typeof rawProtocolTemplates !== 'undefined' && typeof templateMapper !== 'undefined') {
console.log('Raw protocol templates loaded from templates.js');
// Process each template to use module references
rawProtocolTemplates.forEach(rawTemplate => {
const processedTemplate = templateMapper.convertTemplateToModules(rawTemplate, allModules);
templates.push(processedTemplate);
});
console.log('Processed templates to use module references:', templates);
}
} catch (e) {
console.error('Error processing protocol templates:', e);
templates = [];
}
// Protocol data structure
let protocol = {
metadata: {
communityName: "",
summary: ""
},
stages: {}
};
// DOM elements
const stageHeaders = document.querySelectorAll('.stage-header');
console.log('Found stage headers:', stageHeaders.length);
const stageContents = document.querySelectorAll('.stage-body');
console.log('Found stage bodies:', stageContents.length);
const moduleSelects = document.querySelectorAll('.module-select');
console.log('Found module selects:', moduleSelects.length);
const protocolTemplateSelect = document.getElementById('protocol-template');
const communityNameInput = document.getElementById('community-name');
const protocolSummaryTextarea = document.getElementById('protocol-summary');
const exportBtn = document.getElementById('export-btn');
const exportMdBtn = document.getElementById('export-md');
const exportPdfBtn = document.getElementById('export-pdf');
const exportJsonBtn = document.getElementById('export-json');
const importJsonInput = document.getElementById('import-json');
const importBtn = document.getElementById('import-btn');
// Populate protocol template select
if (protocolTemplateSelect && templates.length > 0) {
templates.forEach(template => {
const option = document.createElement('option');
option.value = template.id;
option.textContent = template.title;
protocolTemplateSelect.appendChild(option);
});
// Add template selection event handler
protocolTemplateSelect.addEventListener('change', function() {
const selectedTemplateId = this.value;
if (selectedTemplateId) {
// Find the selected template
const selectedTemplate = templates.find(t => t.id === selectedTemplateId);
if (selectedTemplate) {
console.log('Applying template:', selectedTemplate);
console.log('Selected template:', selectedTemplate.title);
// Reset protocol data while preserving metadata
protocol = {
metadata: {
communityName: communityNameInput.value || "",
summary: protocolSummaryTextarea.value || ""
},
stages: {},
templateId: selectedTemplate.id,
templateTitle: selectedTemplate.title,
templateDescription: selectedTemplate.description
};
// If summary is empty, use template description
if (!protocol.metadata.summary) {
protocolSummaryTextarea.value = selectedTemplate.description;
protocol.metadata.summary = selectedTemplate.description;
}
// Apply the template module references to the form
for (const stageId in selectedTemplate.moduleRefs) {
if (!protocol.stages[stageId]) {
protocol.stages[stageId] = {};
}
for (const componentId in selectedTemplate.moduleRefs[stageId]) {
if (!protocol.stages[stageId][componentId]) {
protocol.stages[stageId][componentId] = {};
}
for (const fieldId in selectedTemplate.moduleRefs[stageId][componentId]) {
const moduleId = selectedTemplate.moduleRefs[stageId][componentId][fieldId];
const textarea = document.getElementById(fieldId);
if (textarea) {
// Find the module with this ID
let moduleContent = '';
for (const category in allModules) {
const foundModule = allModules[category].find(m => m.id === moduleId);
if (foundModule) {
moduleContent = foundModule.content;
break;
}
}
// Apply the module content to the textarea
textarea.value = moduleContent;
// Store in protocol data
protocol.stages[stageId][componentId][fieldId] = moduleContent;
// If there's a template selector for this field, update it
const moduleSelector = document.querySelector(`select.module-select[data-field-id="${fieldId}"][data-component-id="${componentId}"]`);
if (moduleSelector) {
moduleSelector.value = moduleId;
}
}
}
}
}
// Expand all sections to show the populated content
stageContents.forEach(content => {
content.style.display = 'block';
const toggleBtn = content.parentElement.querySelector('.toggle-btn');
if (toggleBtn) {
toggleBtn.textContent = '-';
}
});
// Update preview mode if active
if (previewModeActive) {
markComponentsWithContent();
}
}
} else {
// Clear all fields if "Create Your Own" is selected
document.querySelectorAll('textarea').forEach(textarea => {
textarea.value = '';
});
// Reset protocol data
protocol = { stages: {} };
// Collapse all sections
stageContents.forEach(content => {
content.style.display = 'none';
const toggleBtn = content.parentElement.querySelector('.toggle-btn');
if (toggleBtn) {
toggleBtn.textContent = '+';
}
});
// Update preview mode if active
if (previewModeActive) {
markComponentsWithContent();
}
}
});
}
// Initialize all module selects
populateModuleSelects();
// Module selection handlers
moduleSelects.forEach(select => {
select.addEventListener('change', function() {
const fieldId = this.getAttribute('data-field-id');
const componentId = this.getAttribute('data-component-id');
const targetTextarea = document.getElementById(fieldId);
if (targetTextarea && this.value) {
// Find the selected module
for (const category in allModules) {
const selectedModule = allModules[category].find(m => m.id === this.value);
if (selectedModule) {
targetTextarea.value = selectedModule.content;
// Update protocol data
updateProtocolData();
// Update preview mode if active
if (previewModeActive) {
markComponentsWithContent();
}
break;
}
}
}
});
});
// Function to populate module select dropdowns
function populateModuleSelects() {
console.log('Populating module selects...');
console.log('Available module categories:', Object.keys(allModules));
// Debugging: Log all modules to check componentId and fieldId
console.log('All module mapping:');
for (const category in allModules) {
console.log(`Category: ${category}`);
allModules[category].forEach(module => {
console.log(` Module: ${module.id}, Component: ${module.componentId}, Field: ${module.fieldId}`);
});
}
moduleSelects.forEach(select => {
const fieldId = select.getAttribute('data-field-id');
const componentId = select.getAttribute('data-component-id');
console.log(`Processing module select for fieldId: ${fieldId}, componentId: ${componentId}`);
// Clear existing options except the first one
while (select.options.length > 1) {
select.remove(1);
}
// Find modules that match this field and component
let hasOptions = false;
// Always show select first - we'll hide it later if no options found
select.closest('.module-selector').style.display = 'flex';
// Check for case matching issues and missing references
for (const category in allModules) {
let exactMatches = allModules[category].filter(m =>
m.fieldId === fieldId && m.componentId === componentId
);
let caseInsensitiveMatches = allModules[category].filter(m =>
m.fieldId.toLowerCase() === fieldId.toLowerCase() &&
m.componentId.toLowerCase() === componentId.toLowerCase() &&
!exactMatches.includes(m)
);
if (caseInsensitiveMatches.length > 0) {
console.warn(`Found ${caseInsensitiveMatches.length} case-insensitive matches for ${componentId}/${fieldId}. Consider fixing these module references.`);
// Add case-insensitive matches to the collection
caseInsensitiveMatches.forEach(module => {
// Create a copy with corrected references
const correctedModule = {
...module,
componentId: componentId,
fieldId: fieldId
};
// Add to the exact matches
exactMatches.push(correctedModule);
});
}
if (exactMatches.length > 0) {
console.log(`Found ${exactMatches.length} modules in category ${category} for ${componentId}/${fieldId}`);
hasOptions = true;
// Don't use option groups - add options directly to the select
// This avoids showing category labels which can be confusing
exactMatches.forEach(module => {
const option = document.createElement('option');
option.value = module.id;
// Use the module title directly from the definition
// This relies on proper module titles being defined in modules.js
option.textContent = module.title;
// Add directly to select instead of to a group
select.appendChild(option);
});
}
}
// If no modules found, hide the selector
if (!hasOptions) {
console.log(`No modules found for ${componentId}/${fieldId}, hiding selector`);
select.closest('.module-selector').style.display = 'none';
}
});
}
// Update protocol data from form inputs
function updateProtocolData() {
// Update metadata
protocol.metadata = {
communityName: communityNameInput.value || "",
summary: protocolSummaryTextarea.value || ""
};
// Reset the stages data
protocol.stages = {};
// Get all textareas and their values
const textareas = document.querySelectorAll('textarea');
textareas.forEach(textarea => {
const fieldId = textarea.id;
const fieldValue = textarea.value;
// Skip empty fields
if (!fieldValue || !fieldValue.trim()) return;
// Find the component and stage for this field
const componentCard = textarea.closest('.component-card');
if (!componentCard) return;
const componentId = componentCard.id.replace('component-', '');
const stageSection = textarea.closest('.stage-section');
if (!stageSection) return;
const stageId = stageSection.id.replace('stage-', '');
// Initialize stage and component if they don't exist
if (!protocol.stages[stageId]) {
protocol.stages[stageId] = {};
}
if (!protocol.stages[stageId][componentId]) {
protocol.stages[stageId][componentId] = {};
}
// Set the field value
protocol.stages[stageId][componentId][fieldId] = fieldValue;
});
// If a template is selected, preserve the template information
const selectedTemplateId = protocolTemplateSelect ? protocolTemplateSelect.value : '';
if (selectedTemplateId) {
const selectedTemplate = templates.find(t => t.id === selectedTemplateId);
if (selectedTemplate) {
protocol.templateId = selectedTemplateId;
protocol.templateTitle = selectedTemplate.title;
protocol.templateDescription = selectedTemplate.description;
}
}
// Remove empty components and stages
for (const stageId in protocol.stages) {
// Check if stage has any non-empty components
const stageComponents = protocol.stages[stageId];
let stageHasContent = false;
for (const componentId in stageComponents) {
// Check if component has any fields
const component = stageComponents[componentId];
const fieldCount = Object.keys(component).length;
if (fieldCount > 0) {
stageHasContent = true;
} else {
// Remove empty component
delete stageComponents[componentId];
}
}
// If stage has no content, remove it
if (!stageHasContent) {
delete protocol.stages[stageId];
}
}
}
// Export to Markdown
exportMdBtn.addEventListener('click', function(e) {
e.preventDefault();
updateProtocolData();
// Use community name if available, otherwise default
const communityName = protocol.metadata.communityName || "Community";
let markdown = `# ${communityName} Dispute Protocol\n\n`;
// Include protocol summary if available
if (protocol.metadata.summary) {
markdown += `${protocol.metadata.summary}\n\n`;
markdown += '---\n\n';
}
// Include template information if a template was used
if (protocol.templateTitle) {
markdown += `**Template Used:** ${protocol.templateTitle}\n\n`;
markdown += '---\n\n';
}
// Loop through the stages in order
stageHeaders.forEach(header => {
const stageId = header.getAttribute('data-stage');
const stageName = header.querySelector('h2').textContent;
let stageContent = '';
let hasContent = false;
// Get components for this stage
const stageComponents = protocol.stages[stageId];
if (stageComponents) {
// Loop through components
for (const componentId in stageComponents) {
const componentCard = document.getElementById(`component-${componentId}`);
if (componentCard) {
const componentName = componentCard.querySelector('h3').textContent;
let componentContent = '';
let componentHasContent = false;
// Loop through fields
for (const fieldId in stageComponents[componentId]) {
const fieldValue = stageComponents[componentId][fieldId];
// Skip empty fields
if (fieldValue && fieldValue.trim()) {
const fieldLabel = document.querySelector(`label[for="${fieldId}"]`).textContent;
componentContent += `#### ${fieldLabel}\n\n${fieldValue}\n\n`;
componentHasContent = true;
hasContent = true;
}
}
// Only add component if it has content
if (componentHasContent) {
stageContent += `### ${componentName}\n\n${componentContent}`;
}
}
}
}
// Only add stage if it has content
if (hasContent) {
markdown += `## ${stageName}\n\n${stageContent}`;
}
});
// Create and download the file
downloadFile('community_dispute_protocol.md', markdown);
});
// Export to PDF
exportPdfBtn.addEventListener('click', function(e) {
e.preventDefault();
updateProtocolData();
// Create a styled HTML version for PDF export
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
let yPos = 20;
// Use community name if available, otherwise default
const communityName = protocol.metadata.communityName || "Community";
// Add title
doc.setFontSize(18);
doc.text(`${communityName} Dispute Protocol`, 105, yPos, { align: 'center' });
yPos += 15;
// Add protocol summary if available
if (protocol.metadata.summary) {
doc.setFontSize(12);
const summaryLines = doc.splitTextToSize(protocol.metadata.summary, 180);
doc.text(summaryLines, 14, yPos);
yPos += summaryLines.length * 7 + 8;
}
// Add template info if available
if (protocol.templateTitle) {
doc.setFontSize(10);
doc.text(`Template Used: ${protocol.templateTitle}`, 14, yPos);
yPos += 10;
}
// Loop through the stages
stageHeaders.forEach(header => {
const stageId = header.getAttribute('data-stage');
const stageName = header.querySelector('h2').textContent;
let stageHasContent = false;
let stageStartYPos = yPos;
// Save current position to add stage heading later if content is found
if (yPos > 250) {
doc.addPage();
stageStartYPos = 20;
yPos = 20;
}
// Skip stage heading for now - we'll add it if the stage has content
let currentYPos = stageStartYPos + 10; // Space for the heading
// Get components for this stage
const stageComponents = protocol.stages[stageId];
if (stageComponents) {
// Loop through components
for (const componentId in stageComponents) {
const componentCard = document.getElementById(`component-${componentId}`);
if (componentCard) {
let componentHasContent = false;
let componentStartYPos = currentYPos;
// Check for page break
if (currentYPos > 250) {
doc.addPage();
componentStartYPos = 20;
currentYPos = 20;
}
// Skip component heading for now - add if it has content
const componentFieldStartYPos = componentStartYPos + 8;
let fieldYPos = componentFieldStartYPos;
const componentName = componentCard.querySelector('h3').textContent;
// Loop through fields
for (const fieldId in stageComponents[componentId]) {
const fieldValue = stageComponents[componentId][fieldId];
// Skip empty fields
if (fieldValue && fieldValue.trim()) {
const fieldLabel = document.querySelector(`label[for="${fieldId}"]`).textContent;
// Add page break if needed
if (fieldYPos > 250) {
doc.addPage();
fieldYPos = 20;
}
// We have content - if this is the first content in the component,
// add the component heading
if (!componentHasContent) {
componentHasContent = true;
stageHasContent = true;
// If this is the first content in the stage, add the stage heading
if (!stageHasContent) {
doc.setFontSize(16);
doc.text(stageName, 14, stageStartYPos);
}
// Add component heading
doc.setFontSize(14);
doc.text(componentName, 14, componentStartYPos);
}
// Add field heading
doc.setFontSize(12);
doc.text(fieldLabel, 14, fieldYPos);
fieldYPos += 6;
// Split the text into lines to handle wrapping
const textLines = doc.splitTextToSize(fieldValue, 180);
// Add field content
doc.setFontSize(10);
doc.text(textLines, 14, fieldYPos);
fieldYPos += textLines.length * 5 + 8;
}
}
// Update current Y position if component had content
if (componentHasContent) {
currentYPos = fieldYPos;
}
}
}
}
// Update the overall Y position if stage had content
if (stageHasContent) {
yPos = currentYPos;
}
});
// Save the PDF
doc.save('community_dispute_protocol.pdf');
});
// Export to JSON
exportJsonBtn.addEventListener('click', function(e) {
e.preventDefault();
updateProtocolData();
const jsonData = JSON.stringify(protocol, null, 2);
downloadFile('community_dispute_protocol.json', jsonData);
});
// Import from JSON
importBtn.addEventListener('click', function() {
importJsonInput.click();
});
importJsonInput.addEventListener('change', function(event) {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(e) {
try {
const importedProtocol = JSON.parse(e.target.result);
protocol = importedProtocol;
// Populate metadata fields if present
if (protocol.metadata) {
if (protocol.metadata.communityName) {
communityNameInput.value = protocol.metadata.communityName;
}
if (protocol.metadata.summary) {
protocolSummaryTextarea.value = protocol.metadata.summary;
}
}
// Populate the component fields with the imported data
for (const stageId in protocol.stages) {
for (const componentId in protocol.stages[stageId]) {
for (const fieldId in protocol.stages[stageId][componentId]) {
const textarea = document.getElementById(fieldId);
if (textarea) {
textarea.value = protocol.stages[stageId][componentId][fieldId];
}
}
}
}
// If the imported protocol has template information, select that template
if (protocol.templateId && protocolTemplateSelect) {
protocolTemplateSelect.value = protocol.templateId;
// Update template description
if (protocol.templateDescription && templateDescription) {
templateDescription.textContent = protocol.templateDescription;
templateDescription.style.display = 'block';
}
// Expand all sections
stageContents.forEach(content => {
content.style.display = 'block';
const toggleBtn = content.parentElement.querySelector('.toggle-btn');
if (toggleBtn) {
toggleBtn.textContent = '-';
}
});
} else {
// If no template, reset the template selector
if (protocolTemplateSelect) {
protocolTemplateSelect.value = '';
}
if (templateDescription) {
templateDescription.textContent = '';
templateDescription.style.display = 'none';
}
}
// Update preview mode if active
if (previewModeActive) {
markComponentsWithContent();
}
alert('Protocol imported successfully!');
} catch (error) {
alert('Failed to import protocol. Invalid JSON format.');
console.error(error);
}
};
reader.readAsText(file);
}
});
// Helper function to download a file
function downloadFile(filename, content) {
const element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(content));
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
// Save data when inputs change
document.querySelectorAll('textarea').forEach(textarea => {
textarea.addEventListener('input', function() {
updateProtocolData();
// Update preview mode if active
if (previewModeActive) {
markComponentsWithContent();
}
});
});
// Function to update preview content
function updatePreviewContent() {
// First, clear any existing preview divs
document.querySelectorAll('.preview-content').forEach(div => {
div.parentNode.removeChild(div);
});
// Show all textareas again
document.querySelectorAll('textarea').forEach(textarea => {
textarea.style.display = '';
});
// Then create new preview divs for all textareas with content
document.querySelectorAll('textarea').forEach(textarea => {
if (textarea.value && textarea.value.trim()) {
// Create a div to replace the textarea for preview
const previewDiv = document.createElement('div');
previewDiv.className = 'preview-content';
previewDiv.textContent = textarea.value;
previewDiv.dataset.forTextarea = textarea.id;
// Hide the textarea and insert the div
textarea.style.display = 'none';
textarea.parentNode.insertBefore(previewDiv, textarea.nextSibling);
}
});
}
// Update preview content when preview mode is toggled
document.getElementById('preview-toggle').addEventListener('change', function() {
if (this.checked) {
// Wait for the preview mode styles to apply, then update content
setTimeout(updatePreviewContent, 100);
}
});
// Update preview content when module content changes
document.querySelectorAll('.module-select').forEach(select => {
select.addEventListener('change', function() {
setTimeout(() => {
if (document.getElementById('preview-toggle').checked) {
updatePreviewContent();
}
}, 100);
});
});
// Update preview content on window resize
window.addEventListener('resize', function() {
if (document.getElementById('preview-toggle').checked) {
updatePreviewContent();
}
});
console.log('Builder initialization complete');
});

1997
static/js/data/modules.js Normal file

File diff suppressed because it is too large Load Diff

@ -0,0 +1,274 @@
// This file handles mapping raw template content to module IDs
// It's used to convert templates that use raw content to use module references instead
// Helper function to find the best matching module for a given content
function findBestMatchingModule(content, componentId, fieldId, modules) {
// If content is empty, return null
if (!content || !content.trim()) {
return null;
}
// Check if there are modules for this component and field
let matchingModules = [];
for (const category in modules) {
const categoryModules = modules[category].filter(m =>
m.componentId === componentId && m.fieldId === fieldId
);
if (categoryModules.length > 0) {
matchingModules = matchingModules.concat(categoryModules);
}
}
if (matchingModules.length === 0) {
return null;
}
// Find the most similar module based on content
let bestMatch = null;
let highestSimilarity = 0;
matchingModules.forEach(module => {
// Simple similarity metric: count of matching words
const contentWords = content.toLowerCase().split(/\s+/);
const moduleWords = module.content.toLowerCase().split(/\s+/);
// Count matching words
let matchCount = 0;
contentWords.forEach(word => {
if (moduleWords.includes(word)) {
matchCount++;
}
});
// Calculate similarity as percentage of matching words
const similarity = matchCount / Math.max(contentWords.length, moduleWords.length);
if (similarity > highestSimilarity) {
highestSimilarity = similarity;
bestMatch = module;
}
});
// Only return a match if similarity is above threshold
return highestSimilarity > 0.5 ? bestMatch : null;
}
// Convert a raw template to use module references
function convertTemplateToModules(template, modules) {
const result = {
id: template.id,
title: template.title,
description: template.description,
moduleRefs: {}
};
// Go through each stage, component, and field
for (const stageId in template.data.stages) {
if (!result.moduleRefs[stageId]) {
result.moduleRefs[stageId] = {};
}
for (const componentId in template.data.stages[stageId]) {
if (!result.moduleRefs[stageId][componentId]) {
result.moduleRefs[stageId][componentId] = {};
}
for (const fieldId in template.data.stages[stageId][componentId]) {
const content = template.data.stages[stageId][componentId][fieldId];
// Find best matching module
const matchingModule = findBestMatchingModule(content, componentId, fieldId, modules);
if (matchingModule) {
// Store module reference
result.moduleRefs[stageId][componentId][fieldId] = matchingModule.id;
} else {
// If no matching module, create a custom one with this content
const customId = `custom-${template.id}-${componentId}-${fieldId}`;
// Add to appropriate module category or create a new one
const categoryKey = stageId; // Use stage ID as category
if (!modules[categoryKey]) {
modules[categoryKey] = [];
}
// Check if custom module already exists
const existingModule = modules[categoryKey].find(m =>
m.id === customId && m.componentId === componentId && m.fieldId === fieldId
);
if (!existingModule) {
// Create a concise but descriptive module title
let moduleTitle = "";
// Helper function to create more meaningful component-based titles
function getComponentBasedTitle() {
// Get a human-readable form of the component and field IDs
const componentName = componentId.split('_')
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ');
const fieldName = fieldId.replace(/([A-Z])/g, ' $1')
.replace(/Text$/, '')
.replace(/Id$/, '')
.split(/[_\s]/)
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ')
.trim();
// Find core theme from content
const lines = content.split('\n').map(l => l.trim()).filter(l => l);
// Try to find a descriptive keyword from the first paragraph
const firstPara = lines[0];
const keywords = firstPara.match(/\b(restorative|collaborative|consensus|transformative|community|circle|mediation|third-party|written|verbal|facilitated|direct|multi-channel|needs|impact|harm|assessment|visual|phased|panel|independent|detailed|criteria|values|commitments|skills)\b/gi) || [];
if (keywords.length > 0) {
const keywordTitle = keywords[0].charAt(0).toUpperCase() + keywords[0].slice(1).toLowerCase();
return `${keywordTitle} ${fieldName || componentName}`;
}
// Check for approach/model/process keywords
const approachMatch = content.match(/\b(approach|model|process|method|system|framework|practice)\b/i);
if (approachMatch) {
// Get adjectives before the approach word
const contentBefore = content.substring(0, approachMatch.index).trim();
const lastWords = contentBefore.split(/\s+/).slice(-2);
if (lastWords.length > 0 && lastWords[0].length > 3) {
const adjective = lastWords.join(' ');
return `${adjective.charAt(0).toUpperCase() + adjective.slice(1)} ${approachMatch[0]}`;
}
}
return `${componentName} ${fieldName}`.trim();
}
// Analyze content structure
const firstSentence = content.split(/[.!?:]\s+/)[0].trim().replace(/^[^a-zA-Z0-9]*/, '');
const lines = content.split('\n').map(l => l.trim()).filter(l => l);
const hasNumberedList = lines.some(line => line.match(/^[0-9]\.\s+/));
// Strategy 1: Look for purpose statements (often after "Our", "The", etc.)
const purposeMatch = content.match(/\b(Our|The|This|A)\s+([^.!?:]+)(is|uses|follows|provides|ensures|helps)\s+/i);
if (purposeMatch) {
const purpose = purposeMatch[2].trim();
if (purpose.length > 5 && purpose.length < 40) {
moduleTitle = purpose.charAt(0).toUpperCase() + purpose.slice(1);
}
}
// Strategy 2: Check for clear format identifiers in first line
if (!moduleTitle && lines.length > 0) {
const firstLine = lines[0];
if (firstLine.includes('approach') ||
firstLine.includes('model') ||
firstLine.includes('process') ||
firstLine.includes('system')) {
moduleTitle = firstLine;
}
}
// Strategy 3: Title with colon format
if (!moduleTitle && firstSentence.includes(':')) {
const beforeColon = firstSentence.split(':')[0].trim();
if (beforeColon.length > 5 && beforeColon.length < 40) {
moduleTitle = beforeColon.replace(/^(The|Our|This)\s+/i, '');
}
}
// Strategy 4: Numbered list with key concept
if (!moduleTitle && hasNumberedList) {
// Get the first numbered point - often a good summary
for (let i = 0; i < lines.length && i < 5; i++) {
const line = lines[i];
if (line.match(/^[0-9]\.\s+/)) {
let pointText = line.replace(/^[0-9]\.\s+/, '');
// Extract core concept (first 3-5 words)
const words = pointText.split(/\s+/);
if (words.length > 2) {
pointText = words.slice(0, Math.min(5, words.length)).join(' ');
}
if (pointText.length > 5 && pointText.length < 40) {
moduleTitle = pointText;
break;
}
}
}
}
// Strategy 5: Extract key theme based on field purpose
if (!moduleTitle) {
// Use component and field context to generate meaningful title
moduleTitle = getComponentBasedTitle();
}
// Cleanup and formatting
// Remove stopwords from beginning
moduleTitle = moduleTitle.replace(/^(The|Our|This|An|A)\s+/i, '');
// Capitalize first letter
moduleTitle = moduleTitle.charAt(0).toUpperCase() + moduleTitle.slice(1);
// Ensure reasonable length
if (moduleTitle.length > 40) {
const words = moduleTitle.split(/\s+/);
moduleTitle = words.slice(0, 4).join(' ');
}
// Remove any duplicate words
const words = moduleTitle.split(/\s+/);
const uniqueWords = [];
for (const word of words) {
if (!uniqueWords.includes(word)) {
uniqueWords.push(word);
}
}
moduleTitle = uniqueWords.join(' ');
// If all else fails, create a descriptive title based on component and content
if (moduleTitle.length < 5) {
const componentKey = componentId.split('_')[0];
const componentName = componentKey.charAt(0).toUpperCase() + componentKey.slice(1);
// Find a distinctive word from content
const contentWords = content.split(/\s+/)
.filter(word =>
word.length > 4 &&
!['process', 'option', 'through', 'their', 'these', 'those', 'about', 'which', 'would', 'could', 'should'].includes(word.toLowerCase())
);
const distinctiveWord = contentWords[0] || 'Standard';
moduleTitle = distinctiveWord.charAt(0).toUpperCase() + distinctiveWord.slice(1) + " " + componentName;
}
// Create new custom module with concise title
modules[categoryKey].push({
id: customId,
title: moduleTitle,
componentId: componentId,
fieldId: fieldId,
content: content
});
}
result.moduleRefs[stageId][componentId][fieldId] = customId;
}
}
}
}
return result;
}
// Export the mapper functions
const templateMapper = {
findBestMatchingModule,
convertTemplateToModules
};
// Make sure it's available globally
window.templateMapper = templateMapper;

905
static/js/data/templates.js Normal file

@ -0,0 +1,905 @@
// Protocol templates
// This file contains the raw template data
// The builder.js code will convert these to use module references
const rawProtocolTemplates = [
{
id: "restorative-justice",
title: "Restorative Justice",
description: "A collaborative process that focuses on healing relationships and repairing harm rather than punitive measures",
data: {
stages: {
intake: {
process_start: {
processStartText: "The restorative justice process begins when anyone in the community submits a request form indicating harm that needs to be addressed. This form asks for a brief description of what happened, who was involved, and what the person hopes might come from the process. A restorative justice coordinator acknowledges receipt within 24 hours and begins initial conversations with the person who submitted the request."
},
rules_access: {
rulesAccessText: "Our community principles and restorative process guidelines are publicly available in multiple formats: a printed handbook in common spaces, an accessible online document, and visual displays in community gathering areas. New members receive an orientation to these principles when they join the community."
},
information_access: {
informationAccessText: "Information about specific restorative processes is shared only with those directly involved. Statistical information about types of harm addressed (without identifying details) is shared annually to help the community learn and grow. The circle keeper maintains confidential records that are accessible only to them and the participants in each case."
},
participant_inclusion: {
participantInclusionText: "Other participants are brought into the process through thoughtful invitation rather than formal notification. The restorative coordinator reaches out personally to each identified participant, explains the process, answers questions, and extends an invitation to participate. They emphasize that the goal is healing rather than blame."
},
participation_requirement: {
participationRequirementText: "Participation in restorative justice processes is entirely voluntary. We believe that genuine healing and transformation can only come from willing engagement. If someone chooses not to participate, we respect that decision and explore other paths forward with the person who initiated the request."
},
participation_commitments: {
participationCommitmentsText: "Participants in restorative processes commit to: 1) Speaking honestly from their own experience, 2) Listening deeply to others without interruption, 3) Maintaining confidentiality about what is shared, 4) Working toward understanding before solutions, 5) Following through on agreements they make, and 6) Engaging with respect and care for themselves and others throughout the process."
}
},
process: {
preparation: {
preparationText: "Before any circle gathering, the circle keeper meets individually with each participant to build relationship, explain the process in detail, answer questions, address concerns, and help the person prepare what they might want to share. These preparation meetings help establish trust and safety for the full circle process."
},
place: {
placeText: "Restorative circles take place in a neutral, comfortable space with natural light and privacy. Chairs are arranged in a perfect circle with no tables or barriers. A centerpiece with meaningful objects (plants, stones, candles, etc.) creates a focal point. The space is prepared thoughtfully to create a sense of safety and importance."
},
facilitation: {
facilitationText: "The dispute process uses a restorative circle approach:\n\n1. A trained circle keeper facilitates but does not control the process\n2. All participants sit in a circle with no tables or barriers between them\n3. A talking piece is passed around the circle to ensure each person can speak without interruption\n4. Multiple rounds allow for deepening the conversation and moving toward resolution\n5. The circle process follows indigenous wisdom traditions adapted for contemporary contexts\n6. The circle keeper prepares participants individually before the full circle gathering"
},
communication: {
communicationText: "Communication in restorative circles follows these guidelines: 1) Speak from the heart about your own experience, 2) Listen from the heart without planning your response, 3) Speak with respect and without blame, 4) Share what's true for you in the moment, 5) Be mindful of time so everyone can share, 6) Honor the talking piece - only the person holding it may speak, 7) Respect the confidentiality of what is shared."
},
participation: {
participationText: "A restorative circle typically includes: 1) The person who experienced harm, 2) The person who caused harm, 3) Community members or loved ones who support each primary participant, 4) Community members affected by the situation, and 5) The circle keeper. Everyone participates as an equal in the circle, though the needs of those most affected guide the process."
},
documentation: {
documentationText: "The circle keeper takes minimal notes during the process to maintain presence. The agreements reached are documented clearly in a format agreed upon by all participants. These written agreements are shared only with participants and include specific actions, timelines, and follow-up plans."
}
},
assessment: {
situation: {
situationText: "The situation is assessed through a harm and needs framework:\n\n1. Each participant describes what happened from their perspective\n2. Participants identify how they have been affected or harmed\n3. Underlying needs that weren't met are identified\n4. The impact on relationships and the wider community is explored\n5. The assessment focuses on understanding rather than blame\n6. This approach creates a foundation for addressing specific harms"
},
stage_of_conflict: {
stageOfConflictText: "The circle keeper assesses the readiness of all parties for a restorative process. They consider: 1) Whether those who caused harm acknowledge their responsibility, 2) The emotional state and safety needs of those who experienced harm, 3) The willingness of all parties to work toward repair, and 4) Any power dynamics that might affect the process. This assessment helps determine timing and structure."
},
needs: {
needsText: "During preparation and circle meetings, participants identify their underlying needs related to the situation. These might include needs for safety, acknowledgment, understanding, accountability, belonging, repair, or healing. The circle process helps surface these needs and explore how they might be met through the restorative process."
},
evidence: {
evidenceText: "Restorative processes focus more on impact and experience than evidence in a traditional sense. Participants share their direct experiences and how they were affected. When factual disagreements arise, the circle keeper helps the group find shared understanding without determining absolute truth. The focus remains on healing rather than proof."
},
jurisdiction: {
jurisdictionText: "Our restorative justice process is appropriate for most interpersonal harms and conflicts within our community. For situations involving ongoing safety risks, legal violations that require reporting, or when participants are unwilling to acknowledge basic responsibility for harm, the process may be adapted or alternative resources recommended."
}
},
deliberation: {
information_gathering: {
informationGatheringText: "Information emerges organically through circle sharing. The process begins with establishing relationships and context before directly addressing the harm. Multiple rounds of the talking piece allow deeper layers of the situation to surface. As understanding develops, the circle considers what needs to happen to make things right."
},
brainstorming: {
brainstormingText: "Once the impact of the situation is well understood, the circle moves into generating ideas for repair and moving forward. Everyone contributes possibilities without immediate evaluation. The keeper encourages creative thinking that addresses the specific harms and needs identified earlier in the process."
},
discussion: {
discussionText: "The circle discusses potential solutions through a structured process: 1) Each idea is considered in terms of how it addresses identified harms and needs, 2) Those most affected by the situation speak to what would help them move forward, 3) The group refines ideas based on what's practical and meaningful, 4) The keeper helps the group move toward consensus on actions for repair and healing."
},
deliberation_format: {
deliberationFormatText: "Deliberation happens within the circle format, guided by a series of thoughtful questions from the keeper. The talking piece continues to structure the conversation. The process may include multiple circle sessions with time for reflection between meetings. Deliberation concludes when the group reaches shared agreements about how to move forward."
}
},
resolution: {
decision_making: {
decisionMakingText: "Decisions in restorative processes are made by consensus of all participants. The circle keeper helps test potential agreements to ensure everyone can support them. If perfect agreement isn't possible, the keeper helps craft a solution that addresses core needs while respecting individual boundaries about what people are willing to do."
},
outcomes: {
outcomesText: "Restorative outcomes typically include: 1) Acknowledgment of the harm that occurred, 2) Specific actions to repair damage or address impacts, 3) Commitments to changed behavior in the future, 4) Healing rituals or symbolic acts, 5) Plans for rebuilding trust and relationships over time, and 6) Community support mechanisms to help implement agreements."
},
agreement: {
agreementText: "All resolutions result in a collaborative responsibility plan:\n\n1. The plan details specific actions to repair harm\n2. Each participant has clear responsibilities for making things right\n3. The plan includes timeline commitments for implementation\n4. Support mechanisms are built in to help participants fulfill their commitments\n5. The plan may include ongoing relationship-building activities\n6. All participants sign the agreement and receive a copy\n7. The agreement focuses on healing and moving forward rather than punishment"
},
follow_up: {
followUpText: "The circle keeper schedules a follow-up circle 3-4 weeks after agreements are made to check on progress, celebrate steps taken, and address any challenges. Additional follow-up may happen at 3 months and 6 months depending on the situation. These follow-ups provide accountability and ongoing support for the healing process."
},
announcement: {
announcementText: "The outcomes of restorative processes remain confidential to the participants unless they specifically agree to share information with the broader community. When information is shared, it focuses on lessons learned and community needs rather than personal details."
}
},
appeal: {
criteria: {
criteriaText: "Restorative processes can be reopened if: 1) Agreements aren't being fulfilled despite good faith efforts, 2) New information emerges that significantly changes understanding of the situation, 3) Additional harms occur related to the original situation, or 4) The process was completed but healing remains incomplete."
},
appeal_process: {
appealProcessText: "To revisit a completed process, any participant can contact the circle keeper to request a follow-up circle. The keeper reaches out to all original participants to check willingness to reconvene. If everyone agrees, a new circle is scheduled focusing specifically on the issues that need further attention."
},
appeal_deliberation: {
appealDeliberationText: "The reconvened circle follows the same structured format as the original process but with focused attention on the specific concerns that led to reopening the case. The circle acknowledges progress already made while addressing outstanding issues or new insights."
},
appeal_resolution: {
appealResolutionText: "The follow-up circle develops revised or additional agreements addressing the newly identified needs. These amendments are added to the original agreement with clear timelines for implementation and additional follow-up as needed."
}
},
delegation: {
criteria: {
criteriaText: "The restorative process may be inappropriate when: 1) There are immediate safety concerns that need addressing first, 2) One or more key participants are unwilling to engage, 3) The harm involves legal violations requiring formal intervention, 4) The situation involves complex systems beyond interpersonal harm, or 5) Previous restorative attempts have not led to meaningful change."
},
delegation_process: {
delegationProcessText: "If restorative justice isn't the right fit, the circle keeper works with participants to identify more appropriate resources. They provide warm referrals to other services like mediation, therapy, organizational change processes, or when necessary, formal authorities. The transition includes clear communication about why delegation is recommended."
},
delegation_authority: {
delegationAuthorityText: "Our community maintains relationships with professional mediators, conflict coaches, mental health providers, social workers, and when needed, legal professionals. We have established referral protocols with each of these resources and provide financial assistance when cost would be a barrier to accessing needed support."
}
}
}
}
},
{
id: "transformative-justice",
title: "Transformative Justice",
description: "A process that addresses immediate harm while working to transform the conditions that allowed harm to occur",
data: {
stages: {
intake: {
process_start: {
processStartText: "The transformative justice process begins when a community member reaches out to the transformative justice collective with a concern about harm. This initial contact can be through a secure online form, a phone line, or direct conversation with a collective member. Within 48 hours, two collective members are assigned to do an initial assessment and begin conversations with the person who raised the concern."
},
rules_access: {
rulesAccessText: "Our community agreements, values, and transformative justice framework are documented in accessible formats including a community handbook (print and digital), visual materials, audio resources, and multilingual versions. These resources clearly distinguish between aspirational values and concrete practices. All members participate in regular workshops to review and update these materials."
},
information_access: {
informationAccessText: "Information is shared based on a consent-based model. Those directly involved determine what information is shared beyond the immediate process. The transformative justice collective maintains secure records that include agreements made and lessons learned, but not sensitive personal details. Pattern-level information about types of harm addressed informs community education while protecting confidentiality."
},
participant_inclusion: {
participantInclusionText: "People are brought into the process through intentional outreach by the facilitators, who explain the transformative approach and how it differs from punitive models. Key stakeholders include those directly harmed, those who caused harm, support people for both parties, and community members affected by or contributing to the situation. Each person receives individual preparation before group sessions."
},
participation_requirement: {
participationRequirementText: "Participation is voluntary but strongly encouraged as part of our community commitments. We recognize that meaningful accountability cannot be forced. However, if someone chooses not to participate directly, the process may continue with those who are willing, focusing on community support for those harmed and addressing systemic factors that contributed to the harm."
},
participation_commitments: {
participationCommitmentsText: "Participants commit to: 1) Engaging honestly in examining harm and its impacts, 2) Considering both individual and collective dimensions of accountability, 3) Respecting confidentiality boundaries established by the group, 4) Working to understand systemic factors beyond individual actions, 5) Contributing to implementation of agreements, and 6) Participating in follow-up and ongoing learning."
}
},
prepare: {
principles: {
principlesText: "Our dispute resolution process is guided by these transformative justice principles:\n\n1. Address immediate harm between individuals\n2. Connect individual instances of harm to broader social patterns\n3. Transform the conditions that allowed harm to occur\n4. Build community accountability systems without relying on punitive measures\n5. Center the needs of those most impacted while inviting those who caused harm into accountability\n6. Develop collective strategies for healing, resilience, and safety\n7. Work toward long-term cultural and structural change"
},
values: {
valuesText: "Our transformative justice work is rooted in these core values: 1) Liberation - working toward freedom from all forms of oppression, 2) Accountability without punishment, 3) Collective responsibility for community well-being, 4) Radical honesty about impacts and conditions, 5) Compassion for all involved, including those who have caused harm, 6) Faith in people's capacity to transform, 7) Commitment to sustainable, long-term change."
},
agreements: {
agreementsText: "Participants in the transformative justice process agree to: 1) Approach the process with a willingness to examine personal and collective relationships to systems of power, 2) Listen to understand rather than defend, 3) Be open to feedback about impact regardless of intent, 4) Recognize that transformative work takes time and commitment, 5) Balance accountability with care for self and others."
}
},
process: {
preparation: {
preparationText: "Preparation includes multiple one-on-one conversations with each participant before any group sessions. During these meetings, facilitators build relationship, explain the process, address concerns, provide educational resources about transformative justice, and help participants identify their needs and capacities. Support people are oriented to their role in the process."
},
place: {
placeText: "Meetings take place in spaces that feel safe, accessible, and comfortable for all participants. The environment is checked for potential triggers or barriers. Sessions may move between private and community spaces depending on the phase of work. Sometimes neutral territory outside the community is used to provide perspective."
},
facilitation: {
facilitationText: "The dispute process uses a community accountability approach:\n\n1. A facilitation team of 2-3 trained community members guides the process\n2. Both the person harmed and the person who caused harm have support teams\n3. The wider community is represented by stakeholders affected by the issues\n4. The process begins with individual preparation sessions before group meetings\n5. Facilitation focuses on transforming harmful patterns, not just individual incidents\n6. Multiple sessions allow for deep exploration of systemic factors\n7. The process builds community capacity to address similar issues in the future"
},
communication: {
communicationText: "Communication follows these agreements: 1) Speak from personal experience using 'I' statements, 2) Acknowledge the difference between intent and impact, 3) Use language that recognizes both individual and systemic dimensions, 4) Name patterns and power dynamics when relevant, 5) Practice active listening, 6) Honor silence and processing time, 7) Express needs directly rather than through criticism."
},
participation: {
participationText: "The process includes a constellation of participants depending on the situation: 1) Core participants directly involved in the harm, 2) Support people chosen by core participants, 3) Facilitators from the transformative justice collective, 4) Community stakeholders who represent affected groups or have relevant expertise, 5) Witnesses who help document and hold the process. Each participant has a specific role with clear responsibilities."
},
documentation: {
documentationText: "Documentation includes: 1) Meeting summaries shared with all participants, 2) Agreements and action plans with assigned responsibilities, 3) Feedback collected after each major session, 4) Analysis of structural and cultural factors identified, 5) Resources shared during the process. Personal information is documented only as necessary and with consent."
}
},
assessment: {
situation: {
situationText: "The situation is assessed through a systemic analysis framework:\n\n1. Individual experiences and harms are documented\n2. Patterns of behavior and power dynamics are identified\n3. Structural factors that contributed to the harm are analyzed\n4. Community norms and cultural assumptions are examined\n5. The assessment connects individual incidents to broader social contexts\n6. This approach identifies intervention points at multiple levels, from individual to systemic"
},
stage_of_conflict: {
stageOfConflictText: "The facilitation team assesses: 1) The history and timeline of the harm, 2) Whether this is an isolated incident or part of a pattern, 3) The presence of immediate safety concerns, 4) The current capacity of all involved to engage in the process, 5) Community readiness to address potential systemic changes, and 6) Power dynamics that might impact the process."
},
needs: {
needsText: "The assessment identifies needs at multiple levels: 1) Immediate needs for safety, support, and stabilization, 2) Individual healing needs for those directly impacted, 3) Accountability needs to address the harm, 4) Community needs for understanding and prevention, 5) Systemic needs for policy or cultural change, and 6) Learning needs to build capacity for addressing similar situations."
},
evidence: {
evidenceText: "Information is gathered through multiple perspectives rather than a singular evidence-based approach. This includes: 1) First-person accounts of experiences, 2) Documentation of impacts, 3) Contextual information about the environment in which harm occurred, 4) Historical patterns within the community, 5) Analysis of how power operates in the situation, and 6) Relevant community agreements or expectations."
},
jurisdiction: {
jurisdictionText: "Transformative justice processes are most appropriate for situations where: 1) The harm is connected to broader social patterns, 2) Community-based intervention is possible and desired, 3) There is willingness to address both immediate harm and root causes, and 4) Public systems (legal, etc.) would likely cause additional harm. The process may be adapted based on safety needs and legal requirements."
}
},
deliberation: {
information_gathering: {
informationGatheringText: "Information is gathered through a trauma-informed approach that centers those most impacted. Multiple sessions allow time for reflection and integration. The facilitation team helps contextualize individual experiences within systemic patterns, gathering information about both the specific harm and the conditions that enabled it."
},
brainstorming: {
brainstormingText: "Solution-building happens through structured brainstorming processes that include: 1) Small group work to generate ideas addressing different levels of change, 2) Research into approaches used by other communities, 3) Consultation with relevant experts or elders, 4) Creative visioning exercises that imagine new possibilities, and 5) Reality testing of proposals against available resources and capacities."
},
discussion: {
discussionText: "Facilitated discussions focus on building shared understanding of how change can happen at multiple levels. Participants examine proposed solutions in terms of how they address immediate needs, build accountability, heal relationships, transform conditions, and prevent future harm. Special attention is paid to sustainability and community capacity."
},
deliberation_format: {
deliberationFormatText: "The deliberation process includes multiple formats: 1) Structured dialogue sessions with all participants, 2) Caucus meetings with specific stakeholder groups, 3) One-on-one conversations for sensitive topics, 4) Community forums for systemic issues, and 5) Reflection periods between sessions. The process typically unfolds over 2-3 months, adapting to the specific situation."
}
},
resolution: {
decision_making: {
decisionMakingText: "Decisions are made through a consensus process that prioritizes the needs of those most impacted while engaging everyone in finding solutions. The facilitation team helps test proposals against transformative justice principles. When full consensus isn't possible, the group identifies which elements have universal support and which need further development."
},
outcomes: {
outcomesText: "Outcomes address multiple dimensions: 1) Survivor-centered responses to address immediate harm, 2) Accountability processes for those who caused harm, 3) Community support mechanisms to enable healing and accountability, 4) Education initiatives to build awareness, 5) Policy or structural changes to transform conditions, and 6) Community capacity-building to sustain changes over time."
},
agreement: {
agreementText: "All resolutions result in a multi-level transformative action plan:\n\n1. Individual actions to address immediate harm and accountability\n2. Relationship-building commitments between affected parties\n3. Community-level interventions to address cultural factors\n4. Structural changes to prevent similar harms in the future\n5. Education and awareness components to share learning\n6. The plan includes both short-term and long-term actions\n7. Regular review points are scheduled to assess progress and adjust strategies"
},
follow_up: {
followUpText: "Follow-up includes: 1) Regular check-ins on agreement implementation, 2) Support for those taking on accountability, 3) Ongoing resources for those who were harmed, 4) Community updates on systemic changes, 5) Periodic reassessment of whether the approach is effective, and 6) Documentation of lessons learned to inform future processes."
},
announcement: {
announcementText: "Communication about outcomes follows consent-based protocols established during the process. Typically, information is shared at different levels: 1) Detailed information with direct participants, 2) General progress reports with the broader community, 3) Pattern-level insights for community education, and 4) Specific policy or structural changes implemented as a result of the process."
}
},
appeal: {
criteria: {
criteriaText: "The process can be revisited if: 1) Agreements aren't being implemented as planned, 2) Implementation reveals unforeseen challenges, 3) New information emerges about the situation, 4) The harm continues or recurs, 5) Systemic changes aren't effectively addressing root causes, or 6) Additional affected parties come forward."
},
appeal_process: {
appealProcessText: "Any participant can request reassessment by contacting the transformative justice collective. Two members review the request and consult with key stakeholders to determine next steps. This may lead to reconvening the original group, forming a new group, or taking targeted action on specific unaddressed issues."
},
appeal_deliberation: {
appealDeliberationText: "Reassessment follows a structured format: 1) Review of original agreements and implementation status, 2) Identification of gaps or new issues, 3) Analysis of why certain aspects haven't been effective, 4) Development of refined or additional responses, with emphasis on systematic factors that may have been overlooked."
},
appeal_resolution: {
appealResolutionText: "The renewed process produces an updated action plan that builds on previous work while addressing newly identified needs. This updated plan includes specific metrics for success and may assign new roles or resources to overcome previous implementation barriers."
}
},
delegation: {
criteria: {
criteriaText: "Delegation to other resources may be appropriate when: 1) Immediate safety requires formal intervention, 2) The situation involves legal requirements beyond community capacity, 3) Specialized expertise is needed, 4) The community lacks resources to address the scale of harm, or 5) The transformative justice approach has been attempted without success."
},
delegation_process: {
delegationProcessText: "When delegation is needed, the facilitation team: 1) Clearly explains why additional resources are recommended, 2) Helps participants understand options and potential impacts, 3) Supports access to appropriate services, 4) Continues to provide community support even when formal systems are involved, and 5) Documents learnings to strengthen future community capacity."
},
delegation_authority: {
delegationAuthorityText: "Our community maintains relationships with a network of resources including: 1) Specialized transformative justice practitioners for complex cases, 2) Mental health providers with trauma expertise, 3) Legal advocates who understand transformative approaches, 4) Cultural workers who can support healing processes, and 5) Organizations working on systemic change in relevant areas."
}
}
}
}
},
{
id: "jury-protocol",
title: "Community Jury",
description: "A process where a randomly selected jury of community members hears evidence and makes decisions on disputes",
data: {
stages: {
intake: {
process_start: {
processStartText: "The community jury process begins when a community member submits a case request form. This form requires a description of the dispute, parties involved, attempts at resolution so far, and desired outcome. The Jury Administrator reviews all submissions within 3 business days to determine if the case meets basic criteria for the jury process. If accepted, the case is assigned a number and scheduled for an initial hearing date."
},
rules_access: {
rulesAccessText: "Community standards and jury procedures are publicly available through multiple channels: 1) A comprehensive online handbook with searchable content, 2) Print copies in the community center, 3) Audio recordings for accessibility, and 4) Regular community education sessions. New residents receive an orientation to these standards during their welcome process. The Jury Administrator is available to answer questions about procedures."
},
information_access: {
informationAccessText: "Information about specific cases follows tiered access protocols: 1) Case parties receive all documentation relevant to their case, 2) Jury members receive case materials with sensitive personal information redacted, 3) The wider community receives notification of cases accepted and decisions made without identifying details, 4) Case summaries with key learnings are published annually for community education. Records are maintained securely by the Jury Administrator."
},
participant_inclusion: {
participantInclusionText: "When a case is accepted, all named parties receive formal notification through both email and paper letter. This notification includes the initial claim, information about the jury process, their rights and responsibilities, important dates, and a response form to be returned within 10 days. The Jury Administrator follows up by phone if no response is received within 5 days."
},
participation_requirement: {
participationRequirementText: "For community members, participation in the jury process is required as specified in the community agreement signed upon joining. For non-members or external entities, participation is voluntary. If a respondent declines to participate, the jury may still hear the case and reach a decision based on available information, but will note the limited nature of the proceedings."
},
participation_commitments: {
participationCommitmentsText: "All participants in the jury process commit to: 1) Providing truthful information and evidence, 2) Adhering to scheduled deadlines and hearing dates, 3) Treating all participants with respect regardless of disagreements, 4) Preparing materials as requested by the jury, 5) Accepting the jury's decision as binding within community governance, and 6) Implementing agreed-upon actions or decisions within specified timeframes."
}
},
prepare: {
principles: {
principlesText: "Our dispute resolution process is guided by these community jury principles:\n\n1. Fair representation through random selection of community members\n2. Impartiality through screening for conflicts of interest\n3. Informed deliberation based on evidence and testimony\n4. Collective wisdom through diverse perspectives\n5. Transparency in process while maintaining appropriate confidentiality\n6. Community standards as the basis for decision-making\n7. Balance between structure and flexibility to ensure fairness"
},
values: {
valuesText: "Our community jury system is grounded in these core values: 1) Procedural fairness - ensuring consistent, transparent processes, 2) Collective wisdom - trusting in the reasoned judgment of peers, 3) Community ownership - placing decision-making authority within the community, 4) Balanced perspective - bringing diverse viewpoints to each case, 5) Reasoned judgment - basing decisions on evidence and community standards, and 6) Restorative outcomes - seeking decisions that repair harm and rebuild relationships."
},
agreements: {
agreementsText: "All participants in the jury process agree to: 1) Accept the authority of the randomly selected jury to make decisions, 2) Present information honestly and completely, 3) Respect the confidentiality of sensitive information shared during the process, 4) Abide by the procedural rules established for hearings and deliberations, 5) Implement jury decisions in good faith, and 6) Use the appeals process rather than undermining decisions publicly."
}
},
process: {
preparation: {
preparationText: "Case preparation includes several key steps: 1) The Jury Administrator creates a case file containing all initial submissions, 2) Both parties receive a preparation packet with instructions for submitting evidence and witness statements, 3) Parties have 14 days to submit all materials, which are then organized and distributed to jury members, 4) Jurors review all materials individually before the hearing, 5) Pre-hearing conferences address procedural questions and establish time allocations, 6) The facilitator ensures all parties understand the process and their roles."
},
place: {
placeText: "Jury hearings take place in the community's designated hearing room, which features: 1) A formal arrangement with tables for parties and jury members, 2) Audio recording equipment to document proceedings, 3) Presentation technology for displaying evidence, 4) Good acoustics and appropriate lighting, 5) Accessibility features for all participants, and 6) A separate deliberation room for jury discussions. For sensitive cases, alternative venues can be arranged to ensure privacy and comfort for all participants."
},
facilitation: {
facilitationText: "The dispute process is facilitated through a structured jury format:\n\n1. A trained process facilitator guides the proceedings but does not participate in decision-making\n2. The process follows clear phases: opening statements, evidence presentation, questions, deliberation, and decision\n3. All parties have equal time to present their perspectives and evidence\n4. Jurors may ask clarifying questions through the facilitator\n5. The facilitator ensures adherence to community standards and procedural fairness\n6. Deliberations are conducted by jurors alone, with the facilitator available for procedural questions"
},
communication: {
communicationText: "Communication during jury proceedings follows formal protocols: 1) Opening and closing statements are uninterrupted and time-limited, 2) Evidence presentation follows a structured format with visual aids as needed, 3) Questions from jurors are submitted to the facilitator, who may rephrase for clarity, 4) Cross-examination is limited and focused on fact clarification rather than confrontation, 5) The facilitator moderates all exchanges to maintain respectful discourse, 6) Emotional expression is allowed but must remain appropriate to the setting."
},
participation: {
participationText: "Jury proceedings involve the following participants: 1) The 5-7 community members selected as jurors, 2) The case parties (initiator and respondent), 3) A trained facilitator who guides the process, 4) Witnesses called by either party or the jury itself, 5) The Jury Administrator who manages logistics and record-keeping, and 6) Community observers who may attend open portions of the hearings. Each role has clear responsibilities and boundaries established in the process guidelines."
},
documentation: {
documentationText: "Comprehensive documentation is maintained throughout the jury process: 1) Audio recordings of all open proceedings, 2) Written transcripts produced from these recordings, 3) A case file containing all submitted evidence and statements, 4) Jury deliberation worksheets (without attribution to specific jurors), 5) The final written decision with its rationale, and 6) Implementation and follow-up records. All documentation is maintained securely by the Jury Administrator for a minimum of five years."
}
},
assessment: {
situation: {
situationText: "The jury assesses each case through a structured framework: 1) Establishing agreed-upon facts versus disputed elements, 2) Identifying relevant community standards or agreements that apply, 3) Evaluating the credibility and completeness of evidence presented, 4) Considering context and mitigating circumstances, 5) Assessing impacts on individuals and the community, and 6) Determining responsibility based on the preponderance of evidence. This assessment is documented as part of their deliberation process."
},
stage_of_conflict: {
stageOfConflictText: "The jury considers the stage and history of the conflict, including: 1) Whether this is a first-time issue or recurring pattern, 2) Previous attempts at resolution and why they were unsuccessful, 3) Whether the situation is escalating or de-escalating, 4) The current relationship between the parties, 5) Potential impacts of various decision options on the conflict trajectory, and 6) How the timing of intervention might affect outcomes. This contextual understanding informs both their decision and implementation recommendations."
},
needs: {
needsText: "The jury identifies the fundamental needs of all involved parties: 1) Each party's stated desired outcome, 2) Underlying needs for recognition, restoration, safety, or clarity, 3) Community needs for precedent, standard-setting, or harm prevention, 4) Practical needs related to resources, access, or accommodations, 5) Relationship needs between the parties and with the broader community, and 6) Systemic needs that might require policy changes beyond the specific case. This needs assessment guides the development of comprehensive solutions."
},
evidence: {
evidenceText: "Evidence is evaluated through a structured process: 1) Written statements from all parties and witnesses, 2) Documentary evidence such as communications, records, or other relevant materials, 3) Visual evidence including photos, videos, or site documentation, 4) Community standards and agreements that establish expectations, 5) Expert testimony when specialized knowledge is required, and 6) Impact statements describing effects on involved parties. The jury weighs evidence based on relevance, credibility, and consistency rather than technical rules of admissibility."
},
jurisdiction: {
jurisdictionText: "The community jury has jurisdiction over: 1) Disputes between community members regarding shared resources or spaces, 2) Alleged violations of community agreements or standards, 3) Conflicts affecting community function or wellbeing, 4) Requests for clarification of policies or practices, and 5) Appeals of decisions made by community committees. The jury does not have jurisdiction over legal matters requiring formal court proceedings, situations presenting immediate safety risks, or disputes that have been explicitly excluded in the community charter."
}
},
deliberation: {
information_gathering: {
informationGatheringText: "Jury information gathering continues during deliberation: 1) Jurors identify information gaps that emerged during the hearing, 2) They may request clarification from parties through written questions, 3) They review all submitted evidence methodically, creating an evidence summary, 4) They consult community standards and precedents from previous similar cases, 5) If needed, they may request additional expert input on technical matters, and 6) They document key findings of fact that will form the basis for their decision."
},
brainstorming: {
brainstormingText: "The jury uses a structured brainstorming process: 1) Individual jurors first write down potential solutions independently, 2) Each juror shares their ideas without criticism or evaluation, 3) Ideas are recorded visibly for all jurors to consider, 4) Building on initial ideas, jurors suggest modifications and combinations, 5) The full range of possibilities is organized into categories, and 6) The jury identifies underlying principles that might guide an effective resolution. This approach ensures all perspectives are considered before evaluation begins."
},
discussion: {
discussionText: "Jury deliberation discussions follow a structured format: 1) The jury first clarifies the key questions that must be answered, 2) They review evidence related to each question, 3) Each juror shares their perspective on how the evidence answers these questions, 4) Areas of agreement and disagreement are explicitly identified, 5) For disagreements, jurors explore underlying reasoning and concerns, 6) The facilitator helps maintain focus and ensures all voices are heard, and 7) The jury works toward finding areas of consensus before moving to formal decision-making."
},
finding_solutions: {
findingSolutionsText: "Solutions are developed through structured jury deliberation:\n\n1. Jurors first identify key issues requiring resolution\n2. Each juror shares their initial perspective without interruption\n3. The jury works to develop a shared understanding of the situation\n4. Multiple solution options are generated and evaluated\n5. Decisions require a supermajority (typically 2/3) agreement\n6. When consensus isn't possible on specific points, the jury may offer multiple options\n7. The jury documents their reasoning along with their final decision"
},
deliberation_format: {
deliberationFormatText: "Jury deliberations follow a clear format: 1) Initial deliberations occur immediately following the hearing while information is fresh, 2) If needed, additional sessions are scheduled within 7 days, 3) A designated jury foreperson facilitates the discussion with assistance from the process facilitator as requested, 4) Deliberations are private, with only jury members present unless procedural assistance is needed, 5) Deliberations continue until a decision is reached or the maximum time (typically 10 hours total) has been used, 6) The jury takes structured breaks to prevent fatigue and allow reflection."
}
},
resolution: {
decision_making: {
decisionMakingText: "Decisions are made through a structured jury voting process:\n\n1. After thorough deliberation, the jury votes on proposed resolutions\n2. A 2/3 majority is required for decisions to be adopted\n3. If the first vote doesn't reach the threshold, further discussion occurs\n4. Up to three voting rounds may take place to reach the required majority\n5. If consensus cannot be reached after three rounds, the most supported option with at least 60% support is adopted\n6. The jury provides written rationale for their decision based on community standards\n7. Jury decisions are binding within the scope of community governance"
},
outcomes: {
outcomesText: "Jury decisions may include multiple outcome elements: 1) Determination of whether community standards were violated, 2) Specific actions required to address harm or restore conditions, 3) Clarification of rights and responsibilities going forward, 4) Resource allocations or adjustments to shared arrangements, 5) Monitoring provisions to ensure implementation, 6) Preventative measures to avoid similar issues, and 7) Recommendations for community policy or practice changes. Outcomes are designed to be specific, measurable, achievable, relevant, and time-bound."
},
agreement: {
agreementText: "The jury decision is documented in a formal written determination that includes: 1) A summary of the case and key facts established, 2) The specific questions the jury was asked to resolve, 3) The jury's findings on each question with supporting rationale, 4) Specific actions required of each party with deadlines, 5) Consequences for non-compliance if applicable, 6) Monitoring and verification procedures, and 7) Signatures of all jury members. This document is provided to all parties and becomes part of community records."
},
follow_up: {
followUpText: "Implementation of jury decisions is tracked through a structured follow-up process: 1) The Jury Administrator monitors compliance with required actions, 2) Parties submit documentation of completed items by established deadlines, 3) A 30-day check-in assesses initial progress, 4) A final implementation review occurs after all deadlines have passed, 5) The original jury foreperson is consulted if clarification is needed, and 6) Successful implementation is documented and the case is formally closed. If implementation issues arise, the Administrator may reconvene the jury or initiate the non-compliance process."
},
announcement: {
announcementText: "Jury decisions are announced according to established protocols: 1) Parties receive the full written determination within 3 days of the decision, 2) A brief announcement that a decision has been reached is posted to community channels, 3) A redacted version removing sensitive information may be shared if the case involves community-wide issues, 4) Any policy implications or precedents are highlighted for community governance, 5) The jury may recommend specific educational communications if the case reveals common misunderstandings of community standards."
}
},
appeal: {
criteria: {
criteriaText: "Appeals of jury decisions may be filed based on specific criteria: 1) Significant new evidence that wasn't available during the original hearing, 2) Procedural errors that materially affected the outcome, 3) Clear misapplication of community standards by the jury, 4) Jury bias or misconduct that affected the decision, or 5) Implementation difficulties that make the decision unworkable. Appeals must be filed within 14 days of the decision and must specifically identify which criteria apply."
},
appeal_process: {
appealProcessText: "The appeal process follows these steps: 1) The appellant submits a written appeal stating the grounds and desired outcome, 2) The Appeal Committee (three community members not involved in the original case) reviews the appeal to determine if it meets criteria, 3) If accepted, a new jury is selected, larger than the original, 4) The new jury reviews all original materials plus the appeal documentation, 5) A limited appeal hearing is held focusing only on the specific grounds for appeal, 6) The appeal jury deliberates and issues a new decision that either confirms, modifies, or overturns the original decision."
},
appeal_deliberation: {
appealDeliberationText: "Appeal deliberations focus specifically on the grounds presented: 1) For new evidence appeals, the jury assesses whether the evidence is truly new and would likely have changed the outcome, 2) For procedural error appeals, they determine if errors occurred and materially affected the result, 3) For misapplication of standards, they review the standards and their application, 4) For bias claims, they examine the conduct and decision patterns, 5) For implementation issues, they assess practicality and alternatives. Their deliberation is limited to the specific appeal grounds rather than rehearing the entire case."
},
appeal_resolution: {
appealResolutionText: "The appeal jury has three possible resolution options: 1) Confirm the original decision if the appeal grounds are not substantiated, 2) Modify specific aspects of the decision while maintaining the core findings, or 3) Overturn the decision completely and issue a new determination. The appeal resolution includes specific reasoning addressing each appeal ground raised. Appeal decisions are final and not subject to further community appeal, though legal rights remain unaffected."
}
},
delegation: {
criteria: {
criteriaText: "Cases may be delegated from the jury process when: 1) The matter involves legal issues beyond community governance, 2) Specialized expertise is required for proper resolution, 3) Immediate intervention is needed for safety concerns, 4) The case complexity exceeds what volunteer jurors can reasonably handle, 5) Multiple previous attempts through the jury process have failed to resolve the issue, or 6) The case would create significant conflicts of interest within the available jury pool. Delegation decisions are made by the Jury Administrator in consultation with community leadership."
},
delegation_process: {
delegationProcessText: "When delegation is appropriate, the process includes: 1) The Jury Administrator documents the reason for delegation, 2) Parties are notified of the delegation decision and rationale, 3) They are provided with information about the alternative process and next steps, 4) Relevant case information is transferred to the appropriate body (with party consent), 5) The Jury Administrator remains available as a resource during the transition, and 6) The community record notes the delegation and eventual outcome for future reference and learning."
},
selection: {
selectionText: "Jurors are selected through a structured random process:\n\n1. A pool of 15-20 community members is randomly selected from the membership roster\n2. Potential jurors complete a screening questionnaire to identify conflicts of interest\n3. Both parties in the dispute may exclude up to 3 potential jurors without stating a reason\n4. A final panel of 5-7 jurors is confirmed from the remaining pool\n5. Selected jurors receive orientation materials and basic conflict resolution training\n6. The process ensures diversity of perspectives while maintaining impartiality"
},
delegation_authority: {
delegationAuthorityText: "Our community maintains relationships with several delegation authorities: 1) A panel of professional mediators for complex relationship conflicts, 2) Legal advisors for matters with potential legal implications, 3) Subject matter experts in areas like construction, finance, and technology, 4) Restorative justice practitioners for cases involving harm repair, 5) Mental health professionals for situations involving psychological wellbeing, and 6) External facilitation teams for conflicts involving governance leadership. These resources receive training on our community values and approaches."
}
}
}
}
},
{
id: "referee-protocol",
title: "Community Referee",
description: "A streamlined process where a single trained referee facilitates and decides on dispute resolution",
data: {
stages: {
intake: {
process_start: {
processStartText: "The referee process begins when a community member submits a dispute resolution request form. This form includes a description of the issue, parties involved, desired outcome, and relevant documentation. Within 2 business days, the Dispute Coordinator reviews the form and determines if the referee process is appropriate. If so, the referee selection process begins immediately, with a goal of assigning a referee within 5 days of the initial submission."
},
rules_access: {
rulesAccessText: "Community standards and the referee process guidelines are made accessible through: 1) A comprehensive digital handbook available on the community website, 2) Print copies in the community office, 3) Periodic community workshops explaining the process, and 4) A quick-reference guide that summarizes key points. New community members receive orientation to these materials when they join. The Dispute Coordinator is available to answer questions about the process."
},
information_access: {
informationAccessText: "Information management follows clear confidentiality protocols: 1) Case information is shared only with the assigned referee and parties directly involved, 2) Documentation is stored securely in both digital and physical formats, 3) Anonymized statistical information is compiled quarterly for process improvements, 4) Final determinations may be used as precedent for future cases with identifying details removed, and 5) Parties may agree to share specific outcomes with the wider community when relevant to community functioning."
},
participant_inclusion: {
participantInclusionText: "When a case is accepted, the Dispute Coordinator contacts all identified parties via email and phone within 48 hours. They receive an explanation of the process, a copy of the initial dispute form, information about referee selection, and a response form to be completed within 3 days. The coordinator answers questions and addresses concerns about the process to ensure informed participation. If a party is unresponsive, a secondary contact method is attempted."
},
participation_requirement: {
participationRequirementText: "Participation in the referee process is a condition of community membership as outlined in our community agreement. Members are expected to engage in good faith when named in a dispute. However, the process may proceed even if a party declines to participate actively. In such cases, the referee will consider available information and note the limited participation in their determination. External parties not bound by community agreements may voluntarily opt in to the process."
},
participation_commitments: {
participationCommitmentsText: "Parties in the referee process commit to: 1) Providing accurate and complete information, 2) Responding to referee requests within specified timeframes, 3) Participating in scheduled meetings prepared and on time, 4) Engaging respectfully even during disagreement, 5) Considering resolution options with an open mind, 6) Abiding by the referee's determination, and 7) Implementing required actions within established deadlines. These commitments are acknowledged in writing at the process start."
}
},
prepare: {
principles: {
principlesText: "Our dispute resolution process is guided by these referee principles:\n\n1. Expertise-based facilitation by a qualified individual\n2. Fairness through clear procedures and balanced participation\n3. Efficiency through streamlined process with a single decision-maker\n4. Consistency in applying community standards\n5. Practicality in developing workable solutions\n6. Transparency in reasoning while maintaining confidentiality\n7. Authority balanced with participant input and feedback"
},
values: {
valuesText: "The referee process embodies these essential values: 1) Efficiency - streamlining resolution to minimize time and resources, 2) Fairness - ensuring balanced consideration and equal opportunity to be heard, 3) Expertise - bringing relevant knowledge and skills to complex situations, 4) Practicality - focusing on workable solutions that can be implemented, 5) Consistency - applying community standards evenly across similar cases, and 6) Respect - maintaining dignity for all participants throughout the process."
},
agreements: {
agreementsText: "All parties in the referee process agree to: 1) Recognize the authority of the referee to make binding determinations, 2) Provide information honestly and completely when requested, 3) Meet deadlines for submissions and responses, 4) Participate in good faith in all scheduled sessions, 5) Treat the referee and other participants with respect, 6) Maintain confidentiality about process details, and 7) Implement the referee's determination promptly once issued."
}
},
process: {
preparation: {
preparationText: "Case preparation follows a streamlined sequence: 1) The assigned referee reviews the initial submission within 24 hours, 2) A case management plan with clear timeline is created and shared with all parties, 3) Parties submit position statements and supporting documentation within 5 days, 4) The referee identifies key issues and information gaps, 5) Individual pre-meeting calls are conducted with each party, and 6) The referee prepares a structured agenda for the joint session, focusing discussion on the most relevant issues."
},
place: {
placeText: "Referee sessions typically take place in a neutral meeting room at the community center, featuring: 1) A conference table with equal seating for all parties, 2) Presentation equipment for sharing relevant information, 3) Soundproofing to ensure privacy, 4) Comfortable seating for sessions that may last 2-3 hours, 5) Good lighting and ventilation, and 6) Water and basic refreshments. Virtual participation options are available when necessary, using secure video conferencing technology with screen sharing capabilities."
},
facilitation: {
facilitationText: "The dispute process is led by a single referee who:\n\n1. Reviews all submitted materials before the first meeting\n2. Conducts individual intake interviews with each party\n3. Structures a joint session with clear speaking times and guidelines\n4. Asks clarifying questions to develop a complete understanding\n5. May request additional information or witnesses as needed\n6. Maintains control of the process while ensuring all voices are heard\n7. Provides guidance on realistic options based on community standards"
},
communication: {
communicationText: "Communication in referee sessions follows structured guidelines: 1) The referee establishes clear speaking protocols at the start, 2) Each party has equal opportunity to present their perspective without interruption, 3) Questions are directed through the referee to maintain order, 4) Time limits ensure balanced participation, 5) The referee may caucus with parties separately when needed, 6) Communication focuses on facts and interests rather than accusations, and 7) The referee summarizes key points to ensure shared understanding."
},
participation: {
participationText: "Participation typically includes: 1) The primary parties directly involved in the dispute, 2) The referee who facilitates and ultimately decides the case, 3) One support person per party (non-speaking unless invited), 4) Witnesses with relevant information (for specific portions only), 5) The Dispute Coordinator who handles logistics and record-keeping, and 6) Occasional observers for training purposes (with party consent). All participants receive clear information about their role and expectations in advance."
},
documentation: {
documentationText: "Documentation is maintained throughout the process: 1) All written submissions are compiled in a case file, 2) The referee takes structured notes during all meetings and calls, 3) Audio recording may be used with party consent for accuracy, 4) The referee documents key findings of fact and policy interpretations, 5) A written summary is provided to parties after each significant meeting, and 6) The final determination serves as the official record of the process outcome. All documentation is maintained confidentially in accordance with community record-keeping policies."
}
},
assessment: {
situation: {
situationText: "The referee conducts a thorough situation assessment: 1) Identifying agreed-upon facts versus disputed facts, 2) Clarifying which community standards or agreements apply to the situation, 3) Determining the chronology of relevant events, 4) Assessing the impact on involved parties and the community, 5) Evaluating the credibility of conflicting accounts when necessary, and 6) Distinguishing between primary issues that require resolution and secondary factors. This assessment provides the foundation for a fair determination."
},
stage_of_conflict: {
stageOfConflictText: "The referee evaluates the stage and dynamics of the conflict: 1) Whether this is a new issue or part of an ongoing pattern, 2) The level of escalation and emotional intensity, 3) Current communication patterns between the parties, 4) Power dynamics that may influence resolution options, 5) Previous attempts at resolution and why they were unsuccessful, and 6) The potential for cooperative versus imposed solutions based on relationship factors. This assessment helps the referee tailor the process appropriately."
},
needs: {
needsText: "The referee identifies the underlying needs of all parties: 1) Stated desires and positions as expressed by each party, 2) Deeper interests that may not be explicitly articulated, 3) Practical needs related to resources, timing, or implementation capacity, 4) Relationship needs between the parties, 5) Community needs for precedent and standard enforcement, and 6) Procedural needs for clarity and closure. Understanding these needs helps the referee craft solutions that address core concerns rather than just surface positions."
},
evidence: {
evidenceText: "Evidence evaluation follows a practical approach: 1) Written statements from all involved parties, 2) Supporting documentation such as communications, photos, or records, 3) Witness accounts from those with direct knowledge, 4) Site visits or inspections when relevant to physical disputes, 5) Community guidelines and precedents from similar cases, and 6) Expert input when specialized knowledge is required. The referee weighs evidence based on relevance, credibility, and consistency, focusing on information that directly impacts the key issues."
},
jurisdiction: {
jurisdictionText: "The referee process has jurisdiction over: 1) Interpretation and application of community agreements and policies, 2) Allocation of shared resources and spaces, 3) Interpersonal conflicts affecting community functioning, 4) Minor property disputes between community members, and 5) Compliance with previous community decisions. The process does not have jurisdiction over legal matters outside community governance, criminal activities, or disputes explicitly excluded in the community charter. Complex cases may be referred to specialized authorities when appropriate."
}
},
deliberation: {
information_gathering: {
informationGatheringText: "The referee gathers information through a structured approach: 1) Initial submissions from all parties, 2) Clarification questions to fill information gaps, 3) Targeted witness statements on specific disputed facts, 4) Review of community standards and precedents, 5) Site visits or physical inspections when relevant, and 6) Expert consultation on technical matters if needed. The process is designed to be thorough but efficient, gathering essential information without unnecessary delay."
},
brainstorming: {
brainstormingText: "Solution development occurs through guided brainstorming: 1) The referee first asks parties to suggest potential solutions, 2) Each suggestion is noted without immediate evaluation, 3) The referee may offer additional options based on experience with similar cases, 4) Benefits and challenges of each option are identified, 5) Parties discuss which elements of various options might be combined, and 6) The referee helps refine promising approaches into workable solutions. This collaborative phase occurs before the referee makes a final determination."
},
discussion: {
discussionText: "Discussion in referee sessions is highly structured: 1) The referee identifies specific topics for focused conversation, 2) Each party has equal opportunity to address each topic, 3) Direct questions between parties are moderated by the referee, 4) The referee summarizes points of agreement and disagreement, 5) When positions differ, the referee explores underlying interests and concerns, and 6) The discussion concludes with a summary of key findings and possible resolution paths. This structure ensures efficient use of time while covering all relevant issues."
},
deliberation_format: {
deliberationFormatText: "The referee's deliberation typically includes: 1) A structured review of all gathered information, 2) Analysis of which community standards apply to the situation, 3) Assessment of the credibility and weight of conflicting evidence, 4) Consideration of precedent from similar cases, 5) Evaluation of proposed solutions against practical implementation criteria, and 6) Drafting of a determination that addresses all key issues. The referee may consult with other referees on complex matters while maintaining case confidentiality. Deliberation occurs within 3 days of the final information gathering."
}
},
resolution: {
decision_making: {
decisionMakingText: "Decisions are made through a referee determination process:\n\n1. The referee first encourages participants to reach their own agreement\n2. If parties cannot agree, the referee considers all presented information\n3. The decision is based on community standards, precedent, and fairness\n4. The referee provides a written determination with clear reasoning\n5. Parties may ask clarifying questions about the decision\n6. The referee has authority to make binding decisions within community governance\n7. Decisions are delivered within one week of the final session"
},
outcomes: {
outcomesText: "Referee determinations may include multiple elements: 1) Findings on disputed facts based on the preponderance of evidence, 2) Interpretation of how community standards apply to the situation, 3) Specific actions required of each party with deadlines, 4) Allocation of costs or resources if relevant, 5) Preventive measures to avoid similar disputes in the future, 6) Monitoring protocols to verify implementation, and 7) Recommendations for community policy clarification if gaps are identified. Outcomes balance fairness with practicality, focusing on clear, implementable solutions."
},
agreement: {
agreementText: "All resolutions result in a clear written determination:\n\n1. The document summarizes the dispute and process\n2. Key findings on factual and policy matters are stated clearly\n3. Specific required actions are detailed with deadlines\n4. Rationale for the decision is provided with reference to community standards\n5. Implementation responsibilities are assigned to specific parties\n6. Follow-up and verification methods are specified\n7. The referee signs the determination, and parties acknowledge receipt"
},
follow_up: {
followUpText: "Implementation is supported through structured follow-up: 1) The referee schedules check-in points based on action deadlines, 2) Parties submit verification of completed items, 3) The Dispute Coordinator tracks overall implementation progress, 4) Brief follow-up calls address any clarification needs or implementation challenges, 5) If implementation problems arise, the referee may reconvene the parties for problem-solving, and 6) When all requirements are complete, the case is formally closed with documentation of successful implementation. This accountability system ensures determinations are put into practice."
},
announcement: {
announcementText: "Communication about referee determinations follows a tiered approach: 1) Parties receive the complete determination document, 2) The Dispute Coordinator records the outcome in the confidential case tracking system, 3) If the case involves community-wide issues, a general announcement noting that a determination has been made may be shared without personal details, 4) Policy implications or clarifications may be communicated to relevant community committees, and 5) Anonymized case summaries may be used for referee training and process improvement."
}
},
appeal: {
criteria: {
criteriaText: "Appeals of referee determinations may be filed based on limited criteria: 1) Significant new information that wasn't available during the original process, 2) Clear misapplication of community standards, 3) Procedural errors that materially affected the outcome, 4) Bias or conflict of interest that wasn't previously disclosed, or 5) Implementation impossibility due to factors outside the party's control. Appeals must be filed within 10 days of the determination and must specifically identify which criterion applies and provide supporting evidence."
},
appeal_process: {
appealProcessText: "The appeal process follows these steps: 1) The appealing party submits a written appeal form with supporting documentation, 2) The Appeals Committee (consisting of three experienced referees not involved in the original case) reviews the appeal to determine if it meets criteria, 3) If accepted, a senior referee not involved in the original case is assigned, 4) The senior referee reviews all materials from the original case plus the appeal documentation, 5) A limited appeal hearing may be held to address specific issues, and 6) The senior referee issues a final determination that confirms, modifies, or replaces the original decision."
},
appeal_deliberation: {
appealDeliberationText: "Appeal deliberation is tightly focused on the specific grounds raised: 1) For new information appeals, the senior referee assesses whether the information is truly new and substantial enough to affect the outcome, 2) For misapplication appeals, they review the relevant standards and their application, 3) For procedural error appeals, they determine if the alleged errors occurred and materially impacted the result, 4) For bias appeals, they evaluate the evidence of partiality, and 5) For implementation appeals, they assess the practical constraints. The deliberation is completed within 5 days of receiving all appeal materials."
},
appeal_resolution: {
appealResolutionText: "The appeal resolution is documented in a written determination that: 1) Addresses each appeal ground specifically, 2) Explains the rationale for upholding or modifying the original determination, 3) Provides any revised directives or timelines, 4) Clarifies implementation requirements, 5) Notes that this decision is final within the community process, and 6) Is delivered to all parties within 48 hours of the decision. The Appeals Committee records the outcome for tracking and quality improvement purposes."
}
},
delegation: {
criteria: {
criteriaText: "Cases may be delegated from the referee process when: 1) Legal issues beyond community governance are central to the dispute, 2) The complexity requires specialized expertise beyond the referees' training, 3) Safety concerns require immediate professional intervention, 4) The scope affects multiple community systems or external entities, 5) Significant conflicts of interest exist with all available referees, or 6) The case involves policy creation rather than policy application. The Dispute Coordinator makes initial delegation recommendations, which are reviewed by the Referee Oversight Committee."
},
delegation_process: {
delegationProcessText: "The delegation process includes: 1) Documentation of why the referee process is not appropriate, 2) Consultation with parties about alternative options, 3) Formal referral to the appropriate resource with relevant background information, 4) Assistance with transition to ensure parties understand the new process, 5) The Dispute Coordinator remains available as a resource during the transition, and 6) The outcome is recorded for community learning and process improvement. This approach ensures no dispute falls through the cracks due to jurisdictional limitations."
},
selection: {
selectionText: "The referee is selected through a structured process:\n\n1. The community maintains a roster of 5-7 trained referees with diverse expertise\n2. For each dispute, 3 available referees are presented to the parties\n3. Parties rank their preferences, with the highest mutual ranking selected\n4. If parties cannot agree, a random selection from the three options is made\n5. Selected referees must disclose any potential conflicts of interest\n6. Parties may challenge the selection based on demonstrated bias or conflict\n7. Referees receive ongoing training and peer review to maintain quality"
},
delegation_authority: {
delegationAuthorityText: "Our community maintains relationships with several authorities for delegation: 1) A network of professional mediators with various specializations, 2) Legal services for matters requiring formal legal intervention, 3) Subject matter experts in areas like construction, finance, technology, and health, 4) Conflict coaching services for high-emotion situations, 5) Therapeutic resources for conflicts with significant relational components, and 6) Regulatory agencies when disputes involve compliance with external requirements. The community budget includes funds to support access to these resources when needed."
}
}
}
}
},
{
id: "peer-to-peer",
title: "Peer-to-Peer",
description: "A self-facilitated process where participants work together directly to resolve disputes",
data: {
stages: {
intake: {
process_start: {
processStartText: "The process begins when any community member fills out a dispute form, which is available on the community website or as paper copies in common areas. The form asks for a description of the issue, who is involved, and what resolution they're seeking."
},
rules_access: {
rulesAccessText: "Community rules are kept in a shared digital repository accessible to all members, with physical copies posted in community spaces. Rules are reviewed annually in a community-wide meeting."
},
information_access: {
informationAccessText: "Information about disputes is shared only with those directly involved in the process. A summary of resolved disputes (with identifying details removed) is shared quarterly to help the community learn and improve processes."
},
participant_inclusion: {
participantInclusionText: "When a dispute is filed, all identified parties are contacted via their preferred communication method within 48 hours. They receive a copy of the dispute form and information about the peer-to-peer resolution process."
},
participation_requirement: {
participationRequirementText: "Participation is voluntary but strongly encouraged. Community members have agreed in advance that the peer resolution process is the first step before escalating disputes to other forums."
},
participation_commitments: {
participationCommitmentsText: "Participants commit to: 1) Communicating honestly and respectfully, 2) Listening to understand rather than to respond, 3) Working toward a mutually beneficial resolution, 4) Respecting confidentiality, and 5) Following through on any agreed-upon actions."
}
},
process: {
preparation: {
preparationText: "Both parties have 3-5 days to prepare for the conversation. During this time, they reflect on the issue, their needs, and possible solutions. A preparation worksheet is provided to help structure their thoughts. Participants may seek advice from trusted friends but are asked to keep details confidential."
},
place: {
placeText: "Participants choose a neutral location that feels comfortable for both parties. This could be a community meeting room, quiet outdoor space, or online video call if necessary. The space should be private, quiet, and free from interruptions."
},
facilitation: {
facilitationText: "This process is self-facilitated by the participants. Both parties review a shared guidance document on productive communication before meeting. This document includes suggested time frames, communication techniques, and a basic structure for the conversation."
},
communication: {
communicationText: "Participants follow these guidelines: 1) Take turns speaking without interruption, 2) Use 'I' statements to express feelings and needs, 3) Ask clarifying questions, 4) Summarize what you've heard to ensure understanding, 5) Focus on the present issue and future solutions rather than past grievances."
},
participation: {
participationText: "Only the directly involved parties participate in the initial conversation. If they reach an impasse, they may jointly decide to invite a mutual trusted friend to help facilitate a follow-up conversation."
},
documentation: {
documentationText: "Participants take collaborative notes during the meeting, focusing on agreements made and next steps. Both parties review these notes at the end of the meeting and receive a copy. These notes remain confidential to the participants."
}
},
assessment: {
situation: {
situationText: "Participants assess the situation together by identifying: 1) The specific issue or behavior causing concern, 2) The impact on each person and the community, 3) Related community values or agreements, and 4) What needs to happen for resolution."
},
stage_of_conflict: {
stageOfConflictText: "Participants jointly determine whether the dispute is: 1) Early stage (single incident or misunderstanding), 2) Developing (pattern forming but communication still possible), or 3) Escalated (significant breakdown in communication or trust). This helps determine appropriate next steps."
},
needs: {
needsText: "Each participant identifies and shares their underlying needs, such as respect, clarity, security, fairness, autonomy, or community connection. They discuss how these needs can be addressed while honoring the needs of others."
},
evidence: {
evidenceText: "Participants share relevant information with each other directly. This may include communications, photos, witness accounts, or other documentation. Both parties agree to honestly present all relevant information."
},
jurisdiction: {
jurisdictionText: "The peer-to-peer process is appropriate for most interpersonal conflicts and minor disagreements. If the dispute involves illegal activity, poses safety risks, or requires specialized expertise, participants should refer to the delegation process."
}
},
deliberation: {
information_gathering: {
informationGatheringText: "Participants ask each other clarifying questions to ensure they fully understand the situation. They may take a break to gather more information if needed before continuing the conversation."
},
brainstorming: {
brainstormingText: "Participants jointly brainstorm potential solutions without immediately evaluating them. All ideas are recorded. After generating options, they discuss the advantages and challenges of each approach."
},
discussion: {
discussionText: "Discussion follows the format of: 1) Each person shares their perspective uninterrupted, 2) Clarifying questions are asked, 3) Areas of agreement and difference are identified, 4) Participants work to find solutions that address core needs of all involved."
},
deliberation_format: {
deliberationFormatText: "The deliberation is a face-to-face conversation (or video call if necessary) that typically lasts 60-90 minutes. If more time is needed, participants may schedule follow-up conversations rather than rushing to resolution."
}
},
resolution: {
decision_making: {
decisionMakingText: "Decisions are made through mutual agreement. Both participants must consent to the resolution, meaning they can live with the decision even if it isn't their ideal outcome."
},
outcomes: {
outcomesText: "Possible outcomes include: 1) Clarification of misunderstandings, 2) Apologies and acknowledgment of impact, 3) Agreements about future behavior, 4) Specific actions to restore harm, 5) Plans for ongoing communication, or 6) Agreement to disagree respectfully on certain matters."
},
agreement: {
agreementText: "Agreements are documented in writing, with copies provided to both participants. They include specific, measurable actions with timelines and how progress will be reviewed. Both participants sign the agreement."
},
follow_up: {
followUpText: "Participants schedule a follow-up check-in 2-4 weeks after the agreement to discuss progress and any adjustments needed. This can be a brief meeting or exchange of messages."
},
announcement: {
announcementText: "The resolution remains confidential between the participants unless they jointly agree to share specific information with the wider community."
}
},
appeal: {
criteria: {
criteriaText: "If either participant feels the agreement isn't working or circumstances have changed significantly, they can request a follow-up conversation using the same peer-to-peer process."
},
appeal_process: {
appealProcessText: "To revisit the agreement, the participant sends a written request to the other party explaining why they believe the agreement needs adjustment. They then schedule a new conversation following the same format as the original process."
},
appeal_deliberation: {
appealDeliberationText: "The follow-up conversation focuses specifically on the aspects of the agreement that aren't working, rather than reopening the entire dispute. Both parties discuss changes that could make the agreement more effective."
},
appeal_resolution: {
appealResolutionText: "The participants revise their written agreement based on the follow-up conversation, with both signing the updated document."
}
},
delegation: {
criteria: {
criteriaText: "Delegation to a different process is appropriate if: 1) The peer-to-peer process has been attempted without resolution, 2) The dispute involves serious safety concerns, 3) There is a significant power imbalance between participants, 4) The issue affects the broader community, or 5) Specialized expertise is needed."
},
delegation_process: {
delegationProcessText: "If delegation is needed, participants document what has been tried and what issues remain unresolved. They then request assistance from the community mediator pool, a group of trained volunteer mediators."
},
delegation_authority: {
delegationAuthorityText: "The community mediator pool maintains a roster of trained mediators who can facilitate a more structured process. They also maintain referral relationships with professional mediators, counselors, and legal services as needed."
}
}
}
}
},
{
id: "chosen-facilitator",
title: "Chosen Facilitator",
description: "A process where participants mutually select a facilitator to help guide their dispute resolution",
data: {
stages: {
intake: {
process_start: {
processStartText: "The process begins when a community member submits a dispute form to the Community Relations Committee. The form includes details about the issue, parties involved, and previous attempts at resolution. The committee acknowledges receipt within 24 hours."
},
rules_access: {
rulesAccessText: "Community rules and the dispute resolution protocol are available on the community website and in a physical binder kept in the community center. New members receive an orientation to these guidelines when they join."
},
information_access: {
informationAccessText: "Information is shared on a need-to-know basis. The Community Relations Committee keeps records of disputes, and the parties involved have access to all documentation related to their case. Annual anonymous statistics about disputes are shared with the community."
},
participant_inclusion: {
participantInclusionText: "Within 48 hours of receiving a dispute form, the committee contacts all named parties and provides them with a copy of the form and information about the process. Each person confirms their willingness to participate and receives information about selecting a facilitator."
},
participation_requirement: {
participationRequirementText: "Participation is voluntary, though all community members have agreed as part of their membership that they will make a good faith effort to resolve conflicts through the community process before pursuing outside remedies."
},
participation_commitments: {
participationCommitmentsText: "Participants commit to: 1) Engaging honestly and respectfully, 2) Selecting a mutually acceptable facilitator, 3) Attending all scheduled sessions, 4) Respecting confidentiality, 5) Working toward resolution in good faith, and 6) Abiding by any agreements reached."
}
},
process: {
preparation: {
preparationText: "Before the first facilitated session, each participant completes a preparation form describing their perspective on the issue, their needs, and possible solutions. They submit this to the facilitator at least 48 hours before the first meeting. The facilitator may have individual pre-meetings with participants."
},
place: {
placeText: "Meetings take place in a neutral community space, typically a designated meeting room in the community center. The facilitator ensures the space is set up appropriately with comfortable seating, water, and any needed materials like whiteboard or flipchart."
},
facilitation: {
facilitationText: "The process is guided by a facilitator chosen jointly by all participants from a list of community members who have expressed willingness to serve in this role. The facilitator has basic training in conflict resolution but is not a professional mediator. They help guide the conversation, ensure all voices are heard, and maintain focus on resolution."
},
communication: {
communicationText: "The facilitator establishes ground rules at the beginning of the first session, such as: 1) One person speaks at a time, 2) Focus on issues rather than personal attacks, 3) Use respectful language, 4) Actively listen to understand, 5) Take breaks when needed, and 6) Maintain confidentiality."
},
participation: {
participationText: "The primary participants and the facilitator attend all sessions. With agreement from all parties, participants may bring one support person to sessions. Support people may speak when invited but primarily provide emotional support and perspective between sessions."
},
documentation: {
documentationText: "The facilitator takes notes capturing main discussion points and any agreements reached. These notes are shared with participants after each session for review and correction. Final agreements are documented in writing and signed by all participants."
}
},
assessment: {
situation: {
situationText: "In the first session, the facilitator helps participants create a shared understanding of the situation by: 1) Having each person share their perspective without interruption, 2) Identifying areas of agreement and disagreement, 3) Clarifying facts versus interpretations, and 4) Establishing what resolution would look like."
},
stage_of_conflict: {
stageOfConflictText: "The facilitator helps assess whether the conflict is: 1) A misunderstanding that can be clarified, 2) A disagreement about resources or procedures, 3) A values-based conflict, or 4) A relationship conflict with a history of tension. This assessment helps determine appropriate resolution approaches."
},
needs: {
needsText: "The facilitator guides participants in identifying their underlying needs and interests beyond their stated positions. These might include needs for respect, autonomy, fairness, safety, belonging, or understanding. The facilitator helps frame the dispute in terms of compatible needs rather than opposing positions."
},
evidence: {
evidenceText: "Relevant information is shared through the facilitator, who ensures all participants have access to the same information. The facilitator may request additional documentation or clarification as needed. Information is presented factually without accusatory language."
},
jurisdiction: {
jurisdictionText: "The facilitator helps determine if the chosen facilitator process is appropriate for the dispute. If the issue involves serious safety concerns, legal violations, or requires specialized expertise, the facilitator will recommend delegation to a more appropriate resource."
}
},
deliberation: {
information_gathering: {
informationGatheringText: "After initial perspectives are shared, the facilitator identifies information gaps and helps participants determine what additional information might be needed. They may assign 'homework' to gather specific information before the next session."
},
brainstorming: {
brainstormingText: "The facilitator leads a structured brainstorming session where all possible solutions are recorded without criticism. They may use techniques such as round-robin contribution or written idea submission to ensure everyone's ideas are included."
},
discussion: {
discussionText: "After brainstorming, the facilitator helps participants evaluate options based on previously identified needs and interests. They guide the discussion to focus on finding solutions that address the core concerns of all parties rather than positional bargaining."
},
deliberation_format: {
deliberationFormatText: "Deliberation typically involves 1-3 sessions of 90-120 minutes each, scheduled about a week apart. This provides time for reflection between sessions. The facilitator sets a clear agenda for each session and manages time to ensure productive discussion."
}
},
resolution: {
decision_making: {
decisionMakingText: "Decisions are made by consensus of the participants, with the facilitator helping to test whether proposed solutions are acceptable to everyone. The facilitator may use techniques like fist-to-five voting to gauge levels of support for proposals."
},
outcomes: {
outcomesText: "Typical outcomes include: 1) Mutual understanding and clarified expectations, 2) Specific action agreements with timelines, 3) Changes to procedures or resources, 4) Commitments to specific communication practices, 5) Relationship-rebuilding activities, or 6) Agreements about future conflict resolution if issues arise again."
},
agreement: {
agreementText: "The facilitator drafts a written agreement based on the decisions reached. The agreement includes specific, actionable items with timelines, how implementation will be verified, and a plan for addressing any future issues. All participants review, possibly revise, and sign the agreement."
},
follow_up: {
followUpText: "The facilitator schedules a follow-up check-in 3-4 weeks after the agreement is reached. This may be a meeting or individual check-ins to assess whether the agreement is working and address any implementation challenges."
},
announcement: {
announcementText: "The fact that a resolution has been reached may be shared with the Community Relations Committee, but the details remain confidential unless all participants agree to share specific information more widely."
}
},
appeal: {
criteria: {
criteriaText: "Appeals may be initiated if: 1) New information emerges that could significantly affect the agreement, 2) Circumstances change making the agreement unworkable, 3) There are persistent challenges implementing the agreement, or 4) One or more participants feel the process was unfair."
},
appeal_process: {
appealProcessText: "To appeal, a participant submits a written request to the Community Relations Committee explaining why they believe the agreement needs reconsideration. The committee reviews the request and contacts all original participants to determine next steps."
},
appeal_deliberation: {
appealDeliberationText: "If an appeal proceeds, a new facilitator is selected from the community to provide fresh perspective. This facilitator reviews documentation from the original process and conducts a new series of facilitated sessions focusing on the specific issues raised in the appeal."
},
appeal_resolution: {
appealResolutionText: "The appeal process results in either a confirmation of the original agreement, modifications to address specific concerns, or in some cases, a completely new agreement. The new or modified agreement is documented and signed by all participants."
}
},
delegation: {
criteria: {
criteriaText: "Delegation to a different process is appropriate when: 1) The facilitated process has been attempted without success, 2) The issue requires specialized expertise (legal, financial, therapeutic, etc.), 3) There are significant power imbalances that can't be addressed by a peer facilitator, 4) Safety concerns exist, or 5) The dispute has community-wide implications."
},
delegation_process: {
delegationProcessText: "The facilitator or Community Relations Committee may recommend delegation at any point in the process. They document the reason for delegation and what has been attempted so far. They then connect participants with appropriate resources, which may be within or outside the community."
},
delegation_authority: {
delegationAuthorityText: "The Community Relations Committee maintains a resource list of professional mediators, counselors, restorative justice practitioners, and legal resources. They have established relationships with these providers and can make direct referrals when needed. The community has a small fund to assist with costs if financial barriers exist."
}
}
}
}
},
{
id: "facilitation-council",
title: "Facilitation Council",
description: "A structured process with a trained council of facilitators who manage the dispute resolution process",
data: {
stages: {
intake: {
process_start: {
processStartText: "The dispute resolution process begins when an individual submits a formal request using the council's intake form. This form is available online and in hard copy at the community office. The form requires details about the nature of the dispute, parties involved, and previous resolution attempts. A member of the Facilitation Council acknowledges receipt within 24 hours and assigns an intake coordinator."
},
rules_access: {
rulesAccessText: "Community rules, bylaws, and the detailed dispute resolution protocol are maintained in a searchable online database with version history. Physical copies are available in the community center library. The Facilitation Council conducts quarterly workshops to educate community members about the rules and processes."
},
information_access: {
informationAccessText: "Information access follows a tiered model: 1) The involved parties and council members have full access to case documentation, 2) Council administrators track anonymized case data for process improvement, 3) Quarterly reports with statistical information and lessons learned (without identifying details) are shared with the community."
},
participant_inclusion: {
participantInclusionText: "The intake coordinator contacts all named parties within 48 hours via email and phone. They receive an explanation of the process, a copy of the initial request, information about their rights and responsibilities, and a response form to complete within 5 days. The coordinator offers to meet with each party individually to answer questions about the process."
},
participation_requirement: {
participationRequirementText: "Participation in the facilitation council process is required for active community members as specified in the community membership agreement. For non-members or in cases where mandatory participation would be inappropriate, the council works with willing participants and documents non-participation of others."
},
participation_commitments: {
participationCommitmentsText: "Participants commit to: 1) Providing complete and truthful information, 2) Respecting confidentiality, 3) Attending all scheduled meetings, 4) Engaging respectfully with all parties and council members, 5) Following the structured process, 6) Implementing agreed-upon resolutions, and 7) Participating in scheduled follow-up. These commitments are formalized in writing at the start of the process."
}
},
process: {
preparation: {
preparationText: "After intake, each party receives a preparation packet with: 1) A detailed statement form to document their perspective, 2) Instructions for gathering and submitting relevant evidence, 3) A guide for identifying potential witnesses, and 4) Reflection questions about desired outcomes. Parties have one week to complete these materials. Council members then review all materials before the first session and may request additional information."
},
place: {
placeText: "The council maintains a dedicated dispute resolution room in the community center, designed specifically for these processes. The room features a round table, comfortable seating, good acoustics, privacy screens, and necessary technology for sharing information. For complex cases with many participants, larger spaces can be reserved. Virtual participation options are available when in-person attendance is impossible."
},
facilitation: {
facilitationText: "Disputes are facilitated by a panel of 2-3 council members who have completed a comprehensive training program in conflict resolution, mediation, and restorative practices. The panel always includes diversity of perspectives and backgrounds. One member serves as the lead facilitator, while others may focus on documentation, process management, or emotional support. The council operates according to established procedures with flexibility to adapt to specific needs of each case."
},
communication: {
communicationText: "The council establishes and enforces clear communication protocols: 1) A talking piece indicates who has the floor, 2) Structured speaking order ensures equal voice, 3) Time limits for presentations may be used, 4) Direct communication between parties is facilitated when productive, 5) Council members summarize and reframe statements to ensure understanding, 6) Caucus sessions (private meetings) are available when needed, and 7) Written communication supplements verbal discussion for complex topics."
},
participation: {
participationText: "The process includes: 1) Primary parties to the dispute, 2) Council panel members, 3) Witnesses invited by either party or the council (for specific sessions only), 4) Support persons (one per participant, non-speaking unless invited), and 5) In cases affecting community standards, a community representative. For disputes involving allegations of harm, the council uses practices that prevent re-traumatization while ensuring fair process."
},
documentation: {
documentationText: "A designated council member maintains detailed documentation including: 1) Written submissions from all parties, 2) Minutes of all meetings with key points and decisions, 3) Supporting evidence and witness statements, 4) Audio recordings of sessions (with permission), 5) Written agreements, and 6) Follow-up reports. Parties receive copies of all non-confidential documentation. Records are securely stored according to the council's data retention policy."
}
},
assessment: {
situation: {
situationText: "The council conducts a structured assessment through: 1) Individual interviews with each party, 2) Review of written statements and evidence, 3) Consultation with relevant witnesses, 4) Consideration of applicable community agreements or policies, and 5) Discussion with the full council to identify the nature and scope of the dispute. The assessment is documented in a preliminary findings report shared with all parties."
},
stage_of_conflict: {
stageOfConflictText: "The council uses a formal assessment framework to determine: 1) The history and duration of the conflict, 2) The level of emotion and polarization between parties, 3) Whether communication between parties is still functional, 4) If the dispute is escalating or de-escalating, 5) The underlying causes (structural, relational, value-based, etc.), and 6) The potential community impact. This assessment determines the appropriate intervention approach and timeline."
},
needs: {
needsText: "The council works with each party to identify needs using a structured needs assessment tool that covers: 1) Physical needs (safety, resources, space), 2) Emotional needs (recognition, respect, belonging), 3) Procedural needs (voice, fairness, clarity), and 4) Identity needs (role, values, reputation). The council maps these needs to identify commonalities and differences, using this as a foundation for resolution options."
},
evidence: {
evidenceText: "The council has established procedures for evidence collection and evaluation: 1) Parties submit evidence following standardized guidelines, 2) A designated council member reviews all submissions for relevance and completeness, 3) Evidence is categorized and indexed, 4) All parties have equal access to non-confidential evidence, 5) The council may request additional evidence or clarification, and 6) When factual disputes persist, the council may consult appropriate experts or additional witnesses."
},
jurisdiction: {
jurisdictionText: "The council follows a jurisdictional assessment checklist to determine if the case is appropriate for their process. Cases involving serious legal violations, safety threats, or requiring specialized expertise beyond the council's capacity are referred to appropriate authorities. For complex cases, the council may establish jurisdiction over certain aspects while referring others. The assessment considers legal requirements, community capacity, and the nature of the dispute."
}
},
deliberation: {
information_gathering: {
informationGatheringText: "The council uses a structured information gathering process: 1) Initial statements from all parties, 2) Clarifying questions from council members, 3) Testimony from relevant witnesses, 4) Review of documentary evidence, 5) Expert input if needed for technical matters, and 6) Community standard review when applicable. Information gathering follows a predetermined schedule with deadlines for submissions and specific session agendas."
},
brainstorming: {
brainstormingText: "Facilitated brainstorming sessions use specific methodologies including: 1) Individual brainstorming where each party independently generates solutions, 2) Council-moderated joint sessions using visual mapping tools, 3) Structured brainstorming techniques such as nominal group process or rounds, and 4) Consideration of precedents from similar cases. All options are documented without evaluation during the brainstorming phase."
},
discussion: {
discussionText: "Discussion follows a structured format: 1) Review of brainstormed options, 2) Evaluation against previously identified needs and community values, 3) Consideration of implementation feasibility, 4) Discussion of modifications to promising options, 5) Council-facilitated negotiations on specific details, and 6) Caucus sessions when needed for private discussion. The council maintains focus on interests rather than positions and ensures balanced participation."
},
deliberation_format: {
deliberationFormatText: "The council uses a multi-stage deliberation format: 1) Preliminary council-only meeting to review all materials and plan the process, 2) Joint sessions with all parties following a structured agenda, 3) Separate sessions with individual parties as needed, 4) Council executive sessions to assess progress and adjust process, 5) Final resolution session(s). Most cases involve 3-5 sessions of 2-3 hours each over a 2-4 week period, with a detailed schedule provided at the outset."
}
},
resolution: {
decision_making: {
decisionMakingText: "The council uses a tiered decision-making approach: 1) Facilitated consensus among parties is the preferred method, with the council helping parties reach mutually acceptable agreements, 2) If consensus cannot be reached on all issues after good faith efforts, parties may authorize the council to make recommendations on specific points, 3) In cases involving community standards or policies, the council may make binding decisions following established criteria. The basis for all decisions is documented."
},
outcomes: {
outcomesText: "Resolution outcomes may include: 1) Written agreements between parties with specific commitments, 2) Action plans with timelines and accountability measures, 3) Restorative agreements to address harm, 4) Resource allocation decisions, 5) Clarification of policies or expectations, 6) Structural changes to prevent future conflicts, 7) Educational or training requirements, and 8) Recommendations to community governance bodies for policy changes. All outcomes include clear implementation plans."
},
agreement: {
agreementText: "Agreements are documented using a standard format that includes: 1) Names and roles of all parties, 2) Summary of the dispute and process, 3) Specific agreements with detailed action items, 4) Timelines for implementation, 5) Verification methods, 6) Consequences for non-compliance if applicable, 7) Privacy and communication guidelines, 8) Follow-up schedule, 9) Process for addressing future disputes or agreement modifications, and 10) Signatures of all parties and facilitating council members."
},
follow_up: {
followUpText: "The council implements a multi-stage follow-up process: 1) Initial check-in 2 weeks after agreement, 2) Formal review meeting at 1-3 months, 3) Final assessment at 6 months, 4) Additional check-ins as specified in the agreement. A designated council member serves as agreement monitor, collecting implementation evidence and facilitating resolution of any implementation challenges."
},
announcement: {
announcementText: "The council follows structured guidelines for announcements: 1) Parties and council members agree on what information will be shared, 2) A brief, factual summary is prepared noting that a resolution has been reached (without private details), 3) Any community-wide implications or policy changes are communicated through established channels, 4) In cases of broad community impact, educational sessions may be held to share lessons learned while respecting confidentiality, 5) Statistical information is included in quarterly council reports."
}
},
appeal: {
criteria: {
criteriaText: "Appeals may be filed when: 1) New, significant evidence emerges that was not available during the original process, 2) There was a substantial procedural error that may have affected the outcome, 3) The agreement has proven unworkable despite good faith implementation efforts, or 4) There has been a significant change in circumstances that renders the agreement ineffective. Appeals must be filed within 30 days of discovering the grounds for appeal."
},
appeal_process: {
appealProcessText: "The appeal process includes: 1) Submission of a formal appeal request specifying grounds for appeal and desired outcome, 2) Review by council members not involved in the original case to determine if appeal criteria are met, 3) Notification to all original parties, 4) If accepted, assignment of a new council panel, 5) Structured review of original documentation and new evidence, 6) Limited-scope hearings focused on appeal issues, 7) Decision rendered within 30 days of appeal acceptance."
},
appeal_deliberation: {
appealDeliberationText: "Appeal deliberations follow a specialized process: 1) The appeal panel first reviews all documentation from the original process, 2) New evidence or procedural concerns are examined in detail, 3) Limited testimony may be heard specifically related to appeal grounds, 4) The panel deliberates using a structured framework for evaluating whether the original outcome should stand, be modified, or be replaced, 5) Deliberations are documented with specific reasoning for decisions."
},
appeal_resolution: {
appealResolutionText: "Appeal resolutions are documented in a formal decision that includes: 1) Summary of the original case and resolution, 2) Grounds for appeal and additional evidence considered, 3) Analysis of how the appeal criteria were or were not met, 4) Specific modifications to the original agreement if applicable, 5) Implementation plan for any changes, 6) Statement of finality indicating whether further appeals are possible, and 7) Signatures of appeal panel members. All parties receive this document and acknowledge receipt."
}
},
delegation: {
criteria: {
criteriaText: "Cases are delegated when: 1) They involve legal issues beyond the council's authority, 2) Specialized expertise is required (legal, psychological, financial, etc.), 3) Safety concerns exceed the council's capacity to address, 4) Conflicts of interest make impartial council deliberation impossible, 5) The case has implications beyond the immediate community requiring broader involvement, or 6) Multiple attempts at resolution through the council process have failed."
},
delegation_process: {
delegationProcessText: "The delegation process involves: 1) Identification of delegation need either at intake or during the process, 2) Council deliberation and formal vote on delegation recommendation, 3) Documentation of reasons for delegation and process to date, 4) Consultation with parties about appropriate external resources, 5) Formal referral including transfer of relevant documentation (with permission), 6) Assignment of a council liaison to support transition and maintain communication, 7) Closure of the council process with clear communication about next steps."
},
delegation_authority: {
delegationAuthorityText: "The council maintains formal relationships with: 1) A panel of professional mediators with different specializations, 2) Legal resources including community legal aid, 3) Mental health professionals for cases involving trauma or psychological concerns, 4) Restorative justice practitioners for cases involving harm, 5) Subject matter experts in relevant fields, and 6) Regional conflict resolution centers. Annual budget is allocated for professional services when needed, and financial assistance is available to ensure access regardless of ability to pay."
}
}
}
}
}
];
// Make sure rawProtocolTemplates is available globally
window.rawProtocolTemplates = rawProtocolTemplates;

26
static/js/debug.js Normal file

@ -0,0 +1,26 @@
console.log('Testing toggle button functionality');
// Debug script to inspect template loading
console.log("Debug script loaded");
document.addEventListener('DOMContentLoaded', function() {
console.log("DOM loaded in debug script");
// Log raw templates
console.log("Raw Protocol Templates:", typeof rawProtocolTemplates !== 'undefined' ? rawProtocolTemplates.length : "undefined");
if (typeof rawProtocolTemplates !== 'undefined') {
console.log("Template titles:", rawProtocolTemplates.map(t => t.title));
}
// Log processed templates
setTimeout(() => {
const templateSelect = document.getElementById('protocol-template');
if (templateSelect) {
console.log("Template options:", templateSelect.options.length);
const options = Array.from(templateSelect.options).map(o => o.textContent);
console.log("Option texts:", options);
} else {
console.log("Template select element not found");
}
}, 1000);
});

25
static/js/fix-dropdown.js Normal file

@ -0,0 +1,25 @@
// Make sure the dropdown works correctly
document.addEventListener('DOMContentLoaded', function() {
const exportBtn = document.getElementById('export-btn');
const dropdownMenu = document.querySelector('.dropdown-menu');
if (exportBtn && dropdownMenu) {
// Force clear any previous event listeners
const newExportBtn = exportBtn.cloneNode(true);
exportBtn.parentNode.replaceChild(newExportBtn, exportBtn);
// Add event listener to the new button
newExportBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
dropdownMenu.style.display = dropdownMenu.style.display === 'block' ? 'none' : 'block';
});
// Close dropdown when clicking elsewhere
document.addEventListener('click', function(e) {
if (newExportBtn && \!newExportBtn.contains(e.target) && dropdownMenu && \!dropdownMenu.contains(e.target)) {
dropdownMenu.style.display = 'none';
}
});
}
});

695
static/js/modules-page.js Normal file

@ -0,0 +1,695 @@
document.addEventListener('DOMContentLoaded', function() {
console.log('Modules page initializing...');
// Reference to container and filters
const modulesContainer = document.getElementById('modules-container');
const moduleSearch = document.getElementById('module-search');
const stageFilter = document.getElementById('stage-filter');
const componentFilter = document.getElementById('component-filter');
const templateFilter = document.getElementById('template-filter');
// Data structures
let allModules = [];
let stageNames = {};
let componentNames = {};
let templateUsage = {};
let processedTemplates = [];
// Functions
function initializeData() {
console.log('Initializing data...');
// Check if data is available
if (typeof moduleData === 'undefined') {
console.error('Error: moduleData is undefined');
modulesContainer.innerHTML = '<div class="error">Error: Module data not available</div>';
return false;
}
if (typeof rawProtocolTemplates === 'undefined' || typeof templateMapper === 'undefined') {
console.error('Error: Template data or mapper not available');
modulesContainer.innerHTML = '<div class="error">Error: Template data not available</div>';
return false;
}
// Log what we're working with
console.log('Module categories:', Object.keys(moduleData));
console.log('Templates count:', rawProtocolTemplates.length);
try {
// Process templates
rawProtocolTemplates.forEach(template => {
const processedTemplate = templateMapper.convertTemplateToModules(template, moduleData);
processedTemplates.push(processedTemplate);
});
// Collect all modules into a flat array
for (const category in moduleData) {
moduleData[category].forEach(module => {
// Add category to module
module.category = category;
// Initialize template usage
module.usedInTemplates = [];
// Ensure all modules have a componentId - no uncategorized modules allowed
if (!module.componentId) {
// Try to infer from category first
if (category !== 'uncategorized') {
console.log(`Module ${module.id} missing componentId, using category: ${category}`);
module.componentId = category;
}
// If that doesn't work, infer from title or content
else {
// First, try to find clues in the title
if (module.title) {
const titleLower = module.title.toLowerCase();
// Check for key component names in the title
if (titleLower.includes('principle')) module.componentId = 'principles';
else if (titleLower.includes('process')) module.componentId = 'process';
else if (titleLower.includes('assessment')) module.componentId = 'assessment';
else if (titleLower.includes('intake')) module.componentId = 'intake';
else if (titleLower.includes('appeal')) module.componentId = 'appeal';
else if (titleLower.includes('deliberat')) module.componentId = 'deliberation';
else if (titleLower.includes('resolut')) module.componentId = 'resolution';
else if (titleLower.includes('facilit')) module.componentId = 'facilitation';
else if (titleLower.includes('particip')) module.componentId = 'participants';
else if (titleLower.includes('file') || titleLower.includes('submit')) module.componentId = 'filing';
else if (titleLower.includes('notif') || titleLower.includes('inform')) module.componentId = 'notification';
else if (titleLower.includes('delegat')) module.componentId = 'delegation';
else module.componentId = 'process'; // Default to process
}
// If no title clues, check content
else if (module.content) {
const contentLower = module.content.toLowerCase();
// Same checks in content
if (contentLower.includes('principle')) module.componentId = 'principles';
else if (contentLower.includes('process')) module.componentId = 'process';
else if (contentLower.includes('assessment')) module.componentId = 'assessment';
else if (contentLower.includes('intake')) module.componentId = 'intake';
else if (contentLower.includes('appeal')) module.componentId = 'appeal';
else if (contentLower.includes('deliberat')) module.componentId = 'deliberation';
else if (contentLower.includes('resolut')) module.componentId = 'resolution';
else if (contentLower.includes('facilit')) module.componentId = 'facilitation';
else if (contentLower.includes('particip')) module.componentId = 'participants';
else if (contentLower.includes('file') || contentLower.includes('submit')) module.componentId = 'filing';
else if (contentLower.includes('notif') || contentLower.includes('inform')) module.componentId = 'notification';
else if (contentLower.includes('delegat')) module.componentId = 'delegation';
else module.componentId = 'process'; // Default to process
}
// Last resort default
else {
module.componentId = 'process';
}
console.log(`Module ${module.id} had no componentId, assigned to: ${module.componentId}`);
}
}
// Add to all modules array
allModules.push(module);
});
}
console.log('Total modules collected:', allModules.length);
// Track which templates use each module
processedTemplates.forEach(template => {
for (const stageId in template.moduleRefs) {
if (!stageNames[stageId]) {
// Create a readable stage name
stageNames[stageId] = stageId.charAt(0).toUpperCase() + stageId.slice(1).replace(/_/g, ' ');
}
for (const componentId in template.moduleRefs[stageId]) {
if (!componentNames[componentId]) {
// Create a readable component name
componentNames[componentId] = componentId.charAt(0).toUpperCase() + componentId.slice(1).replace(/_/g, ' ');
}
for (const fieldId in template.moduleRefs[stageId][componentId]) {
const moduleId = template.moduleRefs[stageId][componentId][fieldId];
// Find the module with this id
const matchingModule = allModules.find(m => m.id === moduleId);
if (matchingModule) {
// Add template to module's usage
if (!matchingModule.usedInTemplates.includes(template.title)) {
matchingModule.usedInTemplates.push(template.title);
}
// Set stage and component for the module if not already set
if (!matchingModule.stageId) {
matchingModule.stageId = stageId;
}
// Track template usage
if (!templateUsage[template.title]) {
templateUsage[template.title] = [];
}
if (!templateUsage[template.title].includes(moduleId)) {
templateUsage[template.title].push(moduleId);
}
}
}
}
}
});
// Define official stages from YAML file
const officialStages = {
'intake': 'Intake',
'process': 'Process',
'assessment': 'Assessment',
'deliberation': 'Deliberation',
'resolution': 'Resolution',
'appeal': 'Appeal',
'delegation': 'Delegation'
};
// Define official components with standardized display names
const officialComponents = {
// Process stage components
'principles': 'Principles',
'community_values': 'Values',
'participants': 'Participants',
'facilitation': 'Facilitation',
'ground_rules': 'Ground Rules',
'skills': 'Skills',
// Intake stage components
'process_start': 'Process Start',
'filing': 'Filing',
'notification': 'Notification',
'rules_access': 'Rules Access',
'information_access': 'Information Access',
'participant_inclusion': 'Participant Inclusion',
// Assessment stage components
'dispute_assessment': 'Assessment',
'values_adherence': 'Values Adherence',
'jurisdiction': 'Jurisdiction',
// Deliberation stage components
'deliberation_process': 'Deliberation Process',
'additional_voices': 'Additional Voices',
'deliberation_conclusion': 'Deliberation Conclusion',
// Resolution stage components
'resolution_process': 'Resolution Process',
'resolution_failure': 'Resolution Failure',
// Appeal stage components
'appeal_criteria': 'Appeal Criteria',
'appeal_process': 'Appeal Process',
// Delegation stage components
'delegation_options': 'Delegation Options'
};
// Map all component IDs (including custom ones) to official stages
const componentToStageMap = {
// Process stage components
'principles': 'process',
'community_values': 'process',
'participants': 'process',
'facilitation': 'process',
'ground_rules': 'process',
'skills': 'process',
'values': 'process',
'agreements': 'process',
'participation_commitments': 'process',
// Intake stage components
'process_start': 'intake',
'filing': 'intake',
'notification': 'intake',
'rules_access': 'intake',
'information_access': 'intake',
'participant_inclusion': 'intake',
'reporting': 'intake',
// Assessment stage components
'dispute_assessment': 'assessment',
'values_adherence': 'assessment',
'jurisdiction': 'assessment',
'non_participation': 'assessment',
// Deliberation stage components
'deliberation_process': 'deliberation',
'additional_voices': 'deliberation',
'deliberation_conclusion': 'deliberation',
'decision_making': 'deliberation',
'discussion': 'deliberation',
// Resolution stage components
'resolution_process': 'resolution',
'resolution_failure': 'resolution',
// Appeal stage components
'appeal_criteria': 'appeal',
'appeal_process': 'appeal',
'appeal_deliberation': 'appeal',
'appeal_resolution': 'appeal',
// Delegation stage components
'delegation_options': 'delegation'
};
// Map non-standard components to official ones
const componentMapping = {
'direct_conversation': 'deliberation_process',
'conflict_awareness': 'dispute_assessment',
'accessing_help': 'process_start',
'preparation': 'principles',
'selection': 'participant_inclusion',
'criteria': 'appeal_criteria',
'agreement': 'resolution_process',
'process': 'principles',
'process_change': 'resolution_failure',
'assessment': 'dispute_assessment',
'situation': 'dispute_assessment',
'reflection': 'deliberation_conclusion',
'monitoring': 'dispute_assessment',
'participation_requirement': 'participant_inclusion'
};
allModules.forEach(module => {
// If module has no stageId, try to infer from category
if (!module.stageId && module.category) {
// Check if category matches a known stage
if (stageNames[module.category]) {
module.stageId = module.category;
} else {
// Use category as stageId if not already recognized
module.stageId = module.category;
// Create a readable stage name from category
stageNames[module.category] = module.category.charAt(0).toUpperCase() +
module.category.slice(1).replace(/_/g, ' ');
}
}
// If still no stageId, try to infer from componentId using the mapping
if (!module.stageId && module.componentId) {
const mappedStage = componentToStageMap[module.componentId];
if (mappedStage) {
module.stageId = mappedStage;
console.log(`Module ${module.id} missing stageId, inferred from component: ${mappedStage}`);
} else {
// Default stage if no mapping exists
module.stageId = 'process';
console.log(`Module ${module.id} missing stageId, defaulting to: process`);
}
}
// If STILL no stageId (somehow), assign to process
if (!module.stageId) {
module.stageId = 'process';
console.log(`Module ${module.id} had no stageId, assigned to: process`);
}
// Force module to use only official stages
if (officialStages[module.stageId]) {
// Use official stage name
module.stageName = officialStages[module.stageId];
} else {
// Map to closest official stage
const mappedStage = componentToStageMap[module.componentId];
if (mappedStage && officialStages[mappedStage]) {
module.stageId = mappedStage;
module.stageName = officialStages[mappedStage];
console.log(`Module ${module.id} had invalid stage "${module.stageId}", remapped to: ${mappedStage}`);
} else {
// Default to Process stage if can't map anywhere else
module.stageId = 'process';
module.stageName = officialStages['process'];
console.log(`Module ${module.id} had invalid stage "${module.stageId}", defaulting to: Process`);
}
}
// Handle component mapping for non-standard components
if (componentMapping[module.componentId]) {
const originalComponentId = module.componentId;
module.componentId = componentMapping[originalComponentId];
console.log(`Module ${module.id} had non-standard component "${originalComponentId}", mapped to: ${module.componentId}`);
}
// Set a readable component name using official list
if (officialComponents[module.componentId]) {
module.componentName = officialComponents[module.componentId];
} else {
// Generate a readable name for custom components
module.componentName = module.componentId.charAt(0).toUpperCase() +
module.componentId.slice(1).replace(/_/g, ' ');
// Log any component not in the official list
console.log(`Module ${module.id} uses custom component: ${module.componentId}`);
}
});
// Log the distribution of modules by stage
const stageDistribution = {};
allModules.forEach(module => {
stageDistribution[module.stageName] = (stageDistribution[module.stageName] || 0) + 1;
});
console.log('Module distribution by stage:', stageDistribution);
console.log('Data initialization complete');
console.log('Stages:', Object.keys(stageNames));
console.log('Components:', Object.keys(componentNames));
console.log('Templates:', Object.keys(templateUsage));
return true;
} catch (error) {
console.error('Error initializing data:', error);
modulesContainer.innerHTML = `<div class="error">Error initializing data: ${error.message}</div>`;
return false;
}
}
function populateFilters() {
console.log('Populating filters...');
// Clear existing options
stageFilter.innerHTML = '<option value="">All Stages</option>';
componentFilter.innerHTML = '<option value="">All Components</option>';
templateFilter.innerHTML = '<option value="">All Templates</option>';
// Get unique stages and components
const stages = [...new Set(allModules.map(m => m.stageName))].sort();
const components = [...new Set(allModules.map(m => m.componentName))].sort();
const templates = Object.keys(templateUsage).sort();
console.log('Filter options - Stages:', stages);
console.log('Filter options - Components:', components);
console.log('Filter options - Templates:', templates);
// Add options to filters
stages.forEach(stage => {
const option = document.createElement('option');
option.value = stage;
option.textContent = stage;
stageFilter.appendChild(option);
});
components.forEach(component => {
const option = document.createElement('option');
option.value = component;
option.textContent = component;
componentFilter.appendChild(option);
});
templates.forEach(template => {
const option = document.createElement('option');
option.value = template;
option.textContent = template;
templateFilter.appendChild(option);
});
}
function renderModules() {
console.log('Rendering modules...');
// Clear container
modulesContainer.innerHTML = '';
// Get filter values
const searchText = moduleSearch.value.toLowerCase();
const stageValue = stageFilter.value;
const componentValue = componentFilter.value;
const templateValue = templateFilter.value;
console.log('Filter values:', {
search: searchText,
stage: stageValue,
component: componentValue,
template: templateValue
});
// Create a stage-based organization of modules
const modulesByStage = {};
// Filter modules based on search and filter criteria
allModules.forEach(module => {
// Check if module matches search text
const matchesSearch = searchText === '' ||
module.title.toLowerCase().includes(searchText) ||
(module.content && module.content.toLowerCase().includes(searchText));
// Check if module matches stage filter
const matchesStage = stageValue === '' || module.stageName === stageValue;
// Check if module matches component filter
const matchesComponent = componentValue === '' || module.componentName === componentValue;
// Check if module matches template filter
const matchesTemplate = templateValue === '' ||
module.usedInTemplates.includes(templateValue);
// Include module if it matches all criteria
if (matchesSearch && matchesStage && matchesComponent && matchesTemplate) {
// Initialize stage object if not exists
if (!modulesByStage[module.stageName]) {
modulesByStage[module.stageName] = [];
}
// Add module to its stage
modulesByStage[module.stageName].push(module);
}
});
// Sort stages according to the official order from the YAML file
const stageOrder = [
'Intake', 'Process', 'Assessment',
'Deliberation', 'Resolution', 'Appeal', 'Delegation'
];
// Get all stages from the data
const availableStages = Object.keys(modulesByStage);
// Sort stages according to the defined order, with any others at the end
const sortedStages = [];
// First add stages in the predefined order (if they exist in the data)
stageOrder.forEach(stage => {
if (availableStages.includes(stage)) {
sortedStages.push(stage);
}
});
// Then add any other stages not in the predefined order (sorted alphabetically)
availableStages
.filter(stage => !stageOrder.includes(stage))
.sort()
.forEach(stage => sortedStages.push(stage));
// If no modules match, show message
if (sortedStages.length === 0) {
modulesContainer.innerHTML = '<div class="no-results">No modules match your search criteria</div>';
return;
}
// Create HTML for each stage and its modules
sortedStages.forEach(stageName => {
const stageModules = modulesByStage[stageName];
// Create stage section using similar structure to builder
const stageSection = document.createElement('div');
stageSection.className = 'stage-section';
// Create stage header
const stageHeader = document.createElement('div');
stageHeader.className = 'stage-header';
const stageHeaderContent = document.createElement('div');
stageHeaderContent.className = 'stage-header-content';
stageHeaderContent.innerHTML = `
<h2>${stageName}</h2>
<div class="stage-brief">
Contains ${stageModules.length} module${stageModules.length !== 1 ? 's' : ''}
</div>
`;
// Create toggle button
const toggleBtn = document.createElement('button');
toggleBtn.className = 'toggle-btn';
toggleBtn.innerHTML = '+';
toggleBtn.setAttribute('aria-label', 'Toggle stage content');
stageHeader.appendChild(stageHeaderContent);
stageHeader.appendChild(toggleBtn);
stageSection.appendChild(stageHeader);
// Create stage body
const stageBody = document.createElement('div');
stageBody.className = 'stage-body';
stageBody.style.display = 'none';
// Group modules by component
const modulesByComponent = {};
stageModules.forEach(module => {
// Use just the component name without duplicating stage info
const cleanComponentName = module.componentName.replace(module.stageName, '').trim();
const displayComponentName = cleanComponentName || module.componentName;
if (!modulesByComponent[displayComponentName]) {
modulesByComponent[displayComponentName] = [];
}
modulesByComponent[displayComponentName].push(module);
});
// Sort components
const sortedComponents = Object.keys(modulesByComponent).sort();
// Create components container
const componentsContainer = document.createElement('div');
componentsContainer.className = 'components';
// Create component sections
sortedComponents.forEach(componentName => {
const componentModules = modulesByComponent[componentName];
// Create a component group heading with count
const componentHeading = document.createElement('h3');
componentHeading.className = 'component-group-heading';
// Create main text
const headingText = document.createTextNode(componentName);
componentHeading.appendChild(headingText);
// Add count in parentheses
const moduleCount = componentModules.length;
const countSpan = document.createElement('span');
countSpan.className = 'component-module-count';
countSpan.textContent = ` (${moduleCount} module${moduleCount !== 1 ? 's' : ''})`;
componentHeading.appendChild(countSpan);
componentsContainer.appendChild(componentHeading);
// Add modules to component section
componentModules.forEach(module => {
const moduleCard = createModuleCard(module);
componentsContainer.appendChild(moduleCard);
});
});
stageBody.appendChild(componentsContainer);
stageSection.appendChild(stageBody);
// Add toggle functionality
stageHeaderContent.addEventListener('click', function() {
if (stageBody.style.display === 'none') {
stageBody.style.display = 'block';
toggleBtn.innerHTML = '';
} else {
stageBody.style.display = 'none';
toggleBtn.innerHTML = '+';
}
});
toggleBtn.addEventListener('click', function(e) {
e.stopPropagation();
if (stageBody.style.display === 'none') {
stageBody.style.display = 'block';
toggleBtn.innerHTML = '';
} else {
stageBody.style.display = 'none';
toggleBtn.innerHTML = '+';
}
});
modulesContainer.appendChild(stageSection);
});
console.log('Modules rendering complete');
}
function createModuleCard(module) {
const card = document.createElement('div');
card.className = 'component-card';
card.dataset.id = module.id;
// Format templates list
const templatesList = module.usedInTemplates.length > 0
? module.usedInTemplates.join(', ')
: 'Not used in any template';
// Create card content with structure similar to builder component
card.innerHTML = `
<div class="component-header">
<h3>${module.title}</h3>
</div>
<div class="component-body">
<div class="module-meta">
<span class="tag stage-tag">${module.stageName}</span>
<span class="tag component-tag">${module.componentName}</span>
</div>
<div class="module-content">
<textarea readonly>${module.content}</textarea>
</div>
<div class="module-templates">
<strong>Used in templates:</strong> ${templatesList}
</div>
</div>
`;
// Make the header clickable to toggle content visibility
const header = card.querySelector('.component-header');
const body = card.querySelector('.component-body');
// Add toggle button to the header (already positioned by CSS flexbox)
const toggleBtn = document.createElement('button');
toggleBtn.className = 'toggle-btn';
toggleBtn.innerHTML = '+';
toggleBtn.setAttribute('aria-label', 'Toggle module content');
header.appendChild(toggleBtn);
// Start with content hidden
body.style.display = 'none';
// Toggle functionality
function toggleContent() {
if (body.style.display === 'none') {
body.style.display = 'block';
toggleBtn.innerHTML = '';
card.classList.add('expanded');
} else {
body.style.display = 'none';
toggleBtn.innerHTML = '+';
card.classList.remove('expanded');
}
}
header.addEventListener('click', toggleContent);
return card;
}
// Initialize page
function init() {
console.log('Initializing modules page...');
// Load data
if (!initializeData()) {
console.error('Failed to initialize data');
return;
}
// Populate filters
populateFilters();
// Render modules
renderModules();
// Add event listeners to filters
moduleSearch.addEventListener('input', renderModules);
stageFilter.addEventListener('change', renderModules);
componentFilter.addEventListener('change', renderModules);
templateFilter.addEventListener('change', renderModules);
console.log('Modules page initialized with', allModules.length, 'modules');
}
// Start initialization
init();
});

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2025 YOUR_NAME_HERE
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

@ -0,0 +1,2 @@
+++
+++

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
{{- partial "head.html" . -}}
<body>
{{- partial "header.html" . -}}
<div id="content">
{{- block "main" . }}{{- end }}
</div>
{{- partial "footer.html" . -}}
</body>
</html>

@ -0,0 +1,290 @@
{{ define "main" }}
<div class="builder-container">
<h1>{{ .Title }}</h1>
{{ .Content }}
<div id="protocol-builder" class="builder">
<div class="builder-main">
<div class="protocol-metadata">
<div class="metadata-field">
<label for="community-name">Community Name:</label>
<input type="text" id="community-name" name="community-name" placeholder="Enter your community name...">
</div>
<div class="metadata-field">
<label for="protocol-summary">Protocol Summary:</label>
<textarea id="protocol-summary" name="protocol-summary" placeholder="Briefly describe this dispute resolution protocol and its purpose..."></textarea>
</div>
</div>
<div class="protocol-template-selector">
<label for="protocol-template">Select a Protocol Template:</label>
<select id="protocol-template" class="protocol-template-select">
<option value="">-- Create Your Own Protocol --</option>
<!-- Template options will be populated by JavaScript -->
</select>
</div>
<div class="builder-content">
{{ range $.Site.Data.stages.stages }}
<div class="stage-section" id="stage-{{ .id }}">
<div class="stage-header" data-stage="{{ .id }}">
<div class="stage-header-content">
<h2>{{ .title }}</h2>
<p class="stage-brief">{{ .description }}</p>
</div>
<button type="button" class="toggle-btn" aria-label="Toggle section" onclick="toggleStage(this)">+</button>
</div>
<div class="stage-body">
<div class="components">
{{ $stageId := .id }}
{{ $componentFile := printf "%s" $stageId }}
{{ range index $.Site.Data.components $componentFile }}
{{ $componentId := .id }}
<div class="component-card" id="component-{{ $componentId }}">
<div class="component-header">
<div class="component-title-wrapper">
<div class="component-short-label">{{ $componentId | humanize }}</div>
<h3>{{ .title }}</h3>
</div>
</div>
<div class="component-body">
{{ range .fields }}
<div class="field" id="field-{{ .id }}">
<div class="module-selector">
<label for="module-{{ .id }}">Select a module:</label>
<select id="module-{{ .id }}" class="module-select" data-field-id="{{ .id }}" data-component-id="{{ $componentId }}">
<option value="">-- Choose a module --</option>
</select>
</div>
<textarea id="{{ .id }}" name="{{ .id }}" placeholder="{{ .placeholder }}" {{ if .required }}required{{ end }}></textarea>
</div>
{{ end }}
</div>
</div>
{{ end }}
</div>
</div>
</div>
{{ end }}
</div>
<!-- Export buttons moved to sidebar -->
</div>
<div class="builder-sidebar">
<div class="sidebar-section">
<h3>Tools</h3>
<div id="sidebar-nav" class="sidebar-nav">
<h4>Jump to Section</h4>
<div class="sidebar-nav-content">
<div class="nav-tree">
{{ range $.Site.Data.stages.stages }}
<div class="nav-stage">
<a href="#stage-{{ .id }}" class="nav-stage-link">{{ .title }}</a>
<div class="nav-components">
{{ $stageId := .id }}
{{ $componentFile := printf "%s" $stageId }}
{{ range index $.Site.Data.components $componentFile }}
<a href="#component-{{ .id }}" class="nav-component-link">{{ .title }}</a>
{{ end }}
</div>
</div>
{{ end }}
</div>
</div>
</div>
<div class="sidebar-toggle" style="margin-top: 1.5rem;">
<label class="toggle-switch" for="preview-toggle">
<input type="checkbox" id="preview-toggle">
<span class="toggle-slider"></span>
<span class="toggle-label">Preview Mode</span>
</label>
</div>
<div class="sidebar-info">
<p>Preview mode shows only completed elements.</p>
</div>
</div>
<div class="sidebar-section">
<h3>Export Options</h3>
<div class="sidebar-export-options">
<a href="#" id="export-md" class="sidebar-btn">Export Markdown</a>
<a href="#" id="export-pdf" class="sidebar-btn">Export PDF</a>
<a href="#" id="export-json" class="sidebar-btn">Export JSON</a>
<button id="import-btn" class="sidebar-btn">Import JSON</button>
<input type="file" id="import-json" accept=".json" style="display: none;">
</div>
</div>
</div>
</div>
</div>
<!-- Scripts are loaded in head.html -->
<script>
function toggleStage(button) {
const section = button.closest('.stage-section');
const body = section.querySelector('.stage-body');
if (body.style.display === 'block') {
body.style.display = 'none';
button.textContent = '+';
} else {
body.style.display = 'block';
button.textContent = '-';
}
// Prevent event from propagating
event.stopPropagation();
}
// Make headers also toggle sections
document.addEventListener('DOMContentLoaded', function() {
const headers = document.querySelectorAll('.stage-header-content');
headers.forEach(header => {
header.addEventListener('click', function() {
const stageHeader = this.closest('.stage-header');
const toggleButton = stageHeader.querySelector('.toggle-btn');
toggleButton.click();
});
});
// Export dropdown removed (moved to sidebar)
// Preview Mode Toggle
const previewToggle = document.getElementById('preview-toggle');
if (previewToggle) {
previewToggle.addEventListener('change', function() {
if (this.checked) {
enablePreviewMode();
} else {
disablePreviewMode();
}
});
}
function enablePreviewMode() {
// Create style element
let style = document.createElement('style');
style.id = 'preview-style';
style.innerHTML = `
.module-selector { display: none !important; }
.field:not(.has-content) { display: none !important; }
.component-card:not(.has-content) { display: none !important; }
.stage-section:not(.has-content) { display: none !important; }
.protocol-template-selector { display: none !important; }
.stage-body { display: block !important; }
textarea {
border: none !important;
background-color: transparent !important;
padding: 0 !important;
min-height: unset !important;
height: auto !important;
resize: none !important;
pointer-events: none !important;
overflow: visible !important;
white-space: pre-wrap !important;
width: 100% !important;
word-wrap: break-word !important;
}
.component-header {
background-color: transparent !important;
border-bottom: none !important;
}
.component-short-label { display: none !important; }
`;
document.head.appendChild(style);
// Mark elements with content
document.querySelectorAll('textarea').forEach(textarea => {
if (textarea.value && textarea.value.trim()) {
const field = textarea.closest('.field');
if (field) field.classList.add('has-content');
const component = textarea.closest('.component-card');
if (component) component.classList.add('has-content');
const stage = textarea.closest('.stage-section');
if (stage) stage.classList.add('has-content');
}
});
// Make fields read-only
document.querySelectorAll('textarea, #community-name, #protocol-summary').forEach(el => {
el.readOnly = true;
});
}
function disablePreviewMode() {
// Remove preview styles
const style = document.getElementById('preview-style');
if (style) {
style.parentNode.removeChild(style);
}
// Remove content markers
document.querySelectorAll('.has-content').forEach(el => {
el.classList.remove('has-content');
});
// Make fields editable again
document.querySelectorAll('textarea, #community-name, #protocol-summary').forEach(el => {
el.readOnly = false;
});
}
// Initialize the sidebar navigation
initSidebarNavigation();
});
// Initialize the sidebar navigation
function initSidebarNavigation() {
// Set up click handlers for navigation links
document.querySelectorAll('.nav-stage-link, .nav-component-link').forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
// Get the target element's ID from the href
const targetId = this.getAttribute('href').substring(1);
const targetElement = document.getElementById(targetId);
if (targetElement) {
// If it's a stage, make sure it's expanded
if (targetId.startsWith('stage-')) {
const stageBody = targetElement.querySelector('.stage-body');
const toggleBtn = targetElement.querySelector('.toggle-btn');
if (stageBody && stageBody.style.display !== 'block') {
stageBody.style.display = 'block';
if (toggleBtn) toggleBtn.textContent = '-';
}
}
// If it's a component, make sure its parent stage is expanded
if (targetId.startsWith('component-')) {
const stageSection = targetElement.closest('.stage-section');
if (stageSection) {
const stageBody = stageSection.querySelector('.stage-body');
const toggleBtn = stageSection.querySelector('.toggle-btn');
if (stageBody && stageBody.style.display !== 'block') {
stageBody.style.display = 'block';
if (toggleBtn) toggleBtn.textContent = '-';
}
}
}
// Scroll to the target with some offset to account for sticky headers
window.scrollTo({
top: targetElement.offsetTop - 20,
behavior: 'smooth'
});
}
});
});
}
</script>
{{ end }}

@ -0,0 +1,36 @@
{{ define "main" }}
<div class="container">
<div class="page-header">
<h1>{{ .Title }}</h1>
<p>{{ .Description }}</p>
</div>
<div class="content">
{{ .Content }}
</div>
<div class="search-filter">
<input type="text" id="module-search" placeholder="Search modules...">
<select id="stage-filter">
<option value="">All Stages</option>
</select>
<select id="component-filter">
<option value="">All Components</option>
</select>
<select id="template-filter">
<option value="">All Templates</option>
</select>
</div>
<div id="modules-container" class="modules-container">
<!-- Modules will be loaded here via JavaScript -->
<div class="loading">Loading modules...</div>
</div>
</div>
<!-- Load the module data -->
<script src="{{ "js/data/modules.js" | relURL }}"></script>
<script src="{{ "js/data/templates.js" | relURL }}"></script>
<script src="{{ "js/data/template-mapper.js" | relURL }}"></script>
<script src="{{ "js/modules-page.js" | relURL }}"></script>
{{ end }}

@ -0,0 +1,7 @@
{{ define "main" }}
<div class="content-container">
<article class="page-content">
{{ .Content }}
</article>
</div>
{{ end }}

@ -0,0 +1,26 @@
{{ define "main" }}
<div class="home-content">
<div class="hero">
<h1>{{ .Title }}</h1>
<p class="lead">Create a customized dispute resolution protocol for your community</p>
<a href="/builder/" class="btn-primary">Start Building</a>
<a href="/about/" class="btn-secondary">Learn More</a>
</div>
<div class="content">
{{ .Content }}
</div>
<div class="stages-overview">
<h2>The Dispute Resolution Process</h2>
<div class="stages-grid">
{{ range $.Site.Data.stages.stages }}
<div class="stage-card">
<h3>{{ .title }}</h3>
<p>{{ .description }}</p>
</div>
{{ end }}
</div>
</div>
</div>
{{ end }}

@ -0,0 +1,6 @@
<footer>
<div class="container">
<p>&copy; {{ now.Format "2006" }} Community Dispute Protocol Builder. All rights reserved.</p>
<p>Built with <a href="https://gohugo.io/" target="_blank">Hugo</a></p>
</div>
</footer>

@ -0,0 +1,36 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ .Title }} | {{ .Site.Title }}</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="{{ "css/main.css" | relURL }}">
<link rel="shortcut icon" href="{{ "favicon.ico" | relURL }}" type="image/x-icon">
<!-- JS libraries for PDF export -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
<!-- Custom JS for the builder -->
{{ if eq .Layout "builder" }}
<script defer src="{{ "js/data/modules.js" | relURL }}"></script>
<script defer src="{{ "js/data/templates.js" | relURL }}"></script>
<script defer src="{{ "js/data/template-mapper.js" | relURL }}"></script>
<script defer src="{{ "js/debug.js" | relURL }}"></script>
<script defer src="{{ "js/builder.js" | relURL }}"></script>
{{ end }}
<!-- Additional custom JS from site parameters -->
{{ range .Site.Params.customJS }}
{{ if not (in . "modules.js" ) }}
{{ if not (in . "templates.js" ) }}
{{ if not (in . "template-mapper.js" ) }}
{{ if not (in . "builder.js" ) }}
<script defer src="{{ . | relURL }}"></script>
{{ end }}
{{ end }}
{{ end }}
{{ end }}
{{ end }}
</head>

@ -0,0 +1,15 @@
<header>
<div class="container">
<div class="logo">
<a href="{{ "/" | relURL }}">{{ .Site.Title }}</a>
</div>
<nav>
<ul>
<li><a href="{{ "/" | relURL }}">Home</a></li>
<li><a href="{{ "builder/" | relURL }}">Protocol Builder</a></li>
<li><a href="{{ "modules/" | relURL }}">Modules Library</a></li>
<li><a href="{{ "about/" | relURL }}">About</a></li>
</ul>
</nav>
</div>
</header>

@ -0,0 +1,21 @@
# theme.toml template for a Hugo theme
# See https://github.com/gohugoio/hugoThemes#themetoml for an example
name = "Dispute Protocol Theme"
license = "MIT"
licenselink = "https://github.com/yourname/yourtheme/blob/master/LICENSE"
description = ""
homepage = "http://example.com/"
tags = []
features = []
min_version = "0.41.0"
[author]
name = ""
homepage = ""
# If porting an existing theme
[original]
name = ""
homepage = ""
repo = ""