Restore README

This commit is contained in:
Dimas Wiese
2026-03-16 00:00:01 +01:00
parent 6b0f87199c
commit d05cf7d13d

348
README.md
View File

@@ -1 +1,347 @@
# P2P Poll App # P2P Survey App
A serverless peer-to-peer survey application built with Ionic and Angular.
Survey creators store all data locally in their browser and participants connect
directly via WebRTC — no backend server required.
---
## Table of Contents
1. [Overview](#overview)
2. [Architecture](#architecture)
3. [Features](#features)
4. [Setup & Installation](#setup--installation)
5. [How It Works](#how-it-works)
- [Creator Flow](#creator-flow)
- [Participant Flow](#participant-flow)
6. [Question Types](#question-types)
7. [Technology Stack](#technology-stack)
8. [Limitations](#limitations)
9. [Self-Hosting the PeerJS Signaling Server](#self-hosting-the-peerjs-signaling-server)
10. [Development Commands](#development-commands)
11. [Technology Choices](#technology-choices)
---
## Overview
P2P Survey App lets you create and distribute surveys without any server-side
infrastructure. All survey data — questions, participant tokens, and responses —
lives exclusively in the survey creator's browser (IndexedDB). Participants
connect directly to the creator's browser using WebRTC peer-to-peer data
channels, facilitated by the PeerJS library.
---
## Architecture
```
Creator Browser (Host)
┌─────────────────────────────────────────────┐
│ Ionic/Angular App │
│ ┌─────────────────┐ ┌──────────────────┐ │
│ │ PeerService │ │ Dexie (IndexedDB)│ │
│ │ (PeerJS/WebRTC)│<─>│ surveys │ │
│ └────────┬────────┘ │ participants │ │
│ │ │ responses │ │
│ Peer ID: survey-{id}└──────────────────┘ │
└───────────┼─────────────────────────────────┘
[PeerJS Cloud signaling only, not data relay]
Participant Browser
┌─────────────────────────────────────────────┐
│ Opens: /participate?host=survey-{id} │
│ &token={uuid} │
│ │
│ 1. Connect to host peer via WebRTC │
│ 2. Send { type: 'join', token } │
│ 3. Receive survey questions │
│ 4. Fill in answers │
│ 5. Send { type: 'submit', answers } │
└─────────────────────────────────────────────┘
```
### Star topology
The survey creator acts as the central hub. Each participant opens a direct
WebRTC data channel to the creator's browser. The creator's browser validates
tokens, stores responses, and optionally pushes aggregated results back.
The PeerJS signaling server is only used for the initial WebRTC handshake
(exchanging ICE candidates). Once connected, all data flows directly between
the two browsers — the signaling server never sees response data.
---
## Features
- **Create surveys** with four question types: free text, multiple choice,
yes/no, and 15 rating
- **Generate unique participant links** — each link contains a UUID token that
identifies one participant
- **Token-based access control** — each token can only be submitted once;
reuse is rejected by the host
- **Draft saving** — participants can save answers before final submission
without locking their token
- **Live results** — the creator sees responses update in real time using
Dexie's `liveQuery`
- **Optional results sharing** — the creator can toggle whether participants
see aggregated results after submitting
- **CSV export** — download all responses as a comma-separated file
- **Local-only storage** — all data lives in the creator's IndexedDB; delete
the survey and the data is gone
---
## Setup & Installation
### Prerequisites
- Node.js 18+ and npm 9+
- A modern browser (Chrome, Firefox, Edge, Safari)
### Install
```bash
# 1. Install Ionic CLI globally (skip if already installed)
npm install -g @ionic/cli
# 2. Install project dependencies
npm install
# 3. Start the development server
ionic serve
```
The app opens at `http://localhost:8100`.
### Build for production
```bash
ionic build --prod
```
Output is written to `www/`. Deploy the contents of `www/` to any static
web host (GitHub Pages, Netlify, Vercel, Nginx, etc.).
---
## How It Works
### Creator Flow
1. **Open the app** and click **Create Survey**.
2. **Enter a title** (required) and optional description.
3. **Add questions** — choose a type for each and mark which are required.
4. Click **Create** to save the survey to IndexedDB and navigate to the
**Survey Detail** page.
5. On the detail page:
- Toggle **Show results to participants** if desired.
- Enter a number and click **Generate Links** to create unique participant
tokens. Copy links to share.
- Click **Start Hosting** to initialise the PeerJS peer. The app listens
for incoming connections using the peer ID `survey-{surveyId}`.
6. **Keep this page or the Results page open** while collecting responses.
If the creator navigates away, the peer is destroyed and participants
cannot connect.
7. Click **View Results** to see live aggregated and individual responses.
8. Click **Export CSV** to download all responses.
### Participant Flow
1. **Open the unique link** shared by the survey creator.
2. The app parses `host` and `token` from the URL query parameters.
3. A WebRTC connection is established to the host's peer ID.
4. The participant sends `{ type: 'join', token }`.
5. The host validates the token:
- **Invalid token** → error card is shown.
- **Already submitted** → error card is shown (token is locked).
- **Valid** → survey questions are sent back.
6. Participant fills in answers. Answers are auto-saved as drafts after each
blur event (free text) or selection change (other types).
7. Click **Submit** to finalise. The token is locked on the host side.
8. If the creator enabled result sharing, aggregated results are shown.
---
## Question Types
| Type | Input widget | Aggregation |
|---|---|---|
| **Free Text** | Multi-line textarea | List of all answers |
| **Multiple Choice** | Radio buttons (creator-defined options) | Count per option + bar chart |
| **Yes / No** | Radio buttons (Yes / No) | Count per option + bar chart |
| **Rating** | 5 buttons (15) | Average score + distribution bar chart |
---
## Technology Stack
| Library | Version | Role |
|---|---|---|
| `@ionic/angular` | 8.x | Mobile-first UI components |
| `@angular/core` | 20.x | Application framework |
| `peerjs` | 1.5.x | WebRTC data channel wrapper |
| `dexie` | 4.x | IndexedDB wrapper with liveQuery |
| `qrcode` | 1.5.x | QR code generation (optional usage) |
---
## Limitations
### Host must be online
The survey creator's browser **must be open** and on the Survey Detail or
Results page for participants to submit responses. There is no server that
relays or buffers messages. If the creator goes offline, participants see a
"Host is Offline" card.
### Data loss
All data is stored in the creator's browser IndexedDB. Data is lost if:
- The creator explicitly deletes the survey
- The browser's storage is cleared (private/incognito mode, clearing site data)
- The browser's IndexedDB quota is exceeded
Export responses to CSV regularly to prevent data loss.
### PeerJS Cloud rate limits
The free PeerJS Cloud signaling server (`0.peerjs.com`) has rate limits and
may occasionally be unavailable. For production use, self-host the signaling
server (see below).
### NAT traversal
WebRTC uses STUN to traverse most NAT configurations. Strict corporate
firewalls or symmetric NAT may block direct connections. For full reliability
in such environments, add a TURN server to the PeerJS configuration in
`src/app/services/peer.service.ts`.
### Browser compatibility
Requires a browser that supports:
- WebRTC (DataChannels)
- IndexedDB
- `crypto.randomUUID()`
All modern browsers (Chrome 86+, Firefox 78+, Safari 15.4+, Edge 86+) satisfy
these requirements.
---
## Self-Hosting the PeerJS Signaling Server
For production deployments, run your own PeerJS server to avoid rate limits.
### Option 1: npm
```bash
npm install -g peer
peerjs --port 9000 --key peerjs
```
### Option 2: Docker
```bash
docker run -p 9000:9000 peerjs/peerjs-server
```
### Option 3: Node.js
```javascript
// server.js
const { PeerServer } = require('peer');
const server = PeerServer({ port: 9000, path: '/peerjs' });
```
### Configure the app to use your server
Edit `src/app/services/peer.service.ts` and update the `Peer` constructor:
```typescript
this.peer = new Peer(peerId, {
host: 'your-peer-server.example.com',
port: 9000,
path: '/peerjs',
secure: true, // use wss:// if your server has TLS
});
```
---
## Development Commands
```bash
# Start dev server with live reload
ionic serve
# Build for production
ionic build --prod
# Run TypeScript type check
npx tsc --noEmit
# Lint
npx ng lint
# Build Angular app only (no Ionic wrapper)
npx ng build
```
---
## Technology Choices
### PeerJS over Gun.js
Gun.js is a decentralized graph database that syncs between peers. However,
a survey has a **star topology** (one host, many participants) — not a mesh
where every peer is equal. PeerJS maps directly to this model: the creator
opens one peer ID, participants connect to it, and all data flows through
that central point. Token validation and response deduplication are trivial
to enforce at the host. Gun.js would require additional complexity to achieve
the same guarantees.
### Dexie.js over raw IndexedDB
Raw IndexedDB uses a callback-based API that is verbose and error-prone.
Dexie wraps it in clean Promises, adds a TypeScript-friendly schema
definition, and provides `liveQuery` — a reactive subscription mechanism
that automatically re-runs queries when the underlying data changes. This
powers the live results view without any manual polling or event wiring.
### Module-based Angular over Standalone Components
The Ionic CLI scaffolds a module-based project by default with Angular 20.
Module-based components provide a clear separation of concern via `NgModule`
declarations and are well-supported by the Ionic ecosystem.
---
## Project Structure
```
src/
└── app/
├── shared/
│ └── models/
│ └── survey.models.ts # All TypeScript interfaces + P2PMessage type
├── database/
│ └── database.ts # Dexie singleton (AppDatabase)
├── services/
│ ├── peer.service.ts # PeerJS wrapper (NgZone-aware)
│ ├── survey.service.ts # Survey/participant CRUD
│ └── response.service.ts # Response storage + aggregation
├── pages/
│ ├── home/ # Survey list
│ ├── create-survey/ # Survey creation/editing
│ ├── survey-detail/ # Settings, link generation, hosting
│ ├── survey-results/ # Live results view
│ └── participate/ # Participant survey form
├── app-routing.module.ts
├── app.component.ts
└── app.module.ts
```