Template Doctor analyzes and validates samples and templates, including but not limited to Azure Developer CLI (azd) templates. It provides a web UI to view analysis results and take action, including opening GitHub issues and assigning them to GitHub copilot in one go. It also automates PR updates with scan results.
Template Doctor is a containerized application that analyzes and validates samples and templates, with a focus on Azure Developer CLI (azd) templates. It provides:
- Web UI: TypeScript-based Vite SPA for viewing analysis results and managing templates
- REST API: Express backend for validation, OAuth, and GitHub integration
- Containerized Deployment: Docker-based architecture for consistent development and production environments
- One-Click Actions: GitHub issue creation with AI-powered suggestions and automated PR updates
- Template Analysis: Validate templates against organization standards and best practices
- Interactive Web UI: TypeScript-based Vite SPA for viewing and managing analysis results
- Security Analysis: Bicep security checks for Managed Identity, insecure auth patterns, and anonymous access
- AI Integration: One-click GitHub issue creation with AI-powered suggestions
- Automated Workflows: PR updates with scan results and deployment testing
- Azure Developer CLI (azd): AZD deployment validation and testing
- AI Model Checks: Automated deprecation checking for AI models
- Centralized Archive: Metadata storage for analysis results
- CI/CD Integration: Automated API smoke tests and deployment workflows
Template Doctor is a containerized monorepo with independently deployable packages:
-
packages/app: Vite SPA (TypeScript frontend)
- Built with Vite for fast development and optimized production builds
- Serves dashboard at http://localhost:3000 (preview/production)
- Development server at http://localhost:4000 with HMR
- Loads scan results from
packages/app/results/
-
packages/server: Express backend (TypeScript REST API)
- RESTful API at http://localhost:3001
- Handles OAuth token exchange, template validation, and GitHub integration
- CORS-enabled for frontend communication
- Serves static frontend assets in production
-
packages/analyzer-core: Core analyzer functionality (shared library)
- Shared validation logic used by both server and legacy API
- Bundled into dependent packages during build
-
Docker: Containerized deployment
docker-compose.yml
: Multi-container development setupDockerfile.combined
: Single-container production build- Includes all services (frontend + backend) in one deployable unit
- packages/api: Azure Functions (maintained in
legacy/azure-functions
branch)- Original serverless implementation
- Preserved for reference and migration comparison
- Optional build with
--if-present
flag
Results live under packages/app/results/
:
packages/app/results/index-data.js
— Master list of scanned templates (window.templatesData)packages/app/results/<owner-repo>/<timestamp>-data.js
— Per-scan data (window.reportData)packages/app/results/<owner-repo>/<timestamp>-dashboard.html
— Per-scan dashboard
- Node.js LTS (v20.x, enforced by guard script)
- npm (for dependency management)
- Docker & Docker Compose (recommended for local development)
- GitHub account with appropriate permissions
Note
The project enforces Node.js LTS range: >=20 <23. A guard script (scripts/ensure-node-version.js
) will fail fast if you use an unsupported version. Use nvm install 20 && nvm use 20
if needed.
-
Clone the repository:
git clone https://github.com/Template-Doctor/template-doctor.git cd template-doctor
-
Install dependencies:
npm ci
-
Configure environment:
cp .env.example .env
Edit
.env
with your values (see Environment Variables below) -
Start with Docker Compose:
docker-compose up
-
Access the application:
- Frontend: http://localhost:3000
- Backend API: http://localhost:3001
If you prefer running services without Docker:
-
Follow steps 1-3 from Quick Start above
-
Build packages:
npm run build -w packages/server npm run build -w packages/app
-
Start services in SEPARATE terminals:
Terminal 1 - Express Backend (port 3001):
cd packages/server npm run dev
Terminal 2 - Vite Dev Server (port 4000):
cd packages/app npm run dev
-
Access the application: http://localhost:4000
Important
The Express backend MUST be running before using OAuth login or analysis features. Hard refresh (Cmd+Shift+R / Ctrl+Shift+R) required after config changes.
Service | Development | Preview | Docker |
---|---|---|---|
Vite Dev Server | 4000 | - | - |
Vite Preview | - | 3000 | 3000 |
Express Backend | 3001 | 3001 | 3001 |
- Create a GitHub OAuth app with appropriate callback URL
- Configure environment variables or config.json settings
- See OAuth Configuration Guide for detailed instructions
Warning
You will need different app registrations for local and production environments.
- Run
npm run setup:uami
before you get started - Create an
.env
file at the root, using ./.env.example as a guide - See UAMI Setup Instructions for detailed steps
Template Doctor uses a consolidated approach to environment variables. All variables are defined in a single .env
file at the root of the project.
-
Copy the example file:
cp .env.example .env
-
Required variables:
GITHUB_CLIENT_ID
: OAuth app client ID (required for authentication)GITHUB_CLIENT_SECRET
: OAuth app client secret (required for authentication)GH_WORKFLOW_TOKEN
: GitHub token with workflow permissions
-
Configuration layers:
- Backend (
packages/server/.env
): Copied from root during Docker build - Frontend (
packages/app/config.json
): Client configuration with backend URLs - Environment (
.env
at repo root): Single source of truth for shared config
- Backend (
See the Environment Variables Documentation for a complete reference of all available variables.
-
Install dependencies:
npm ci
-
Start all services:
docker-compose up
-
Access the application:
- Frontend: http://localhost:3000
- Backend API: http://localhost:3001
-
Install dependencies:
npm ci
-
Build packages:
npm run build:analyzer-core npm run build -w packages/server npm run build -w packages/app
-
Terminal 1 - Start Express backend:
cd packages/server npm run dev
-
Terminal 2 - Start Vite dev server:
cd packages/app npm run dev
-
Open browser: http://localhost:4000
Note
The Vite dev server provides hot module replacement (HMR) for fast TypeScript development. The Express backend must be running before using OAuth or analysis features.
From the project root:
npm test # Run all tests
npm run test:ui # Run tests with UI
npm run test:debug # Run tests in debug mode
npm run test -- "-g" "should handle search functionality" packages/app/tests/app.spec.js
For quick end-to-end verification of Express endpoints:
./scripts/smoke-api.sh # Default (http://localhost:3001)
BASE=http://localhost:3001 ./scripts/smoke-api.sh # Override base URL
DRY_RUN=1 ./scripts/smoke-api.sh # Print commands only
The smoke script verifies:
- Config endpoint (
/api/v4/client-settings
) - Validation endpoints
- Analysis endpoints
- OAuth flow (if
GITHUB_TOKEN
present)
Note
Test files use Playwright for E2E testing. Avoid native browser dialogs in code (use notifications) to keep tests stable.
npm run build:all
This builds packages in the correct dependency order:
analyzer-core
(shared library)server
(Express backend)app
(Vite frontend)
# Build the combined image
docker build -f Dockerfile.combined -t template-doctor .
# Run the container
docker run -p 3000:3000 --env-file .env template-doctor
The combined Dockerfile:
- Builds all packages (analyzer-core → server → app)
- Serves frontend and API from single Express process
- Optimized for production deployment
# Start all services
docker-compose up
# Rebuild and restart
docker-compose up --build
# Stop services
docker-compose down
# Build all packages
npm run build:all
# Start preview server (port 3000)
npm run preview -w packages/server
Access at http://localhost:3000
- Origin Upstream Requirement: For provisioning templates with azd, the canonical upstream must be provided in the format
owner/repo
. This is used forazd init -t <owner/repo>
and ensures the test/provision flow uses the correct azd template. - Results Storage: New scan PRs write to
packages/app/results/
and updatepackages/app/results/index-data.js
. - Independent Deployment: Each package is deployable independently via dedicated workflows.
- TypeScript-First: All new code should be TypeScript with proper type definitions.
- No Mocks in Production: All implementations must be complete and production-ready (see
.github/instructions/copilot-instructions.md
).
-
OAuth redirect issues: Ensure ports match between GitHub OAuth app settings and local server
- Development: Frontend 4000, Backend 3001
- Preview/Docker: Frontend 3000, Backend 3001
-
Express server not starting:
- Check
.env
file exists with required variables - Verify port 3001 is not in use:
lsof -i :3001
- Check
-
Docker issues:
- Ensure Docker and Docker Compose are installed and running
- Check logs:
docker-compose logs
-
Port conflicts: Kill processes if needed:
lsof -ti :3000 | xargs kill -9 # Frontend preview lsof -ti :3001 | xargs kill -9 # Backend lsof -ti :4000 | xargs kill -9 # Frontend dev
-
Configuration mismatch: Verify
config.json
has correctgithubOAuth.clientId
matching.env
Located in .github/workflows/
:
-
smoke-api.yml: API smoke tests
- Runs on push/PR to verify Express API endpoints
- Builds analyzer-core → server → runs smoke tests
- See badge at top of README
-
Nightly Deploy: Automated deployment
- Runs nightly at 02:15 UTC
- Can be triggered manually via "Run workflow"
- See details: docs/usage/DEPLOYMENT.md
-
Submit Template Analysis: repository_dispatch workflow
- Saves scan results and opens a PR using
peter-evans/create-pull-request
- See setup guide: docs/usage/GITHUB_ACTION_SETUP.md
- Saves scan results and opens a PR using
- After "Save Results" creates a PR and the PR is merged, results appear on the site after the nightly deploy
- Admins can run the deploy workflow manually to publish immediately
- The UI shows a notification to inform users of this timing
Workflows under .github/workflows/
:
-
Azure Static Web Apps (SWA):
- Uses
Azure/static-web-apps-deploy@v1
app_location: /packages/app
api_location: /packages/api
- Uses
-
Nightly Static Web Apps Deploy (SWA CLI):
- Workflow:
.github/workflows/nightly-swa-deploy.yml
- Runs nightly at 02:15 UTC and can be triggered manually via "Run workflow"
- Requires repo secret
SWA_CLI_DEPLOYMENT_TOKEN
(Static Web App deployment token) - See details: docs/usage/DEPLOYMENT.md
- Workflow:
-
Submit Template Analysis (repository_dispatch):
- Saves scan results and opens a PR using
peter-evans/create-pull-request
- See setup guide (including bot token fallback): docs/usage/GITHUB_ACTION_SETUP.md
- Saves scan results and opens a PR using
Publishing results
- After “Save Results” creates a PR and the PR is merged, results appear on the site after the nightly deploy. Admins can run the deploy workflow manually to publish immediately. The UI shows a notification to inform users of this timing.
Template Doctor can also archive a small JSON metadata file to a central repository for each analysis.
- How to enable and required variables: see
- Env vars reference: docs/development/ENVIRONMENT_VARIABLES.md
- Action setup (archive section): docs/usage/GITHUB_ACTION_SETUP.md
Quick checklist
- In GitHub repo (Settings → Secrets and variables → Actions):
- Set
TD_API_BASE
to your API base (e.g.,https://<your-swa>.azurestaticapps.net/api
). - Optionally set
TD_ARCHIVE_COLLECTION
(defaults toaigallery
).
- Set
- In Azure Functions (Application Settings):
- Set
GH_WORKFLOW_TOKEN
with Contents & Pull requests write access to the central archive repo (authorize SSO if needed).
- Set
- Enable archiving:
- Globally: set
archiveEnabled: true
in runtime-config, or - Per-run: check the “Also save metadata to the centralized archive for this analysis” box in the analyze modal when global is off.
- Globally: set
- Add/update tests for features and fixes. Frontend E2E tests live in the app package; run from root via
npm test
. - Avoid native browser dialogs; use notifications to keep tests stable.
- Format code before committing (packages may include prettier configs and scripts).
- Don't commit generated artifacts like
node_modules/
or large reports. - Update docs and workflows when changing paths or behavior.
Template Doctor now includes enhanced security analysis for Bicep files:
-
Managed Identity Detection: Identifies when Managed Identity is properly used in Azure resources.
-
Insecure Authentication Detection: Identifies and flags insecure authentication methods like:
- Connection strings with embedded credentials
- Access keys
- SAS tokens
- Storage account keys
- KeyVault secrets accessed without Managed Identity
-
Anonymous Access Detection: Identifies Azure resources that typically require authentication but may be configured for anonymous access.
These security checks can be enabled/disabled in each rule set configuration by setting the bicepChecks.securityBestPractices
properties:
"bicepChecks": {
"requiredResources": [...],
"securityBestPractices": {
"preferManagedIdentity": true,
"detectInsecureAuth": true,
"checkAnonymousAccess": true
}
}
For issues, please open a GitHub issue.