"Snap your survey β instant insights."
A Next.js application for collecting and analyzing audience feedback during speaking sessions using Azure AI Content Understanding. Attendees upload photos of their completed survey forms, and the system automatically extracts and aggregates the data for live presentation.
- Mobile-First Upload: Camera-optimized interface for quick survey photo capture
- Azure AI Content Understanding: Automatic extraction of checkboxes, numbers, and handwritten text via Azure AI Services
- Azure AI Foundry Integration: Connected to AI Foundry Project for advanced AI workflows
- Live Dashboard: Real-time feedback aggregation for speakers
- Session Management: Create and manage multiple feedback sessions
- Rich Analytics:
- 5-point Likert scale visualization
- Net Promoter Score (NPS) distribution
- Word cloud from open feedback
- Audience breakdown by type and experience level
- CSV Export: Download complete session data
- Fun UX: Confetti animation on successful submission
- Node.js 20+ and npm
- Azure Subscription with permissions to create resources
- Azure CLI - Install here
- (Optional) Terraform - For infrastructure automation - Install here
- (Optional) Docker - For containerized deployment
audience-survey/
βββ app/ # Next.js 16 application
β βββ src/ # Source code
β β βββ app/ # App Router pages and API routes
β β βββ components/ # React components
β β βββ lib/ # Utilities and business logic
β βββ tests/ # Playwright E2E tests
β βββ public/ # Static assets
β βββ Dockerfile # Container configuration
β βββ ... # Config files (package.json, tsconfig.json, etc.)
βββ iac/ # Infrastructure as Code (Terraform)
β βββ main.tf # Main Terraform configuration
β βββ variables.tf # Variable definitions
β βββ outputs.tf # Output values
β βββ README.md # Detailed IaC documentation
βββ setup/ # Setup scripts
β βββ create-analyzer.sh # Custom analyzer creation script
βββ docs/ # Documentation
β βββ QUICKSTART.md # Quick setup guide
β βββ AZURE_INTEGRATION.md # Azure setup details
β βββ ANALYZER_SCHEMA.md # Custom analyzer schema
β βββ BLOB_STORAGE.md # Storage implementation details
β βββ TESTING.md # Testing guide
β βββ ... # Additional documentation
βββ README.md # This file
cd app
npm installCopy the example environment file:
cp .example.env.local .env.localEdit .env.local and add your credentials:
# Azure AI Content Understanding
AZURE_CONTENT_ENDPOINT=https://your-resource-name.cognitiveservices.azure.com//
AZURE_CONTENT_KEY=your-api-key-here
AZURE_ANALYZER_ID=audience-survey
# Admin Secret (use a strong random string)
ADMIN_SECRET=your-secure-admin-secret-here.env.local for the changes to take effect.
Option 1: Deploy with Terraform (Recommended)
- Follow the Infrastructure as Code guide
- Terraform creates all required resources including:
- Azure AI Services (for Content Understanding)
- Azure AI Foundry Hub and Project
- Storage, Key Vault, and App Service
- Retrieve credentials from Terraform outputs
Option 2: Manual Setup
- Go to Azure Portal
- Create an Azure AI Services resource (not just "Content Understanding")
- This provides Content Understanding + other AI capabilities
- Note the endpoint format:
https://<name>.services.ai.azure.com/
- (Optional but recommended) Create Azure AI Foundry Hub and Project
- Navigate to Azure AI Studio
- Create a new Hub and Project
- Connect your AI Services resource to the project
- Navigate to AI Services β "Keys and Endpoint"
- Copy the endpoint URL and one of the keys
- Create a custom analyzer in Azure AI Studio
- Go to your AI Services resource in Azure AI Studio
- Create analyzer with ID:
audience-survey - Configure fields per ANALYZER_SCHEMA.md
For detailed setup instructions, see QUICKSTART.md.
cd app
npm run devOpen http://localhost:3000 in your browser.
- Navigate to
/admin - Enter your admin secret
- Create a new session before your presentation
- Share the main URL with attendees
- Monitor live results during/after the session
- Export data as CSV when complete
- Close the session when finished
- Navigate to the main URL (provided by speaker)
- Wait for the session to be active
- Take a clear photo of your completed survey form
- Preview and submit
- See confirmation with confetti!
- Frontend: Next.js 16 (App Router with Turbopack), React 19, TypeScript
- Styling: Tailwind CSS, mobile-first responsive design
- State Management: Zustand
- Charts: Recharts
- AI Processing: Azure AI Services (Content Understanding API)
- AI Platform: Azure AI Foundry (Hub + Project for advanced AI workflows)
- Deployment: Vercel / Azure App Service / Azure Static Web Apps
SessionGuard- Blocks access when no active sessionSurveyUploader- Camera/file input with previewSurveyMapper- Maps Azure output to survey modelFeedbackChart- Visualizes 1-5 Likert scalesNpsStrip- Shows 0-10 recommendation distributionWordCloud- Renders top feedback words
POST /api/sessions- Create new session (requires admin secret)PATCH /api/sessions- Close active session (requires admin secret)GET /api/sessions- List all sessionsPOST /api/analyze- Upload and analyze survey imageGET /api/summary?sessionId=xxx- Get session aggregated resultsGET /api/export?sessionId=xxx&adminSecret=xxx- Export CSV
The application expects surveys with these fields:
- Attendee Type: Student / Developer / Manager / Researcher / Hobbyist / Other
- AI Experience Level: Beginner / Intermediate / Advanced / Expert
- Azure AI Usage: Yes / No / Planning to
- How engaging was the presentation?
- How clear was the content?
- Were the demos useful?
- Was it at the right level?
- Did you learn something new?
- 0-10 scale: How likely are you to recommend this session?
- What was the best part?
- What could be improved?
- What topics would you like to see in the future?
- Admin routes protected by shared secret
- File type and size validation (10MB max)
- Rate limiting recommended for production
- HTTPS required for production deployment
- Sensitive data stored in environment variables
The project includes a complete CI/CD pipeline for Azure Container Apps:
Setup:
-
Provision infrastructure with Terraform:
cd iac terraform init terraform apply -
Configure GitHub repository secrets:
AZURE_CLIENT_ID- Service principal client IDAZURE_TENANT_ID- Azure tenant IDAZURE_SUBSCRIPTION_ID- Your subscription IDADMIN_SECRET- Admin secret for the application
-
Push to main branch or manually trigger workflow:
git push origin main
The GitHub Actions workflow (.github/workflows/deploy.yml) will:
- Provision infrastructure (if not exists)
- Build Docker image with commit SHA tag
- Push to Azure Container Registry
- Deploy to Azure Container Apps
- Run Playwright E2E tests against deployed URL
Access deployed app:
cd iac
terraform output container_app_urlSee iac/README.md for detailed infrastructure documentation.
Build and push Docker image:
cd app
# Login to Azure
az login
# Get ACR name from Terraform outputs
cd ../iac
ACR=$(terraform output -raw acr_login_server)
cd ../app
# Build and push
PROJECT=audsurvey
TAG=$(git rev-parse --short HEAD)
docker build -t "$ACR/$PROJECT/web:$TAG" .
az acr login --name ${ACR%%.*}
docker push "$ACR/$PROJECT/web:$TAG"Update Container App:
cd ../iac
terraform apply -var="container_image_tag=$TAG" -auto-approveQuick deploy:
cd app
npm install -g vercel
vercelConfigure environment variables in Vercel dashboard:
AZURE_CONTENT_ENDPOINT- Your AI Services endpointAZURE_CONTENT_KEY- AI Services API keyAZURE_ANALYZER_ID- Custom analyzer ID (audience-survey)AZURE_STORAGE_CONNECTION_STRING- Storage connection stringAZURE_STORAGE_CONTAINER_NAME- Container name (uploads)ADMIN_SECRET- Admin authentication secret
Or use Vercel CLI with env vars:
vercel --env AZURE_CONTENT_ENDPOINT=https://... \
--env AZURE_CONTENT_KEY=your-key \
--env AZURE_ANALYZER_ID=audience-survey \
--env AZURE_STORAGE_CONNECTION_STRING=DefaultEndpointsProtocol=https... \
--env ADMIN_SECRET=your-secretDeploy with SWA CLI:
cd app
# Install SWA CLI
npm install -g @azure/static-web-apps-cli
# Build the application
npm run build
# Deploy (follow prompts for authentication)
swa deployConfigure environment variables in Azure Portal:
- Navigate to Static Web App β Configuration
- Add the same environment variables as Vercel
Note: The staticwebapp.config.json is pre-configured for Next.js routing.
All cloud deployments require these environment variables:
| Variable | Description | Example |
|---|---|---|
AZURE_CONTENT_ENDPOINT |
AI Services endpoint | https://name.services.ai.azure.com/ |
AZURE_CONTENT_KEY |
AI Services API key | abc123... |
AZURE_ANALYZER_ID |
Custom analyzer ID | audience-survey |
AZURE_STORAGE_CONNECTION_STRING |
Storage connection (local/dev) | DefaultEndpointsProtocol=https;... |
AZURE_STORAGE_ACCOUNT_NAME |
Storage account (managed identity) | storageaccountname |
AZURE_STORAGE_CONTAINER_NAME |
Blob container name | uploads |
ADMIN_SECRET |
Admin authentication secret | Strong random string |
Note: Use AZURE_STORAGE_CONNECTION_STRING for Vercel/SWA. Container Apps uses managed identity with AZURE_STORAGE_ACCOUNT_NAME.
-
Test the deployed application:
# Visit your deployment URL curl https://your-app-url.azurecontainerapps.io -
Create a test session:
- Navigate to
/admin - Login with your
ADMIN_SECRET - Create a test session
- Navigate to
-
Upload a test survey:
- Visit the main page
- Upload a sample survey image
- Verify Azure AI Content Understanding extracts data correctly
-
Check logs:
# Container Apps az containerapp logs show \ --resource-group <rg-name> \ --name <app-name> \ --follow # Vercel vercel logs <deployment-url>
To delete all Azure resources and stop charges:
cd iac
terraform destroyThe Next.js application in app/ contains:
app/
βββ src/
β βββ app/ # App Router pages and API routes
β β βββ api/ # API routes
β β β βββ analyze/ # Image analysis endpoint
β β β βββ sessions/ # Session management
β β β βββ summary/ # Aggregated results
β β β βββ export/ # CSV export
β β βββ admin/ # Speaker dashboard
β β βββ page.tsx # Main audience view
β βββ components/ # React components
β βββ lib/ # Utilities and business logic
β βββ types.ts # TypeScript definitions
β βββ store.ts # Zustand state management
β βββ data-store.ts # In-memory data storage
β βββ blob-storage.ts # Azure Blob Storage integration
β βββ azure-content-understanding.ts # Azure AI integration
β βββ survey-mapper.ts # AI result mapping
βββ tests/ # Playwright E2E tests
βββ public/ # Static assets
βββ Dockerfile # Container configuration
βββ ... # Config files
The codebase is structured for easy extension:
-
Add new survey fields:
- Update
src/lib/types.tswith new field definitions - Extend
src/lib/survey-mapper.tsto extract from Azure response - Update
src/lib/data-store.tsaggregation logic - Create visualization components in
src/components/
- Update
-
Add new API endpoints:
- Create route in
src/app/api/ - Follow existing patterns for admin authentication
- Use
export const dynamic = 'force-dynamic'for real-time data
- Create route in
-
Add new visualizations:
- Create component in
src/components/ - Use Recharts for charts, Tailwind for styling
- Import directly (no barrel exports):
import X from '@/components/X'
- Create component in
Current Implementation:
- Session data: In-memory Maps in
DataStoresingleton (resets on restart) - Image files: Azure Blob Storage with unique blob names
- Image references: Blob URLs stored in
SurveyResult.imagePath
For Production:
- Replace
app/src/lib/data-store.tswith database (MongoDB, PostgreSQL, Cosmos DB) - Keep same interface for minimal API route changes
- Images already in cloud storage (Azure Blob Storage)
See docs/BLOB_STORAGE.md for storage implementation details.
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes with clear commit messages
- Test thoroughly
- Submit a pull request
MIT License - feel free to use this for your own presentations and events!
- Built with Next.js and React
- Powered by Azure AI Content Understanding
- UI components styled with Tailwind CSS
- Charts by Recharts
- Confetti by canvas-confetti
- QUICKSTART.md - Quick setup guide
- AZURE_INTEGRATION.md - Azure services setup
- ANALYZER_SCHEMA.md - Custom analyzer configuration
- TESTING.md - Testing guide with Playwright
- BLOB_STORAGE.md - Storage implementation details
- iac/README.md - Infrastructure as Code with Terraform
For issues and questions:
- Check the Azure AI Content Understanding documentation
- Review the documentation in the
docs/folder - Open an issue in the GitHub repository
- Review the troubleshooting section below
Port already in use (Error: listen EADDRINUSE :::3000)
# Find and kill process on port 3000
lsof -ti:3000 | xargs kill -9
# Or use a different port
npm run dev -- -p 3001Environment variables not updating
- Restart development server after changing
.env.local - Verify file is named
.env.localnot.env.local.txt - Check file is in
app/directory, not project root
"Module not found" errors
# Clear Next.js cache and reinstall
rm -rf .next node_modules
npm install
npm run dev"Couldn't read survey" / Image analysis errors:
- Image quality: Ensure good lighting, keep survey flat and in focus
- Custom analyzer: Verify analyzer ID is
audience-surveyin.env.local - Analyzer not deployed: Check Azure AI Studio for analyzer status
- Field mismatch: Ensure analyzer schema matches docs/ANALYZER_SCHEMA.md
Azure API authentication errors (401 Unauthorized):
- Verify endpoint URL format:
https://<name>.services.ai.azure.com/- Must be AI Services endpoint, not legacy
cognitiveservices.azure.com
- Must be AI Services endpoint, not legacy
- Check API key is correct (from AI Services β Keys and Endpoint)
- Ensure key hasn't been regenerated in Azure Portal
- Try using Key 2 if Key 1 fails
Region/availability errors (403 Forbidden):
- Ensure resource is in supported region:
westus,swedencentral, oraustraliaeast - Verify subscription has available quota for AI Services
- Check Content Understanding is enabled in your region
Storage errors ("Failed to upload image to storage"):
- Verify
AZURE_STORAGE_CONNECTION_STRINGis correct - Check storage account name matches in connection string
- Ensure
uploadscontainer exists (auto-created on first upload) - For Container Apps: verify managed identity has
Storage Blob Data Contributorrole
No active session error:
- Admin must create a session from
/adminpage - Only one session can be active at a time
- Session must be explicitly closed before creating new one
- Check browser console for 401 errors (admin secret mismatch)
Admin login fails:
- Verify
ADMIN_SECRETin.env.localmatches your input - No spaces or special characters causing encoding issues
- Try regenerating admin secret (update in both
.env.localand deployment)
Sessions not appearing in dashboard:
- Client polls every 5 seconds - wait or refresh page
- Check browser Network tab for failed
/api/sessionsrequests - Verify server is running and accessible
Container build fails:
# Test Docker build locally
cd app
docker build -t test-build .
# Check for missing dependencies
npm run buildTerraform errors:
# Custom subdomain already exists
# Solution: Change project_name in terraform.tfvars
# State lock errors
terraform force-unlock <lock-id>
# Provider version conflicts
terraform init -upgradeGitHub Actions deployment fails:
- Verify all repository secrets are set correctly
- Check Azure service principal has required permissions
- Review workflow logs for specific error messages
- Ensure Terraform state is not corrupted
Playwright tests failing:
# Install browser dependencies
npx playwright install --with-deps
# Update Playwright
npm install -D @playwright/test@latest
# Run single test file for debugging
npm run test:headed -- tests/admin.spec.tsTests timeout or hang:
- Ensure dev server is not already running on port 3000
- Check
.env.localis properly configured - Increase timeout in
playwright.config.tsif needed
Slow image analysis:
- Azure AI Content Understanding typical response: 2-5 seconds
- Check network latency to Azure region
- Ensure images are not excessively large (max 10MB)
- Consider image compression before upload
Dashboard not updating:
- Verify polling intervals in Zustand stores (default 3-5s)
- Check browser console for JavaScript errors
- Clear browser cache and reload
Uploaded images not persisting:
- Images stored in Azure Blob Storage (check Azure Portal)
- In-memory session data resets on server restart
- Export CSV before restarting server in development
CSV export empty or missing data:
- Verify session has submitted surveys
- Check
sessionIdparameter in export URL - Ensure
adminSecretis correct
If issues persist:
-
Check logs:
# Local development Check terminal output # Container Apps az containerapp logs show --name <app-name> --resource-group <rg-name> --follow # Vercel vercel logs
-
Enable debug mode: Add to
.env.local:NODE_ENV=development
-
Review documentation:
- Azure AI Content Understanding Docs
- Next.js Documentation
- Project docs in
docs/folder
-
Open an issue: Include: error messages, environment (OS, Node version), steps to reproduce
Ready to collect instant feedback? Start your session now! πβ¨