forked from quic-issues/427e7578-d7bf-49c8-aee9-2dd999e25316
Restore README
This commit is contained in:
348
README.md
348
README.md
@@ -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 1–5 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 (1–5) | 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
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user