# Protocol Bicorder - Web App

A Svelte Progressive Web App (PWA) for carrying out protocol diagnostics as defined in `../bicorder.json`.

## Features

- **Single-page diagnostic tool** with ASCII-styled interface
- **Touch-friendly controls** optimized for mobile devices
- **Shortform toggle** - switch between full (23 gradients) and short (10 gradients) versions
- **Tooltips** on all gradient terms (long-press on mobile, hover on desktop)
- **Editable metadata** fields with auto-generated timestamps
- **Auto-calculated analysis** section (hardness/softness, polarized/centrist)
- **Citation support** for each gradient value
- **Local storage** - your progress is automatically saved
- **Export to JSON** - download your completed diagnostic
- **Share functionality** - use Web Share API on supported devices
- **Public upload** - submit readings directly to the public repository
- **Full PWA** - installable, works offline
- **Privacy-focused** - no telemetry, no external fonts, works completely offline

## Development

```bash
# Install dependencies
npm install

# Start development server (http://localhost:5173)
npm run dev

# Build for production
npm run build

# Preview production build (http://localhost:4173)
npm run preview
```

**Important:** The app must be served via HTTP/HTTPS (not opened directly as `file://`). Modern browsers block ES modules and service workers from the file protocol for security reasons. Always use `npm run preview` or deploy to a web server to test the built app.

## Build Process

The app reads `../bicorder.json` at build time and constructs the interface based on its structure. To update the diagnostic:

1. Edit `../bicorder.json`
2. Run `npm run update` (or `npm run build`)
3. The app will automatically reflect the new structure

Alternatively, run `./update-diagnostic.sh` for a friendlier update experience.

## Deployment

The built app is in the `dist/` folder. You can deploy it to any static hosting service:

- **GitHub Pages**: Push the dist folder
- **Netlify**: Connect your repo and set build command to `npm run build`
- **Vercel**: Same as Netlify
- **Static server**: Copy the dist folder contents to your web server

### Quick local server options

If you don't have Node.js available, you can serve the `dist/` folder with:

```bash
# Use the provided script (tries Python/PHP automatically)
./serve-local.sh

# Or manually:
# Python 3
python3 -m http.server 8000 --directory dist

# PHP
php -S localhost:8000 -t dist

# Any other static file server
```

Then open http://localhost:8000 in your browser.

## Usage

### Filling out the diagnostic

1. Fill in the metadata fields (Protocol, Analyst, Standpoint)
2. **Toggle shortform mode** (optional) to show only the 10 core gradients
3. For each gradient, tap/click the numbered buttons (1-9) to set values
   - 1 = strongly toward the left term
   - 5 = balanced/neutral
   - 9 = strongly toward the right term
4. Optionally add citations for each gradient value
5. The Analysis section is automatically calculated based on your inputs

### Exporting and sharing results

- **Export JSON**: Downloads the diagnostic as a JSON file
- **Share**: Uses your device's share functionality (mobile)
- **Upload**: Submit your readings to the public repository

### Public upload

When you click **Upload**, your readings will be:
- Posted to the public repository: [protocol-bicorder-data](https://git.medlab.host/ntnsndr/protocol-bicorder-data)
- Licensed to the public domain (CC0)
- Committed with your analyst name and protocol name
- Stored in the `readings/` directory with a timestamp

All uploaded readings are public and available for research and analysis. By uploading, you consent to releasing your diagnostic under a public domain license.

#### Upload credentials and security model

The upload feature posts directly from the user's browser to the Gitea API using an access token defined in `src/components/ExportControls.svelte` (`GITEA_TOKEN`).

**This token is intentionally embedded in the client bundle, and that is acceptable here.** Because this is a purely static app, the browser must make the API call itself — there is no server-side code of ours to hold the token. Any credential the browser uses is therefore necessarily public; build-time environment variables would still be baked into the shipped JavaScript, so they would offer no real protection. The exposure is contained by *what the token can do* rather than by hiding it:

- The token belongs to a **dedicated `bicorder-bot` account**, not to a personal account.
- `bicorder-bot` is a **collaborator with write access only to the public [`protocol-bicorder-data`](https://git.medlab.host/ntnsndr/protocol-bicorder-data) repo**. It cannot push to any other repository.
- It has **`admin: false`** on that repo, so it can only add/modify files — it cannot delete the repo or change its settings.
- The token scope is `write:repository` (it cannot even read user account details).

The entire worst-case blast radius is therefore: someone extracts the token and spams or vandalizes the contents of the public data repo. This is recoverable (revert the commits) and the repo contains only public submissions.

**If the token is ever abused:** revoke it under the `bicorder-bot` account (Gitea → Settings → Applications → Access Tokens — note that tokens live under the *user account*, not the repo), generate a replacement with the same `write:repository` scope, update `GITEA_TOKEN` in `ExportControls.svelte`, and rebuild. Optionally, enable branch protection on the data repo's `main` branch as an additional safeguard.

## Browser Support

- Modern browsers (Chrome, Firefox, Safari, Edge)
- Mobile browsers (iOS Safari, Android Chrome)
- PWA installation supported on Android, iOS 16.4+, and desktop browsers

## Customization

### Styling

The app uses CSS custom properties for theming. Edit `src/app.css` to change colors:

```css
--bg-color: #000000;     /* Background */
--fg-color: #00ff00;     /* Foreground/text */
--border-color: #00ff00; /* Borders */
--hover-color: #00cc00;  /* Hover states */
```

### Icons

Replace `public/icon.svg` with your own icon. For better PWA support, also generate PNG versions:

```bash
# Example using ImageMagick (if available)
convert -background none -resize 192x192 public/icon.svg public/icon-192.png
convert -background none -resize 512x512 public/icon.svg public/icon-512.png
```

Then update `vite.config.ts` to reference the PNG icons in the manifest.

## Architecture

- **Framework**: Svelte 4 with TypeScript
- **Build tool**: Vite 5
- **PWA**: vite-plugin-pwa with Workbox
- **State management**: Svelte stores + localStorage
- **Data source**: bicorder.json (build-time integration)

## Authorship and licensing

Initiated by [Nathan Schneider](https://nathanschneider.info) and available for use under the [Hippocratic License](https://firstdonoharm.dev/) (do no harm!). Several AI assistants, local and remote, were utilized in developing this tool.

[![Hippocratic License HL3-CORE](https://img.shields.io/static/v1?label=Hippocratic%20License&message=HL3-CORE&labelColor=5e2751&color=bc8c3d)](https://firstdonoharm.dev/version/3/0/core.html)
