npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@phygitallabs/survey

v6.3.1

Published

A comprehensive survey management system built with SurveyJS, React, TypeScript, and PostgreSQL, designed for enterprise-grade survey creation, administration, and analytics.

Readme

Survey Package

A comprehensive survey management system built with SurveyJS, React, TypeScript, and PostgreSQL, designed for enterprise-grade survey creation, administration, and analytics.

Features

  • 🏗️ Full-Stack Architecture: Complete solution with PostgreSQL database, tRPC API, and React components
  • 🎨 Modern UI: Built with SurveyJS and Ant Design v5 for professional, responsive interfaces
  • 📊 Advanced Analytics: Real-time survey analytics with comprehensive statistics
  • 🔒 Security: JWT-based authentication with admin role management
  • 🏢 Multi-tenancy: Project-based survey organization with flexible labeling
  • ⚡ Type-Safe: End-to-end TypeScript with Zod validation and Drizzle ORM
  • 🔄 Real-time Updates: Live response tracking and instant analytics generation
  • 📱 Responsive Design: Works seamlessly on desktop, tablet, and mobile devices
  • 🎯 Survey Management: Complete CRUD operations with pagination and filtering
  • 📋 Import/Export: JSON-based survey definitions with validation
  • 🔍 Results Visualization: Professional analytics dashboard with detailed insights

Installation

# From the root of the monorepo
cd packages/survey
npm install

Project Structure

packages/survey/
├── 📁 src/
│   ├── 📁 admin/                    # Admin UI components
│   │   └── 📁 components/
│   │       ├── SurveyCreator.tsx    # Survey creation/editing
│   │       ├── SurveyList.tsx       # Survey management interface
│   │       └── SurveyImport.tsx     # JSON import with validation
│   │
│   ├── 📁 api/                      # Client-side API layer
│   │   └── surveyApi.ts             # Survey API abstraction
│   │
│   ├── 📁 client/                   # Client-facing components
│   │   ├── 📁 components/
│   │   │   ├── SurveyRenderer.tsx   # Survey display and interaction
│   │   │   └── SurveyResults.tsx    # Analytics visualization
│   │   └── 📁 hooks/
│   │       └── useSurveySubmission.ts # Survey submission logic
│   │
│   ├── 📁 core/                     # Shared core functionality
│   │   ├── 📁 hooks/
│   │   │   └── useSurvey.ts         # Main survey management hook
│   │   ├── 📁 types/
│   │   │   └── survey.types.ts      # TypeScript interfaces
│   │   └── 📁 utils/
│   │       └── surveyHelpers.ts     # Utility functions and analytics
│   │
│   ├── 📁 db/                       # Database schema and types
│   │   ├── schema.ts                # Drizzle ORM schema definitions
│   │   └── index.ts                 # Database exports
│   │
│   ├── 📁 server/                   # Server-side tRPC implementation
│   │   ├── 📁 routers/
│   │   │   ├── survey.ts            # Survey CRUD operations
│   │   │   ├── response.ts          # Response management
│   │   │   └── analytics.ts         # Analytics generation
│   │   ├── 📁 middleware/
│   │   │   └── admin.ts             # Admin authentication
│   │   ├── context.ts               # tRPC context setup
│   │   ├── router.ts                # Main router configuration
│   │   └── trpc.ts                  # tRPC configuration
│   │
│   ├── 📁 scripts/                  # Database utilities
│   │   └── migrate.ts               # Database migration script
│   │
│   └── 📁 themes/                   # UI theming
│       └── default.ts               # Default SurveyJS theme
│
├── 📁 drizzle/                      # Database migrations
│   ├── 📁 meta/                     # Migration metadata
│   └── *.sql                        # Migration files
│
├── 📄 index.ts                      # Client-side exports
├── 📄 server.ts                     # Server-side exports
├── 📄 drizzle.config.ts             # Database configuration
├── 📄 migrate.ts                    # Migration runner
├── 📄 package.json                  # Dependencies and scripts
├── 📄 tsconfig.json                 # TypeScript configuration
├── 📄 tsup.config.ts                # Build configuration
├── 📄 README.md                     # This documentation
└── 📄 DEVELOPMENT_HISTORY.md        # Development history

Module Overview

🎛️ Admin Module (src/admin/)

Components for survey management and administration:

  • SurveyCreator: Create and edit surveys using JSON
  • SurveyList: Display surveys with admin actions (edit, delete, status toggle)
  • SurveyImport: Import surveys with JSON validation and sample templates

👥 Client Module (src/client/)

Components for survey participation and viewing results:

  • SurveyRenderer: Render surveys and collect responses
  • SurveyResults: Display comprehensive analytics and results
  • useSurveySubmission: Hook for handling survey submissions

⚙️ Core Module (src/core/)

Core functionality and utilities:

  • useSurvey: Main hook for survey management operations
  • survey.types.ts: TypeScript interfaces and type definitions
  • surveyHelpers.ts: Utility functions, analytics generation, and validation

🔌 API Layer (src/api/)

Business logic and data operations:

  • SurveyApi: Complete API class with all survey operations
  • Storage abstraction: Works with any storage provider implementation
  • Business logic: Centralized survey management operations

🎨 Themes Module (src/themes/)

Styling and theming configuration:

  • default.ts: Default theme settings and customization options

Quick Start

Basic Usage

import { SurveyRenderer, SurveyResults } from '@phygitallabs/survey';

// Render a survey
<SurveyRenderer
  surveyId="your-survey-id"
  onComplete={(data) => console.log('Survey completed:', data)}
/>

// View survey results
<SurveyResults
  surveyId="your-survey-id"
  responseCount={10}
  responses={responseData}
/>

Admin Dashboard

import { SurveyList, SurveyImport } from '@phygitallabs/survey';

// Survey management with modern UI
<SurveyList
  surveys={surveys}
  onEdit={(id) => handleEdit(id)}
  onDelete={(id) => handleDelete(id)}
  onStatusChange={(id, isActive) => handleStatusChange(id, isActive)}
  onViewResults={(id) => handleViewResults(id)}
  isAdminView={true}
/>

// Import surveys with sample templates
<SurveyImport
  onImport={handleImport}
  sampleSurveyJson={sampleSurvey}
  sampleQuizJson={sampleQuiz}
  onSuccess={handleSuccess}
/>

Components

SurveyRenderer

Renders surveys with Ant Design styling and collects responses.

<SurveyRenderer
  surveyId={string}
  onComplete={(data: Record<string, any>) => void}
  theme?: object
/>

SurveyResults

Displays comprehensive survey analytics with charts and statistics.

<SurveyResults
  surveyId={string}
  responseCount?: number
  responses?: SurveyResponse[]
/>

SurveyList

Modern list view for survey management with admin/client modes.

<SurveyList
  surveys={Survey[]}
  onEdit?: (id: string) => void
  onDelete?: (id: string) => void
  onStatusChange?: (id: string, isActive: boolean) => void
  onViewResults?: (id: string) => void
  onParticipate?: (id: string) => void
  isAdminView?: boolean
  autoLoad?: boolean
/>

SurveyImport

Import surveys with JSON validation and sample templates.

<SurveyImport
  onImport={(json: Record<string, any>) => void}
  sampleSurveyJson?: Record<string, any>
  sampleQuizJson?: Record<string, any>
  onSuccess?: () => void
/>

API Reference

Core Hooks

import { useSurvey } from "@phygitallabs/survey";

const {
  survey,
  responses,
  loading,
  error,
  loadSurvey,
  loadAllSurveys,
  saveSurvey,
  deleteSurvey,
  loadResponses,
  submitResponse,
  getAnalytics,
  createSurvey,
  validateSurvey,
} = useSurvey(surveyId);

API Usage

import { SurveyApi, createSurveyApi, SurveyStorage } from "@phygitallabs/survey";

// Create a custom storage implementation
class MyStorage implements SurveyStorage {
  // Implement all required methods
}

// Create API instance
const api = createSurveyApi(new MyStorage());

// Use API directly
const surveys = await api.loadAllSurveys();
const survey = await api.loadSurvey("survey-id");
const id = await api.saveSurvey(surveyData);

// Or use with React hook
const { loadAllSurveys, saveSurvey } = useSurvey(undefined, new MyStorage());

// Demo implementation (IndexedDB) is available in the demo app
// See: apps/tapquest-portal/src/modules/surveys/storage/indexedDB.ts

Analytics Generation

import { generateSurveyAnalytics } from "@phygitallabs/survey";

const analytics = generateSurveyAnalytics(survey, responses);

Data Types

Core Types

Survey

interface Survey {
  id: string; // UUID primary key
  title: string; // Survey title
  description?: string; // Survey description
  json: Record<string, any>; // SurveyJS JSON configuration
  type: string; // Survey type (survey, quiz, etc.)
  labels?: Record<string, any>; // Flexible metadata (projectId, tags, etc.)
  createdAt: Date; // Creation timestamp
  updatedAt: Date; // Last update timestamp
  isActive: boolean; // Survey status (active/inactive)
}

SurveyResponse

interface SurveyResponse {
  id: string; // UUID primary key
  surveyId: string; // Foreign key to surveys table
  data: Record<string, any>; // Response data (question answers)
  submittedAt: Date; // Submission timestamp
  userId?: string; // Optional user identifier
  labels?: Record<string, any>; // Flexible metadata
  deviceUid?: string; // Optional device identifier
}

SurveyAnalytics

interface SurveyAnalytics {
  id: string; // UUID primary key
  surveyId: string; // Foreign key to surveys table
  totalResponses: number; // Total number of responses
  averageCompletionTime?: number; // Average time to complete (seconds)
  completionRate?: number; // Completion rate percentage (0-100)
  questionStats?: Record<string, any>; // Per-question statistics JSON
  updatedAt: Date; // Last analytics update timestamp
}

Question Statistics

QuestionStats

interface QuestionStats {
  questionType: string; // Type of question (text, choice, etc.)
  totalAnswers: number; // Number of responses to this question
  answerDistribution?: Record<string, number>; // Answer choice distribution
  averageValue?: number; // Average for numeric questions
  minValue?: number; // Minimum value for numeric questions
  maxValue?: number; // Maximum value for numeric questions
  textResponses?: string[]; // Array of text responses
  averageTextLength?: number; // Average length of text responses
}

Storage Interface

SurveyStorage

interface SurveyStorage {
  // Initialize the storage
  init(): Promise<void>;

  // Survey operations
  getSurvey(id: string): Promise<Survey | null>;
  getAllSurveys(): Promise<Survey[]>;
  saveSurvey(survey: Survey): Promise<string>;
  deleteSurvey(id: string): Promise<void>;

  // Response operations
  getResponse(id: string): Promise<SurveyResponse | null>;
  getResponsesBySurvey(surveyId: string): Promise<SurveyResponse[]>;
  saveResponse(response: SurveyResponse): Promise<string>;
  deleteResponse(id: string): Promise<void>;
  deleteResponsesBySurvey(surveyId: string): Promise<void>;
}

API Types

SurveyApi

class SurveyApi {
  constructor(storage: SurveyStorage);

  // Survey management
  loadSurvey(id: string): Promise<Survey | null>;
  loadAllSurveys(): Promise<Survey[]>;
  saveSurvey(survey: Survey): Promise<string>;
  deleteSurvey(id: string): Promise<void>;
  createSurvey(
    title: string,
    description?: string,
    json?: Record<string, any>
  ): Promise<string>;

  // Response management
  loadResponses(surveyId: string): Promise<SurveyResponse[]>;
  submitResponse(surveyId: string, data: Record<string, any>): Promise<string>;
  deleteResponse(id: string): Promise<void>;
  deleteAllResponses(surveyId: string): Promise<void>;

  // Analytics
  getAnalytics(surveyId: string): Promise<SurveyAnalytics>;

  // Validation
  validateSurvey(survey: Survey): boolean;
}

Component Props

SurveyRenderer Props

interface SurveyRendererProps {
  surveyId: string; // Survey to render
  onComplete?: (data: Record<string, any>) => void; // Completion callback
  theme?: object; // Custom theme object
}

SurveyResults Props

interface SurveyResultsProps {
  surveyId: string; // Survey to display results for
  responseCount?: number; // Total response count
  responses?: SurveyResponse[]; // Response data array
}

SurveyList Props

interface SurveyListProps {
  surveys: Survey[]; // Array of surveys to display
  onEdit?: (id: string) => void; // Edit callback
  onDelete?: (id: string) => void; // Delete callback
  onStatusChange?: (id: string, isActive: boolean) => void; // Status toggle callback
  onViewResults?: (id: string) => void; // View results callback
  onParticipate?: (id: string) => void; // Participate callback
  isAdminView?: boolean; // Admin vs client view mode
  autoLoad?: boolean; // Auto-load surveys
}

SurveyImport Props

interface SurveyImportProps {
  onImport: (json: Record<string, any>) => void; // Import callback
  sampleSurveyJson?: Record<string, any>; // Sample survey template
  sampleQuizJson?: Record<string, any>; // Sample quiz template
  onSuccess?: () => void; // Success callback
}

Hook Return Types

useSurvey Hook

interface UseSurveyReturn {
  // State
  survey: Survey | null;
  responses: SurveyResponse[];
  loading: boolean;
  error: string | null;

  // Survey operations
  loadSurvey: (id: string) => Promise<void>;
  loadAllSurveys: () => Promise<void>;
  saveSurvey: (survey: Survey) => Promise<string>;
  deleteSurvey: (id: string) => Promise<void>;
  createSurvey: (
    title: string,
    description?: string,
    json?: Record<string, any>
  ) => Promise<string>;

  // Response operations
  loadResponses: (surveyId: string) => Promise<void>;
  submitResponse: (
    surveyId: string,
    data: Record<string, any>
  ) => Promise<string>;
  deleteResponse: (id: string) => Promise<void>;
  deleteAllResponses: (surveyId: string) => Promise<void>;

  // Analytics
  getAnalytics: (surveyId: string) => Promise<SurveyAnalytics>;

  // Validation
  validateSurvey: (survey: Survey) => boolean;
}

Utility Types

SurveyJSON

type SurveyJSON = Record<string, any>; // SurveyJS JSON configuration

SurveyTheme

interface SurveyTheme {
  cssVariables?: Record<string, string>; // CSS custom properties
  cssClasses?: Record<string, string>; // CSS class mappings
  [key: string]: any; // Additional theme properties
}

Demo Implementation

A complete demo is available in apps/tapquest-portal/src/modules/surveys/ showcasing:

  • Admin View: Survey management, import/export, analytics
  • Client View: Survey participation, response collection
  • Real-time Updates: Live response tracking and analytics
  • Sample Templates: Pre-built survey and quiz examples
  • IndexedDB Storage: Demo storage implementation for local development

Demo Storage Implementation

The demo includes an IndexedDB storage implementation for local development:

// Location: apps/tapquest-portal/src/modules/surveys/storage/indexedDB.ts
import { IndexedDBStorage } from "./storage/indexedDB";

const storage = new IndexedDBStorage();
const { loadAllSurveys, saveSurvey } = useSurvey(undefined, storage);

Note: This IndexedDB implementation is for demo purposes only. In production, you should implement your own storage provider using the SurveyStorage interface.

Architecture

The survey package implements a modern full-stack architecture with clear separation of concerns:

🏗️ Full-Stack Architecture

┌─────────────────────────────────────────────────────────────┐
│                     Client Applications                     │
├─────────────────────────────────────────────────────────────┤
│  React Components   │   Hooks   │   Theme System   │  API    │
│  - SurveyRenderer   │ useSurvey │   - SurveyJS     │ Client  │
│  - SurveyResults    │ useSubmit │   - Ant Design   │ Layer   │
│  - SurveyList       │           │   - CSS Vars     │         │
├─────────────────────────────────────────────────────────────┤
│                      tRPC API Layer                        │
│  Type-Safe RPC   │   Routers    │  Middleware  │ Validation │
│  - Auto-complete │   - Survey   │  - Auth      │ - Zod      │
│  - Error types   │   - Response │  - Admin     │ - Schema   │
│  - TypeScript    │   - Analytics│  - CORS      │ - Runtime  │
├─────────────────────────────────────────────────────────────┤
│                    Database Layer (PostgreSQL)              │
│  ORM Integration │   Schema     │  Migrations  │ Relations  │
│  - Drizzle ORM   │   - Surveys  │  - Versioned │ - Foreign  │
│  - Type Safety   │   - Responses│  - Automated │   Keys     │
│  - Query Builder │   - Analytics│  - Rollback  │ - Cascade  │
└─────────────────────────────────────────────────────────────┘

🔄 Data Flow

  1. Client Request: React components call tRPC procedures
  2. Type Validation: Zod schemas validate input/output
  3. Authentication: JWT middleware checks permissions
  4. Database Operations: Drizzle ORM executes type-safe queries
  5. Response: Type-safe data flows back to components

🔌 API-First Design

The package supports both direct API usage and React integration:

  • tRPC Procedures: Type-safe server functions with automatic client generation
  • SurveyApi Class: Client-side abstraction for storage-agnostic operations
  • React Hooks: State management wrappers around API calls
  • Dual Exports: Separate client (./index) and server (./server) entry points

Key Architectural Benefits

  • Type Safety: End-to-end TypeScript with runtime validation
  • Scalability: Production-ready PostgreSQL with proper indexing
  • Security: JWT authentication, input validation, SQL injection prevention
  • Performance: Optimized queries, pagination, connection pooling
  • Maintainability: Clear separation of concerns, modular structure
  • Testability: Independent layers can be tested in isolation

Features in Detail

🎨 Modern UI Components

  • Ant Design v5: Professional, accessible, and responsive components
  • Statistics Cards: Visual representation of survey metrics
  • Data Tables: Clean, sortable tables for response analysis
  • Progress Indicators: Loading states and completion tracking
  • Alert System: User-friendly error and success notifications

📊 Advanced Analytics

  • Response Distribution: Visual breakdown of answer choices
  • Numeric Statistics: Min, max, average, and median calculations
  • Text Analysis: Response count and average length metrics
  • Completion Tracking: Real-time completion rate monitoring
  • Question-level Insights: Detailed statistics per question type

🔄 Real-time Features

  • Live Updates: Response counts update immediately after submission
  • Instant Analytics: Results generated on-demand with fresh data
  • Status Management: Toggle survey active/inactive states
  • Response Tracking: Monitor survey participation in real-time

📱 Responsive Design

  • Mobile-First: Optimized for all screen sizes
  • Touch-Friendly: Proper touch targets and interactions
  • Flexible Layout: Adapts to different viewport sizes
  • Accessible: WCAG compliant components and interactions

Server Setup

Database Configuration

The package uses PostgreSQL with Drizzle ORM for data persistence:

// Configure your database connection
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';

const client = postgres(process.env.DATABASE_URL);
const db = drizzle(client);

Running Migrations

# Generate migration files
npm run db:generate

# Apply migrations
npm run db:migrate

# Open Drizzle Studio (database GUI)
npm run db:studio

tRPC Server Integration

import { appRouter, createContext } from '@phygitallabs/survey/server';
import { createHTTPServer } from '@trpc/server/adapters/standalone';

const server = createHTTPServer({
  router: appRouter,
  createContext,
});

server.listen(3001);

Environment Variables

# Required environment variables
DATABASE_URL=postgresql://user:password@localhost:5432/survey_db
JWT_SECRET=your-jwt-secret-key
ADMIN_JWT_SECRET=your-admin-jwt-secret

# Optional
NODE_ENV=development
PORT=3001

Client Setup

tRPC Client Configuration

import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
import type { AppRouter } from '@phygitallabs/survey/server';

const trpc = createTRPCProxyClient<AppRouter>({
  links: [
    httpBatchLink({
      url: 'http://localhost:3001/trpc',
    }),
  ],
});

// Usage
const surveys = await trpc.survey.getAll.query({ page: 1, limit: 10 });

React Query Integration

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { createTRPCReact } from '@trpc/react-query';
import type { AppRouter } from '@phygitallabs/survey/server';

const trpc = createTRPCReact<AppRouter>();
const queryClient = new QueryClient();

function App() {
  return (
    <trpc.Provider client={trpcClient} queryClient={queryClient}>
      <QueryClientProvider client={queryClient}>
        {/* Your app components */}
      </QueryClientProvider>
    </trpc.Provider>
  );
}

Development

See DEVELOPMENT_HISTORY.md for the development roadmap and history.

License

This package uses the free version of SurveyJS, which is licensed under MIT.