To start discovering Github Copilot jump to The Ultimate GitHub Copilot Tutorial on MOAW
This repository has been inspired by the Azure Container Apps: Dapr Albums Sample
It's used as a code base to demonstrate Github Copilot capabilities.
The solution is composed of a frontend plus backend services: the .NET album API, the TypeScript album-api-v2 rewrite, and the NodeJS album viewer.
The album-api-v2 is the primary local backend. It is a Node.js + TypeScript rewrite of the albums API, keeps the catalog in memory, starts on http://localhost:3000 by default, and serves a normalized contract:
- Albums are written with
artist_id,release_date,price, andimage_url - Albums are read back with joined
artistdetails plus a derivedyear - Artists are managed through
GET /artists,GET /artists/{id},POST /artists,PUT /artists/{id}, andDELETE /artists/{id} - Albums remain available through
GET /albums,GET /albums/{id},POST /albums,PUT /albums/{id},DELETE /albums/{id}, plusGET /albums/searchandGET /albums/sorted
The album-api is the original .NET 8 implementation kept in the repo for comparison and migration demos.
The album-viewer is a modern Vue.js 3 application built with TypeScript through which the albums retrieved by the API are surfaced. The application uses the Vue 3 Composition API with full TypeScript support for enhanced developer experience and type safety. In order to display the repository of albums, the album viewer contacts the backend album API.
The current UI includes:
- album browsing with joined artist metadata
- cart persistence and locale persistence
- album CRUD from the Catalog Studio panel
- artist browsing and filtering from the Artists panel
- artist CRUD from the Artist Studio panel
- richer album preview details including release date, derived year, and creation timestamps
There are multiple ways to run this solution locally. Choose the method that best fits your development workflow.
- .NET 8 SDK
- Node.js (version 16 or higher)
- TypeScript (automatically installed with project dependencies)
- Visual Studio Code (recommended)
If you cannot install system-wide packages, use the local installer script:
./scripts/install-dotnet8-local.shThis installs .NET to ~/.dotnet and prints the DOTNET_ROOT and PATH lines to add to your shell profile.
This is the easiest way to run the solution with full debugging capabilities.
- Open the solution in Visual Studio Code
- Open the Debug panel (Ctrl+Shift+D / Cmd+Shift+D)
- Select "All services" from the dropdown
- Click the green play button or press F5
This will automatically:
- Start
album-api-v2onhttp://localhost:3000 - Start the Vue.js TypeScript app on
http://localhost:3001 - Open both services in your default browser
You can also run individual services:
- "Node.js: Album API V2 Debug" - Runs the TypeScript backend
- "Node.js: Album Viewer Debug" - Runs only the Vue.js TypeScript frontend
- "All services (.NET)" - Uses the legacy .NET backend instead of
album-api-v2
# Navigate to the API directory
cd album-api-v2
# Restore dependencies (first time only)
npm install
# Run the API in watch mode
npm run dev
# Or build and run the compiled output
npm run build
npm run startThe API starts on http://localhost:3000 by default.
With album-api-v2 running on port 3000 and the Vue dev server running on port 3001, run:
node scripts/smoke-album-app.mjsThis checks that the Vue dev server is serving HTML and that http://localhost:3001/albums proxies through to the backend successfully.
To verify the rendered album cards in a real browser context, run:
cd album-viewer
npm run smokeThis launches album-api-v2 on port 3000, the Vue dev server on port 3001, opens Chromium headlessly, and runs the smoke suite for album browsing, cart flows, persistence, artist browsing, artist CRUD, and album CRUD.
# Navigate to the API directory
cd albums-api
# Restore dependencies (first time only)
dotnet restore
# Run the API
dotnet runThe API will start on http://localhost:3000 and you can access the Swagger documentation at http://localhost:3000/swagger.
# Navigate to the viewer directory
cd album-viewer
# Install dependencies (first time only)
npm install
# Start the development server
npm run dev
# Optional: Run TypeScript type checking
npm run type-checkThe Vue.js TypeScript app will start on http://localhost:3001 and automatically open in your browser.
You can run both services simultaneously using separate terminal windows:
# Terminal 1 - Start the API
cd albums-api
dotnet run
# Terminal 2 - Start the Vue TypeScript app
cd album-viewer
npm run devThe solution uses the following default configuration:
- Album API V2: Runs on
http://localhost:3000 - Album Viewer: Runs on
http://localhost:3001(TypeScript + Vue 3) - API Endpoint: The Vue app is configured to call the API at
localhost:3000
If you need to change these settings, you can modify:
- API port for
album-api-v2:album-api-v2/src/server.tsor thePORTenvironment variable - Legacy .NET API port:
albums-api/Properties/launchSettings.json - Vue app configuration: Environment variables in
.vscode/launch.jsonor setVITE_ALBUM_API_HOSTenvironment variable
The easiest way is to open this solution in a GitHub Codespace, or run it locally in a devcontainer. The development environment will be automatically configured for you.
Use the Bicep template in iac/bicep/main.bicep to deploy both services to Azure Container Apps.
- Azure CLI
- An Azure subscription where you can create resources
az login
az account set --subscription "<your-subscription-id-or-name>"RESOURCE_GROUP="rg-albums-demo"
LOCATION="eastus"
ACR_NAME="acr$(openssl rand -hex 4)"
API_IMAGE_NAME="albums-api"
VIEWER_IMAGE_NAME="album-viewer"
IMAGE_TAG="$(date +%Y%m%d%H%M%S)"az group create --name "$RESOURCE_GROUP" --location "$LOCATION"
az acr create \
--resource-group "$RESOURCE_GROUP" \
--name "$ACR_NAME" \
--sku Standard \
--admin-enabled trueaz acr build \
--registry "$ACR_NAME" \
--image "$API_IMAGE_NAME:$IMAGE_TAG" \
--file albums-api/Dockerfile \
albums-api
az acr build \
--registry "$ACR_NAME" \
--image "$VIEWER_IMAGE_NAME:$IMAGE_TAG" \
--file album-viewer/Dockerfile \
album-viewerACR_SERVER="$(az acr show -n "$ACR_NAME" -g "$RESOURCE_GROUP" --query loginServer -o tsv)"
ACR_USERNAME="$(az acr credential show -n "$ACR_NAME" --query username -o tsv)"
ACR_PASSWORD="$(az acr credential show -n "$ACR_NAME" --query passwords[0].value -o tsv)"
az deployment group create \
--resource-group "$RESOURCE_GROUP" \
--template-file iac/bicep/main.bicep \
--parameters \
registryName="$ACR_SERVER" \
registryUsername="$ACR_USERNAME" \
registryPassword="$ACR_PASSWORD" \
apiImage="$ACR_SERVER/$API_IMAGE_NAME:$IMAGE_TAG" \
viewerImage="$ACR_SERVER/$VIEWER_IMAGE_NAME:$IMAGE_TAG"az containerapp show -g "$RESOURCE_GROUP" -n album-api --query properties.configuration.ingress.fqdn -o tsv
az containerapp show -g "$RESOURCE_GROUP" -n album-viewer --query properties.configuration.ingress.fqdn -o tsvUse the returned host names with https:// in your browser.
If deployment fails, check the following common issues.
- Ensure ACR admin credentials are enabled:
az acr update --name "$ACR_NAME" --admin-enabled true- Re-read credentials before deployment:
ACR_USERNAME="$(az acr credential show -n "$ACR_NAME" --query username -o tsv)"
ACR_PASSWORD="$(az acr credential show -n "$ACR_NAME" --query passwords[0].value -o tsv)"- Confirm images exist in ACR:
az acr repository list --name "$ACR_NAME" -o table
az acr repository show-tags --name "$ACR_NAME" --repository "$API_IMAGE_NAME" -o table- ACR names must be globally unique and use only lowercase letters and numbers.
- If a region is capacity-constrained, retry with another location such as
westeuropeorwestus2.
If this is a new subscription, register required providers:
az provider register --namespace Microsoft.App
az provider register --namespace Microsoft.OperationalInsights
az provider register --namespace Microsoft.Insights
az provider register --namespace Microsoft.Storageaz deployment group list -g "$RESOURCE_GROUP" -o table
az deployment group show -g "$RESOURCE_GROUP" -n <deployment-name>
az containerapp revision list -g "$RESOURCE_GROUP" -n album-api -o table
az containerapp logs show -g "$RESOURCE_GROUP" -n album-api --followWhen you are done with the environment, remove the deployed Azure resources to avoid ongoing costs.
az group delete --name "$RESOURCE_GROUP" --yes --no-waitOptional: monitor deletion status.
az group exists --name "$RESOURCE_GROUP"If you created additional resource groups for this demo, repeat the same command for each group.