Skip to content
manfredstegerPublic

About

Modern polling and scheduling app for teams. Create schedule polls, surveys, and booking lists with email-based voting, real-time results, PDF export, and QR code sharing. Self-hosted with Docker, no cloud dependencies. Built with React, Express, PostgreSQL.

Topics

Resources

Contributing

Security policy

Stars

5 stars

Watchers

1 watching

Forks

Latest commit

 

History

1,155 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Polly 🗳️

Build Status Version License: MIT TypeScript Docker Changelog Roadmap

Open-source alternative to Doodle, Calendly, and LettuceMeet

A modern, self-hosted polling and scheduling platform for teams. Create surveys, schedule meetings, and manage event signups with ease. Multi-language support (German & English), GDPR-compliant, accessibility-tested (WCAG 2.1 AA), and fully self-hosted.


⚡ Zero-Config Quick Start (10 Minuten)

# Clone & Start - No configuration needed!
git clone --branch v0.1.0-beta.9 --depth 1 https://github.com/manfredsteger/polly.git
cd polly
docker compose up -d

# OR: Destructive fresh local setup (deletes volumes; includes seed data)
make complete

That's it! Open http://localhost:3080 and start exploring.

Default Admin Credentials

Field Value
Username admin
Password Admin123!
Email admin@polly.local

⚠️ Security Warning: After first login, create a new admin account and delete the default admin!

  • ✅ Database auto-configured (PostgreSQL included)
  • ✅ Schema auto-applied on first start
  • ✅ Initial admin account created automatically
  • ✅ Works out of the box - no .env file needed
  • ✅ Demo data shows all three poll types

🎬 See It In Action

For Users: Create Polls Instantly

Polly - Create a Poll in Seconds

Create your first poll in under 30 seconds – no login required

For Admins: Full Control Dashboard

Polly - Admin Dashboard Overview

Manage users, polls, and system settings from one central dashboard


📸 Screenshots

Poll Types

Schedule Poll Creation
📅 Schedule Poll
Find the best meeting time
Survey Poll
📊 Survey
Collect opinions & feedback
Organization List
📋 Organization List
Slot booking with capacity
🖥️ Admin Dashboard Screenshots (click to expand)
Overview User Management
Admin Overview User Management
System stats, recent activity, quick actions Manage users, roles, and permissions
Branding & Theming Settings
Branding Settings
Customize logo, colors, and site name Email, security, and system configuration
Monitoring Test Suite
Monitoring Tests
System health and performance Built-in security and integration tests
🇩🇪 Deutsche Screenshots (click to expand)
Dashboard Benutzer
Admin Übersicht Benutzerverwaltung
Branding Einstellungen
Branding Einstellungen

✨ Features

Three Poll Types

Type German Name Description
📅 Schedule Terminumfrage Find the best date/time with Yes/Maybe/No voting
📊 Survey Umfrage Classic polls with text options and optional images
📋 Organization Orga-Liste Slot booking with capacity limits and comments

Core Capabilities

  • Multi-Language Support: Full German (de) and English (en) interface with automatic browser detection. Easily extensible—add new languages by creating a translation JSON file in client/src/locales/
  • Anonymous & Authenticated Voting: Works for guests and registered users
  • Simple Choice Response Mode: Schedule and survey polls can switch from classic Yes/Maybe/No voting to a simple single-choice (radio) or limited multiple-choice (checkbox) mode with a clear, high-contrast selected state
  • Guest Access Controls: Administrators can separately enable or disable guest poll creation and guest voting without disabling public poll links
  • Real-Time Updates: Live voting with WebSocket connections and fullscreen presentation mode
  • Email Notifications: Vote confirmation, edit links, and expiry reminders via email
  • Matrix Results View: Visual participant × options grid with color-coded responses
  • Export Options: CSV and PDF exports with QR codes
  • Calendar Integration: ICS export and webcal:// subscription for schedule polls
  • QR Code Sharing: Easy poll distribution via QR codes
  • Full Customization: Theme colors, logo, site name via admin panel
  • Dark Mode: System-wide dark mode with admin defaults
  • AI Poll Assistant: Create polls via natural language with AI-powered suggestions (GWDG SAIA integration)
  • Voice Input: Speech-to-text for AI chat with real-time waveform visualization
  • Transactional Slot Booking: PostgreSQL row-level locking prevents overbooking in organization polls

Authentication Options

  • Local Login: Email/password for registered users
  • Keycloak OIDC: Enterprise SSO integration (optional)
  • Role-Based Access: User, Admin, Manager roles
  • Admin MFA Policy: Require MFA for administrator accounts, with an emergency deployment override for account-recovery incidents

🚀 Detailed Setup

Option 1: Production with Custom Settings

# Clone the repository
git clone --branch v0.1.0-beta.9 --depth 1 https://github.com/manfredsteger/polly.git
cd polly

# Copy and customize environment
cp .env.example .env
nano .env  # Add your SMTP, Keycloak settings

# Start with Docker Compose
docker compose up -d

# The app auto-configures on first start!

Option 2: Local Development

# Prerequisites: Node.js 22 LTS, PostgreSQL 15+

# Clone and install
git clone --branch v0.1.0-beta.9 --depth 1 https://github.com/manfredsteger/polly.git
cd polly
npm install

# Set up environment
cp .env.example .env
# Edit .env with your database URL and settings

# Push database schema
npm run db:push

# Start development server
npm run dev

# Open http://localhost:3080

⚙️ Configuration

Full reference: See .env.example for a ready-to-use template with all variables. Production guide: See docs/SELF-HOSTING.md for deployment-specific configuration.

Required

Variable Description Example
DATABASE_URL PostgreSQL connection URL postgresql://user:pass@host:5432/polly
SESSION_SECRET Session encryption key (min 32 chars). Generate with openssl rand -base64 32 a1b2c3d4...

Application URL

Variable Description Example
APP_URL Public URL of your application (used for OIDC redirects, email links, QR codes, sharing) https://poll.example.com

Note: BASE_URL and VITE_APP_URL are supported as legacy aliases. Use APP_URL for new deployments.

Email (SMTP) — Optional

Variable Description Default
SMTP_HOST SMTP server hostname —
SMTP_PORT SMTP port 587
SMTP_SECURE Use TLS (true/false) false
SMTP_USER SMTP username —
SMTP_PASSWORD SMTP password —
FROM_EMAIL Sender address for outgoing emails noreply@polly.example.com
FROM_NAME Sender display name Polly

Legacy aliases: EMAIL_FROM (same as FROM_EMAIL), SMTP_PASS (same as SMTP_PASSWORD)

Keycloak OIDC — Optional

Variable Description Example
KEYCLOAK_REALM Keycloak realm name university
KEYCLOAK_CLIENT_ID Client ID polly
KEYCLOAK_CLIENT_SECRET Client secret secret-uuid
KEYCLOAK_AUTH_SERVER_URL Keycloak base URL https://keycloak.example.com
KEYCLOAK_ISSUER_URL Full OIDC issuer URL (auto-derived if not set) https://keycloak.example.com/realms/myrealm
KEYCLOAK_ADMIN_CLIENT_ID Client ID for Keycloak Admin API calls (e.g. email-exists check). Falls back to KEYCLOAK_CLIENT_ID —
KEYCLOAK_ADMIN_CLIENT_SECRET Client secret for Keycloak Admin API calls. Falls back to KEYCLOAK_CLIENT_SECRET —
SSO_BUTTON_LABEL Custom login button text (e.g. "Kita Hub Login"). Also configurable in Admin panel —
HIDE_LOGIN_FORM Hide local username+password login form when SSO is primary false

Legacy alias: KEYCLOAK_URL (same as KEYCLOAK_AUTH_SERVER_URL)

AI Assistant — Optional

Variable Description Default
AI_API_URL OpenAI-compatible API endpoint —
AI_API_KEY API key. When set via ENV, AI chat is auto-enabled without admin toggle —
AI_API_KEY_FALLBACK Fallback key (used on HTTP 429 rate limit) —
AI_MODEL AI model name llama-3.3-70b-instruct

Security Scanning — Optional

Variable Description Default
CLAMAV_ENABLED Enable ClamAV virus scanning for uploads false
CLAMAV_HOST ClamAV daemon hostname clamav
CLAMAV_PORT ClamAV daemon port 3310
PENTEST_TOOLS_API_TOKEN Pentest-Tools.com Pro API token —

When CLAMAV_ENABLED, CLAMAV_HOST, or CLAMAV_PORT is explicitly set, it overrides the persisted Admin → Security scanner configuration at runtime. Leave all three unset to manage ClamAV in the Admin Panel.

Branding — Optional

These values can also be edited from the Admin Panel after first start. When set via ENV, the corresponding form field becomes read-only (lock icon).

Variable Description Example
SITE_NAME Site name shown in the navbar/title Poll
SITE_NAME_ACCENT Accented part of the site name (highlighted letter) y
FAVICON_URL Public URL of the favicon (PNG/ICO/SVG) https://example.com/favicon.png
LOGO_URL Public URL of the site logo https://example.com/logo.png
PRIMARY_COLOR Primary brand colour (hex) #F97316
POLLY_COPYRIGHT_TEXT Footer copyright text. Limited HTML supported (links, basic markup). When set, the admin field is locked. © 2026 My Org
MFA_ADMIN_REQUIRED Emergency override: set to false to temporarily bypass the admin MFA setting during an account-recovery incident. Remove or leave unset to use the admin-panel setting. —

Docker / Initial Admin — Optional

Variable Description Default
ADMIN_USERNAME Initial admin username admin
ADMIN_EMAIL Initial admin email admin@polly.local
ADMIN_PASSWORD Initial admin password Admin123!
SEED_DEMO_DATA Seed demo polls on first start false
DOCKER_ENV Marker that the app runs inside the bundled Docker image (auto-set by docker-compose.yml) true (in Docker)
POSTGRES_USER Bundled PostgreSQL user (docker-compose only) polly
POSTGRES_PASSWORD Bundled PostgreSQL password (docker-compose only) polly_secret
POSTGRES_DB Bundled PostgreSQL database (docker-compose only) polly

These values create a missing admin only; they never overwrite an existing account on restart. Database-backed tests require a separately initialized test database. Normal application operation does not require one. See TESTING.md.

Advanced

Variable Description Default
PORT Server port 5000
NODE_ENV Node environment production
DATABASE_SSL Enable SSL for database connections false
FORCE_HTTPS Force secure cookies (behind TLS-terminating proxy) auto-detect from APP_URL
DOCKER Legacy runtime marker used by some deployments to indicate container execution true
LOG_LEVEL Logging level: debug, info, warn, error info (prod) / debug (dev)
PUPPETEER_EXECUTABLE_PATH Chromium path for PDF export auto-detected
POLLY_WCAG_OVERRIDE Disable WCAG default theme enforcement false
TEST_MODE_SECRET Custom header value for E2E test mode polly-e2e-test-mode
TEST_DATABASE_URL Separate database for automated tests; see Testing Guide —
TEST_DATABASE_SSL SSL option for the test database connection false

🏗️ Tech Stack

Layer Technology
Frontend React 18, TypeScript, Vite
UI Shadcn/ui, Radix UI, Tailwind CSS
State TanStack Query v5
Backend Express.js, TypeScript
Database PostgreSQL, Drizzle ORM
Auth bcrypt + express-session (local), openid-client (Keycloak OIDC)
AI GWDG KISSKI / SAIA (OpenAI-compatible), Whisper for speech-to-text

📁 Project Structure

├── client/                       # React frontend (Vite)
│   └── src/
│       ├── components/          # Reusable UI + admin panels
│       ├── pages/               # Route components (wouter)
│       ├── hooks/               # Custom React hooks
│       ├── contexts/            # Auth, theme, language providers
│       ├── lib/                 # queryClient, helpers
│       ├── locales/             # i18n JSON (de, en)
│       └── assets/              # Bundled images & logos
├── server/                       # Express backend
│   ├── index.ts                 # App bootstrap, session, security headers
│   ├── routes/                  # Modular route files
│   │   ├── index.ts             # Mount all routers under /api/v1
│   │   ├── auth.ts              # Local login, register, password reset
│   │   ├── polls.ts             # Poll CRUD & voting
│   │   ├── votes.ts             # Vote management
│   │   ├── users.ts             # User self-service endpoints
│   │   ├── admin.ts             # Admin panel API (settings, users, polls)
│   │   ├── ai.ts                # AI chat / transcription proxy
│   │   ├── export.ts            # CSV / PDF / ICS export
│   │   ├── system.ts            # Public branding / health
│   │   └── common.ts            # Shared middleware
│   ├── services/                # authService, emailService, AI, rate limiter
│   ├── scripts/                 # ensureSchema, applyBranding bootstrap
│   ├── seed-admin.ts            # Initial admin seeder
│   ├── storage.ts               # Drizzle data-access layer
│   └── tests/                   # Vitest unit / integration / api / e2e
├── shared/                       # Code shared by client + server
│   ├── schema.ts                # Drizzle schema + Zod insert schemas
│   └── servicePartners.ts       # Single source of truth for GWDG/KISSKI
├── docs/                         # API spec, architecture, self-hosting guide
├── Dockerfile                    # Production container (multi-stage)
└── docker-compose.yml            # Zero-config production setup

🛠️ Development Commands

npm run dev          # Start development server (frontend + backend)
npm run build        # Build for production
npm start            # Start production server
npm run db:push      # Push schema changes to database
npm run db:studio    # Open Drizzle Studio (DB viewer)

🎨 Customization

Access the admin panel at /admin to customize:

  • Theme Colors: Primary, secondary, and feature-specific colors
  • Branding: Logo, site name, footer text
  • Dark Mode: Set system default (light/dark/system)
  • Registration: Enable/disable user registration
  • Email Settings: Configure SMTP for notifications

Install as a PWA

Polly ships as an installable Progressive Web App. Chrome, Edge, and Safari/iOS users can add it to their homescreen for a native-feeling launcher and offline fallback page. The web manifest at /site.webmanifest is rendered dynamically from your admin settings, so the homescreen icon name, splash-screen background, and accent color reflect the siteName, default theme mode, and primary color you configure in the admin panel — no rebuild needed. A service worker caches the app shell and shows a friendly offline page when the network is unreachable.

Feature Colors

Feature Default Color Description
Schedule Orange #F97316 Terminumfragen
Survey Green #7DB942 Umfragen
Organization Teal #72BEB7 Orga-Listen

🔒 Security

  • Session-based authentication with secure cookies
  • Server-side validation of all inputs with Zod
  • Email ownership verification for registered users
  • Role-based access control
  • CSRF protection
  • Secure password hashing with bcrypt
  • AI API key proxying (server-side only)

🐳 Docker Deployment

Using Makefile (Recommended)

# Show all available commands
make help

# Quick setup (first time)
make setup

# Start production
make prod

# Start development with hot-reload
make dev

# View logs
make logs

# Push database schema
make db-push

# Open database shell
make shell-db

# Destructive fresh local setup: deletes volumes, rebuilds and seeds
make complete

# Build and publish to Docker Hub
make publish IMAGE_NAME=yourusername/polly

Manual Docker Commands

# Build and run
docker-compose up -d --build

# View logs
docker-compose logs -f app

# Stop
docker-compose down

Development with Hot Reload

docker-compose -f docker-compose.yml -f docker-compose.dev.yml up

Docker Hub

The official image is published as manfredsteger/polly on Docker Hub:

# Latest beta tag (evaluation)
docker pull manfredsteger/polly:beta

# Specific version (recommended for production)
docker pull manfredsteger/polly:0.1.0-beta.9

# Start the pinned image with PostgreSQL (Portainer/Synology compatible)
docker compose -f docker-compose.image.yml up -d

See docs/SELF-HOSTING.md for production deployment instructions.

📖 API Documentation

All API endpoints use the /api/v1/ prefix. Full OpenAPI specification available in docs/openapi.yaml.

Public Endpoints

Method Endpoint Description
GET /api/v1/polls/public/:token Get poll by public token
POST /api/v1/polls/:publicToken/vote Submit vote
GET /api/v1/polls/:token/results Get poll results
GET /api/v1/polls/:publicToken/calendar.ics ICS calendar export

Authenticated Endpoints

Method Endpoint Description
POST /api/v1/polls Create poll
PATCH /api/v1/polls/:id Update poll
DELETE /api/v1/polls/:id Delete poll
GET /api/v1/users/me Get current user
PATCH /api/v1/users/me/language Update language preference

Admin Endpoints

Method Endpoint Description
GET /api/v1/admin/polls List all polls
GET /api/v1/admin/users List all users
PUT /api/v1/admin/settings Update settings
GET /api/v1/admin/email-templates Manage email templates

WebSocket (Real-Time Voting)

Connect to /ws for live vote updates during presentations. Events: vote_update, slot_update.

🗺️ Roadmap

Polly is currently in Beta Phase (Q1 2025 – Q2 2026). Our focus areas:

Priority Feature Status
🤖 AI Voice & Agentic Poll Creation – GWDG KISSKI Free Tier, Whisper STT ✅ Released (beta.3)
🗓️ Schedule Poll Enhancements – video conf URL, ICS labels, finalize UX ✅ Released (beta.3)
✉️ Notifications – End-Poll mails for all poll types, voter cancellation ✅ Released (beta.3)
🛡️ Guest Access & Admin MFA – separate guest policies plus a recoverable MFA requirement ✅ Released (beta.3)
🐳 Docker Zero-Config – fixed plain-HTTP cookie regression ✅ Released (beta.3)
🔐 Keycloak SSO (OIDC) – Enterprise single sign-on, full E2E coverage In Progress
🔌 OpenAI-Compatible Provider Slots – swap in custom inference endpoints Planned (1.0)
💬 Matrix / Element Chatbot – manage polls from Matrix chat Planned (1.0)
🇪🇺 European DC Focus – simplified deployment for EU data centers Planned (1.0)

👉 View Full Roadmap →

🤝 Service Partners

GWDG Logo GWDG – Gesellschaft für wissenschaftliche Datenverarbeitung mbH Göttingen
The GWDG is the joint computing and IT competence center for the Georg-August-Universität Göttingen and the Max Planck Society. As infrastructure partner, they provide the hosting and computing resources that power Polly's self-hosted deployment capabilities.
KISSKI Logo KISSKI – KI-Servicezentrum für sensible und kritische Infrastrukturen
KISSKI is a BMBF-funded AI service center operated by the GWDG, providing free AI inference capabilities for research and public infrastructure. Polly uses KISSKI's OpenAI-compatible API to offer AI-powered agentic control for poll creation – hosted in Germany, GDPR-compliant, and offers a free AI tier for every Polly user (please get in touch with GWDG/KISSKI for an AI production licence).

📋 Documentation

Document Description
ROADMAP.md Development roadmap and future plans
CHANGELOG.md Version history and release notes
SECURITY.md Security policy and vulnerability reporting
docs/openapi.yaml OpenAPI 3.0 API specification
docs/SELF-HOSTING.md Production deployment guide (Docker, Portainer, Synology, reverse proxy)
docker-compose.image.yml Pinned public Docker image with PostgreSQL
docker-compose.image.external-db.yml Pinned public Docker image for an external PostgreSQL database
docs/FLUTTER_INTEGRATION.md Mobile app integration guide

👥 Contributing

We welcome contributions! See CONTRIBUTING.md for the full guide.

Current beta branch:

  • feature/guest-access-control – source branch for the current public beta and its release tag
  • main – upstream stable branch; it is not changed as part of this beta release
  • feature/<name> – topic branches for future work

Quick steps:

  1. Fork the repository and clone your fork
  2. Create a feature branch from the current beta branch: git checkout -b feature/amazing-feature origin/feature/guest-access-control
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to your fork (git push origin feature/amazing-feature)
  5. Open a Pull Request against the branch agreed for the next release

Development Guidelines

  • Follow existing code style and conventions
  • Write TypeScript with proper types
  • Use Tailwind CSS for styling
  • Add or extend tests for every behaviour change (see CONTRIBUTING.md)
  • Update documentation (README.md, CHANGELOG.md, .env.example) as needed

📄 License

This project is open source and available under the MIT License.

🙏 Acknowledgments


Made with ❤️ for teams everywhere – self-hosted, GDPR-friendly, open source.

About

Modern polling and scheduling app for teams. Create schedule polls, surveys, and booking lists with email-based voting, real-time results, PDF export, and QR code sharing. Self-hosted with Docker, no cloud dependencies. Built with React, Express, PostgreSQL.

Topics

Resources

Contributing

Security policy

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages