Architecture & Tech Stack

Technical overview for developers

Tech Stack#

Askify is built with modern, production-ready technologies:

  • Runtime: Node.js 22+
  • Framework: Bolt for JavaScript (@slack/bolt v4)
  • Database: PostgreSQL (via Supabase)
  • ORM: Prisma v7 with @prisma/adapter-pg
  • Scheduler: node-cron for background jobs
  • Deployment: Docker with multi-stage builds

Database Schema#

Askify uses four main database models:

Poll

Stores poll metadata and configuration.

  • UUID primary key
  • Creator ID, channel ID, message timestamp
  • Question text
  • Poll type (ENUM: single_choice, multi_select, yes_no, rating)
  • Settings (JSONB: anonymous, vote change, live results, reminders)
  • Status (ENUM: draft, scheduled, active, closed)
  • Scheduled and close timestamps

PollOption

Stores individual poll options.

  • UUID primary key
  • Foreign key to Poll
  • Label text (max 200 chars)
  • Position (display order)
  • Added by (user ID if voter-added)

Vote

Tracks individual votes.

  • UUID primary key
  • Foreign keys to Poll and PollOption
  • Voter ID (Slack user ID)
  • Voted at timestamp

PollTemplate

Stores saved poll configurations.

  • UUID primary key
  • User ID (template owner)
  • Template name
  • Config (JSONB: full poll configuration)
  • Created at timestamp

Architecture Overview#

Askify follows an event-driven architecture with these key components:

Slash Commands

Entry points for user interactions (src/commands/):

  • /askify - Opens poll creation modal
  • /askify poll - Inline quick poll creation
  • /askify list - Shows user's polls with filtering
  • /askify templates - Manages poll templates
  • /askify help - Displays usage guide

Actions

Handle button clicks and select menus (src/actions/):

  • Vote buttons (regex: /^vote_.+$/)
  • Close poll, add option, save template buttons
  • Modal select menus with dispatch_action
  • List actions (close, cancel, results)

Views

Process modal submissions (src/views/):

  • Poll creation modal
  • Template save modal
  • Add option modal
  • Share results modal

Background Jobs

Scheduled tasks using node-cron (src/jobs/):

  • autoCloseJob - Closes expired polls (every minute)
  • scheduledPollJob - Posts scheduled polls (every minute)
  • reminderJob - Sends reminder DMs (every 15 minutes)
  • startupRecovery - Catches up on missed events (on startup)

Services

Business logic and database operations (src/services/):

  • pollService - CRUD operations for polls
  • voteService - Vote processing and deduplication
  • templateService - Template management

Event Flow#

Typical poll lifecycle:

  1. User runs /askify → Slash command handler opens modal
  2. User submits modal → View handler validates and creates poll in database
  3. If scheduled: Job picks it up at scheduled time and posts
  4. If immediate: Bot posts poll message via chat.postMessage
  5. Voters click buttons → Action handler records votes, updates message
  6. Vote updates debounced (500ms) to batch rapid clicks
  7. Auto-close job checks periodically, closes expired polls
  8. On close: Results DM sent to creator, voting disabled
  9. Creator clicks 'Share Results' → Posts to chosen channel

Key Patterns#

Socket Mode

Askify uses Slack Socket Mode for real-time communication without exposing a public endpoint. This eliminates the need for ngrok or public URLs during development.

Debounced Updates

Rapid vote clicks are debounced per poll (500ms). The debounced callback refetches fresh data, ensuring the final update reflects current state.

Dynamic Modals

Modal select elements with dispatch_action: true trigger handlers that rebuild and update the modal via client.views.update().

Retry Logic

Exponential backoff for Slack API rate limits using withRetry() wrapper (src/utils/slackRetry.ts).

Project Structure#

text
src/
  app.ts              # Entry point
  lib/prisma.ts       # Prisma singleton
  commands/           # Slash command handlers
  actions/            # Button/select handlers
  views/              # Modal submissions
  events/             # Event handlers (DM, App Home)
  middleware/         # Request logger
  services/           # Business logic
  blocks/             # Block Kit builders
  jobs/               # Background jobs
  utils/              # Helpers
prisma/
  schema.prisma       # Database schema

Development#

Common development commands:

bash
# Development
npm run dev              # Hot-reload with nodemon

# Build
npm run build            # Compile TypeScript
npm start                # Run compiled app

# Database
npm run prisma:migrate   # Create/apply migrations
npm run prisma:generate  # Regenerate Prisma Client
npm run prisma:studio    # Open database browser

# Type checking
npx tsc --noEmit         # Check types without building

Deployment#

Askify is designed for self-hosting. Deployment options:

  • Docker: Multi-stage Dockerfile included
  • VPS: Deploy to any server with Node.js and PostgreSQL
  • PM2: Process manager for production
  • GitHub Actions: Automated deployment pipeline

See docs/DEPLOYMENT.md in the repository for detailed instructions.