Tagline: Snap your doodle. Get your vibe.
A production-ready web application that analyzes hand-drawn pig drawings to provide personality insights using Azure AI Content Understanding and psychological principles.
π View Complete Documentation Index - All guides, deployment instructions, and development resources
- Install deps (npm-only)
npm install
- Create and fill env file
Required values in
cp .env.example .env.local
.env.local:- AZURE_STORAGE_ACCOUNT_NAME, AZURE_STORAGE_ACCOUNT_KEY, AZURE_STORAGE_CONTAINER_NAME=pig-images
- CONTENT_UNDERSTANDING_ENDPOINT (https://{custom-subdomain}.cognitiveservices.azure.com/)
- CONTENT_UNDERSTANDING_KEY (subscription key)
- AI_FOUNDRY_* (from Terraform outputs; not required at runtime today)
- Run the app
Open http://localhost:3000 and verify
npm run dev
GET /api/analyzereturns{ status: 'ok' }.
- Provision infra (from
iac/)cd iac terraform init terraform plan -out=main.tfplan terraform apply main.tfplan - Retrieve secrets for local dev (Key Vault)
App Service uses Key Vault references; restart after changes:
az keyvault secret show --vault-name <kv-name> --name content-understanding-key --query value -o tsv az keyvault secret show --vault-name <kv-name> --name storage-account-key --query value -o tsv
az webapp restart --resource-group <rg> --name <app-name>
- Configure GitHub Actions (OIDC)
- Secrets: AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_SUBSCRIPTION_ID, AZURE_WEBAPP_NAME
- Workflow:
.github/workflows/azure-deploy.ymlpackages Next.js standalone and deploys via ZIP
- Deploy
- Push to
mainor run the workflow manually - Or deploy manually using the standalone ZIP steps in βDeploymentβ below
- Push to
-
terraform applycompleted without errors - AI Services endpoint (custom subdomain) noted
- Secrets present in Key Vault (content-understanding-key, storage-account-key)
- App Service restarted to pick up Key Vault references
-
.env.localpopulated for local runs
- 5-Minute Drawing Timer: Guided drawing experience with countdown timer
- Smart Image Upload: Drag-and-drop or camera capture for mobile
- AI-Powered Analysis: Azure AI Content Understanding extracts visual features
- Personality Insights: Rule-based engine maps features to personality traits
- Group Mode: Upload multiple drawings and compare results with discussion prompts
- Admin Dashboard: Export all results as CSV/JSON
- Privacy-First: Images automatically deleted after 24 hours
The app analyzes your pig drawing based on:
| Feature | Analysis | Interpretation |
|---|---|---|
| Vertical Placement | Top / Middle / Bottom | Optimism level and outlook on life |
| Orientation | Left / Right / Front | Tradition vs innovation; interpersonal style |
| Detail Level | Many / Few | Analytical vs emotional thinking |
| Leg Count | <4 / 4 | Security and stability in life |
| Ear Size | Large / Normal | Listening skills and empathy |
| Tail Length | Long / Normal | Intelligence indicators |
- Frontend: Next.js 15 (App Router), TypeScript, React Server Components, Tailwind CSS
- Backend: Next.js API Routes (Node.js runtime)
- AI Service: Azure AI Content Understanding (REST API)
- Storage: Azure Blob Storage (images + JSON results)
- Secrets: Azure Key Vault
- Infrastructure: Terraform (IaC)
- Hosting: Azure App Service (Linux)
- Testing: Jest + React Testing Library
- Node.js 20+ and npm
- Azure subscription
- Terraform 1.0+ (for infrastructure deployment)
Note: This project is npm-only (package-lock.json is committed). Do not use pnpm or yarn.
-
Clone the repository
cd pig-personality-test -
Install dependencies
npm install
-
Set up environment variables
cp .env.example .env.local
Fill in
.env.localwith these values (from Terraform outputs/Key Vault):AZURE_STORAGE_ACCOUNT_NAMEβ storage account nameAZURE_STORAGE_ACCOUNT_KEYβ storage account access keyAZURE_STORAGE_CONTAINER_NAMEβ should bepig-imagesCONTENT_UNDERSTANDING_ENDPOINTβ https://{custom-subdomain}.cognitiveservices.azure.com/CONTENT_UNDERSTANDING_KEYβ AI Services subscription keyAI_FOUNDRY_HUB_NAMEβ hub nameAI_FOUNDRY_HUB_IDβ hub resource IDAI_FOUNDRY_PROJECT_NAMEβ project nameAI_FOUNDRY_PROJECT_IDβ project resource ID
Tip: The AI Foundry values are provisioned by Terraform for future integrations and arenβt required at runtime today.
-
Run development server
npm run dev
-
Run tests
npm test
-
Navigate to infrastructure directory
cd iac -
Initialize Terraform
terraform init
-
Review the plan
terraform plan -out=main.tfplan
-
Apply infrastructure
terraform apply main.tfplan
-
Get outputs
terraform output
This provisions:
- β Resource Group
- β
Storage Account (with containers:
pig-images,pig-results) - β Key Vault (stores secrets)
- β Azure AI Services (Content Understanding)
- β Azure AI Foundry Workspace (hub for AI projects)
- β Application Insights (monitoring)
- β App Service Plan + Web App (Linux, Node.js 20)
Terraform stores secrets in Key Vault. To retrieve them:
# Get Content Understanding key
az keyvault secret show --vault-name <your-keyvault-name> --name content-understanding-key --query value -o tsv
# Get Storage account key
az keyvault secret show --vault-name <your-keyvault-name> --name storage-account-key --query value -o tsvThis app uses Next.js standalone output. Package the standalone server and deploy via ZIP:
# Build production
npm run build
# Create deployment payload (standalone)
rm -rf deploy && mkdir -p deploy/.next/static deploy/public
cp -r .next/standalone/. deploy/
cp -r .next/static/. deploy/.next/static/
[ -d public ] && cp -r public/. deploy/public/ || true
# Add startup script
cat > deploy/startup.sh << 'EOF'
#!/bin/sh
PORT="${PORT:-8080}"
node server.js
EOF
chmod +x deploy/startup.sh
# Zip and deploy
cd deploy && zip -r ../deployment.zip . && cd ..
az webapp deployment source config-zip \
--resource-group rg-draw-the-pig \
--name <your-app-service-name> \
--src deployment.zip \
--timeout 600The repo includes a GitHub Actions workflow (.github/workflows/azure-deploy.yml) that:
- Builds the Next.js app (standalone output)
- Runs tests
- Packages
.next/standalone+ static + public and adds astartup.sh - Deploys to Azure App Service via ZIP using OIDC authentication
-
Create a service principal with federated credentials (see DEPLOYMENT.md for detailed steps)
-
Configure GitHub secrets:
AZURE_CLIENT_ID- Service principal application IDAZURE_TENANT_ID- Your Azure tenant IDAZURE_SUBSCRIPTION_ID- Your Azure subscription IDAZURE_WEBAPP_NAME- App Service name (e.g.,<your-project-name>-app-<suffix>)
-
Push to
mainbranch or manually trigger the workflow
See DEPLOYMENT.md for complete setup instructions.
- Local: http://localhost:3000 should load the app
- Health check:
GET /api/analyzereturns{ status: 'ok' } - Image domains: ensure Azure Blob URLs are allowed (see
next.config.tsimages.remotePatterns)
- Tail logs for App Service:
az webapp log tail --resource-group <your-resource-group> --name <your-app-name>
- After changing app settings, restart:
az webapp restart --resource-group <your-resource-group> --name <your-app-name>
- More tips in DEPLOYMENT.md
The project includes comprehensive unit tests for the pig rules engine:
# Run all tests
npm test
# Watch mode
npm run test:watch
# Coverage report
npm test -- --coverageTest coverage includes:
- β Placement analysis (top/middle/bottom)
- β Detail level detection (many/few)
- β Leg count variations (0, 2, 3, 4 legs)
- β Ear size evaluation
- β Tail length assessment
- β Summary generation
- β Edge cases
pig-personality-test/
βββ app/ # Next.js App Router
β βββ layout.tsx # Root layout with navigation
β βββ page.tsx # Landing page
β βββ draw/ # Timer page
β βββ upload/ # Image upload page
β βββ results/[id]/ # Individual result view
β βββ group/ # Group mode
β β βββ results/ # Group comparison view
β βββ admin/ # Admin dashboard
β βββ api/
β βββ analyze/ # Analysis API endpoint
βββ lib/
β βββ types.ts # TypeScript definitions
β βββ azure/
β β βββ content-understanding.ts # Azure REST client
β βββ scoring/
β β βββ pigRules.ts # Personality rules engine
β βββ storage/
β βββ blob.ts # Blob storage helpers
β βββ results.ts # Result persistence
βββ iac/ # Terraform infrastructure
β βββ main.tf
β βββ variables.tf
β βββ outputs.tf
βββ tests/
β βββ pigRules.test.ts # Unit tests
βββ README.md
- Secrets Management: All credentials stored in Azure Key Vault
- Image Retention: Drawings automatically deleted after 24 hours
- Private Results: Analysis results stored in private blob container
- HTTPS Only: All traffic encrypted via HTTPS
- No PII Storage: No personal information collected beyond drawings
Analyzes a pig drawing and returns personality insights.
Request:
{
"imageBase64": "data:image/jpeg;base64,...",
"participantName": "Optional name"
}Response:
{
"id": "uuid-string",
"summary": "You have a tendency to be positive...",
"evidence": [
{
"key": "placement=Top",
"value": 0.25
}
]
}Detailed documentation is available in the following files:
-
DEPLOYMENT.md - Complete Azure deployment guide
- Resource inventory and URLs
- Local development setup
- Manual and automated deployment options
- AI Foundry hub and project setup
- Monitoring and troubleshooting
- Cleanup instructions
-
GITHUB-SECRETS-SETUP.md - GitHub Actions CI/CD setup
- Service principal creation with OIDC
- Required GitHub secrets configuration
- Step-by-step deployment pipeline setup
-
.github/copilot-instructions.md - Development guidelines
- Project architecture and patterns
- Critical conventions and best practices
- Common pitfalls and solutions
- File organization and structure
This is a demonstration project. For production use:
- Add rate limiting to
/api/analyze - Implement authentication for admin routes
- Add monitoring and alerting (Application Insights)
- Set up automated image cleanup cron job
- Configure custom domain and SSL
- Azure AI Content Understanding Documentation
- Azure AI Content Understanding REST API Quickstart
- Terraform Azure Provider
- Next.js 15 Documentation
This project is provided as-is for educational and demonstration purposes.
- Psychology-based "Draw the Pig" personality test rubric
- Azure AI Content Understanding team for image analysis capabilities
- Next.js team for the excellent React framework
Built with β€οΈ using Azure AI and Next.js