### Summary of Changes
1. Documentation Consolidation:
• Relocated the docs/ folder and all repository .md files (README.md, DEPLOYMENT.md, DOCKER_README.md,
DOMAINS_README.md, GETTING_STARTED.md, CI_CD_PORTAINER_GUIDE.md, ADMIN_DEPLOYMENT_SUMMARY.md,
SECURITY_PRIVATE_FILES.md, handoff.md, azure-project-plan.md, plus service-specific READMEs) into .
• Updated document links in README.md.
2. AI Agent Project Map:
• Created PROJECT_MAP.md in the project root containing complete architecture diagrams, service specs, ports, DB
schemas, environment variables, and developer workflows.
• Added PROJECT_MAP.md to .gitignore.
3. Monitoring UI & Infrastructure Integration:
• Added monitoring_ui service to docker-compose.yml (port 5175).
• Configured Gitea workflow docker-build.yml for monitoring_ui builds.
• Added CORS middleware headers in index.js.
• Added nginx.conf copy step in Dockerfile.
──────
### Recommended Commit Message
docs: consolidate project documentation into monitoring_ui and add agent project map
- Move all markdown documentation files and docs/ folder into monitoring_ui/docs/
- Update documentation hub index (monitoring_ui/docs/README.md) with relative paths
- Generate comprehensive AI agent reference map (PROJECT_MAP.md) in repository root
- Add PROJECT_MAP.md and monitoring_ui build output/env overrides to .gitignore
- Integrate monitoring_ui service into docker-compose.yml and Gitea CI workflow
- Configure CORS handling in employee_api for monitoring dashboard access
──────
### Alternative Short Commit Message
refactor(docs): move docs to monitoring_ui and create AI agent PROJECT_MAP.md
8.5 KiB
Important: This skill provides guidance and recommended instructions to assist the AI system. Outputs are not guaranteed to be complete, correct, secure, or applicable to every scenario. Results should be reviewed and validated by a human before being applied. The AI model may choose not to follow all instructions exactly, and additional verification may be required.
App Onboard Prepare — Per-Service Pricing Patterns
Filter strings, meter names, and formulas per Azure service. For methodology and troubleshooting, see pricing-guide.md.
Container Apps
No armSkuName. Filter: serviceName eq 'Azure Container Apps' and armRegionName eq '{region}' and priceType eq 'Consumption' and isPrimaryMeterRegion eq true
Key meters: Standard vCPU Active Usage (1 Second), Standard Memory Active Usage (1 GiB Second), Standard Requests (1M).
Monthly (Consumption, 1 vCPU, 2 GiB, 8h active/day):
(vCPU_active_rate × 3600 × 8 × 30) + (memory_active_rate × 2 × 3600 × 8 × 30)
Free grant: 180K vCPU-sec + 360K GiB-sec + 2M requests/sub/month. Scale-to-zero = $0 idle. When min_replicas >= 1: add idle cost from idle meters.
Container Registry (ACR)
Empty armSkuName — ⛔ do NOT filter by sku (returns []). Filter: serviceName eq 'Container Registry' and armRegionName eq '{region}' and priceType eq 'Consumption', then match meterName.
| Tier | meterName |
unitOfMeasure |
Monthly |
|---|---|---|---|
| Basic | Basic Registry Unit |
1/Day |
retailPrice × 30 (~$5) |
| Standard | Standard Registry Unit |
1/Day |
retailPrice × 30 (~$20) |
| Premium | Premium Registry Unit |
1/Day |
retailPrice × 30 (~$50) |
⛔ 1/Day → × 30, NOT × 730. The other ACR meters (Task vCPU Duration = 1 Second build compute, Data Stored = 1 GB/Month) are usage-based — exclude from the fixed monthly unless the app builds heavily. ACR Basic fixed cost ≈ $5/mo.
App Service
MCP call: pricing_get --service "Azure App Service" --region "{region}"
Meter-to-SKU mapping:
| SKU | meterName |
Notes |
|---|---|---|
| B1 | B1 |
Compute floor — no F1/Free (see sku-matrix.md) |
| B2 | B2 |
|
| S1 | S1 App |
|
| P1v3 | P1 v3 App |
Linux/Windows have different productName |
Gotcha: armSkuName empty for Basic/Standard. Match on meterName.
Monthly: retailPrice × 730
Azure SQL Database
DTU model — no armSkuName. Filter by productName + meterName.
| SKU | productName contains |
meterName (unit: 1/Day) |
|---|---|---|
| Basic (5 DTU) | SQL Database Single Basic |
B DTU |
| S0 (10 DTU) | SQL Database Single Standard |
S0 DTUs |
| S1 (20 DTU) | SQL Database Single Standard |
S1 DTUs |
Monthly (DTU): retailPrice × 30
vCore model: productName filters — Serverless: 'SQL Database General Purpose - Serverless - Compute Gen5'. Hyperscale: 'SQL Database Single/Elastic Pool Hyperscale'. Monthly: retailPrice × 730.
Cosmos DB
Filter: serviceName eq 'Azure Cosmos DB' and armRegionName eq '{region}' and priceType eq 'Consumption' and isPrimaryMeterRegion eq true
| Model | Match on | Monthly formula |
|---|---|---|
| Provisioned | meterName eq '100 RU/s', productName eq 'Azure Cosmos DB' |
(targetRU / 100) × retailPrice × 730 |
| Autoscale | productName eq 'Azure Cosmos DB autoscale', meterName starts with AP |
varies |
| Serverless | productName eq 'Azure Cosmos DB serverless', meterName eq '1M RUs' |
retailPrice × estimatedMillionsOfRU |
⚠️ Provisioned 100 RU/s gotcha: The
isPrimaryMeterRegion eq trueentry hasretailPrice: 0(free-tier placeholder). The real price (~$0.008/hr in eastus) hasisPrimaryMeterRegion: false. DropisPrimaryMeterRegionfrom the filter or match onretailPrice > 0.
Storage: meterName eq 'Data Stored' with productName eq 'Azure Cosmos DB' (1 GB/Month). Note: this meter has isPrimaryMeterRegion: false — drop that filter or query without it.
Free tier: 1,000 RU/s + 25 GB per account (one per subscription).
Storage
No armSkuName. Filter by meterName + productName.
Filter (Hot LRS Blob):
serviceName eq 'Storage' and armRegionName eq '{region}' and meterName eq 'Hot LRS Data Stored' and productName eq 'Blob Storage'
Meter-to-SKU mapping:
| SKU matrix tier | meterName |
productName |
|---|---|---|
| Standard_LRS | Hot LRS Data Stored |
Blob Storage or General Block Blob v2 |
| Standard_GRS | Hot GRS Data Stored |
Blob Storage or General Block Blob v2 |
| Premium_LRS | Premium LRS Data Stored |
Premium Block Blob |
Monthly: retailPrice × estimatedGB
Service Bus
Filter:
serviceName eq 'Service Bus' and armRegionName eq '{region}'
⚠️ Do NOT add
isPrimaryMeterRegion eq true— all Service Bus meters haveisPrimaryMeterRegion: false. Adding that filter returns zero useful results.
Key meters:
| Tier | meterName |
Unit | Notes |
|---|---|---|---|
| Basic | Basic Messaging Operations |
1M | Usage-based only |
| Standard | Standard Base Unit |
1/Hour | Base cost (always-on) |
| Standard | Standard Messaging Operations |
1M | Tiered: first 13M free |
| Premium | Premium Messaging Unit |
1/Hour | Per messaging unit |
Monthly (Standard): baseUnitRate × 730 + operations beyond free tier. Standard tiered: first 13M free.
Gotcha: Standard Base Unit has two entries — hourly and monthly. Use hourly × 730.
Redis Cache
armSkuName IS populated — pricing_get --sku works.
MCP call: pricing_get --service "Redis Cache" --sku "{armSkuName}" --region "{region}"
armSkuName pattern: Azure_Redis_Cache_{Tier}_{Size}_Cache (e.g., Azure_Redis_Cache_Basic_C0_Cache, Azure_Redis_Cache_Standard_C1_Cache). Query the MCP tool for exact pricing.
Gotcha: Basic tier entries have isPrimaryMeterRegion: false. The standard filter strips them out. Query by armSkuName directly or omit isPrimaryMeterRegion and match on productName eq 'Azure Redis Cache Basic'.
Monthly: retailPrice × 730
Azure Database for PostgreSQL Flexible Server
armSkuName IS populated — pricing_get --sku works. ⛔ skuName is CASE-SENSITIVE: B1MS works, B1ms returns 0 results.
MCP call: pricing_get --service "Azure Database for PostgreSQL" --sku "{armSkuName}" --region "{region}"
armSkuName values: ⛔ Case-sensitive. Small Burstable uses short names (B1MS, B2S); larger Burstable + GP/MO use Standard_ prefix.
| SKU | armSkuName |
|---|---|
| Burstable B1ms | B1MS |
| Burstable B2s | B2S |
| Burstable B2ms | Standard_B2ms |
| General Purpose D2ds_v5 | Standard_D2ds_v5 |
Storage: Query separately — meterName eq 'Storage Data Stored' and productName containing Flexible Server Storage. Unit: 1 GiB/Month. Default 32 GiB included at ~$0.115/GiB/mo.
Monthly (compute): retailPrice × 730
Monthly (storage): storageRate × storageSizeGB
Total: compute + storage (e.g., B1ms + 32 GiB ≈ $12.41 + $3.68 = ~$16.09)
Functions
Consumption plan: Not in API. Free: 1M executions + 400K GB-seconds/month.
Flex/Premium — filter: serviceName eq 'Functions' and armRegionName eq '{region}' and priceType eq 'Consumption' and isPrimaryMeterRegion eq true
- Flex:
On Demand Execution Time(1 GB Second),On Demand Total Executions(10),Always Ready Baseline - Premium:
Premium vCPU Duration(1 Hour),Premium Memory Duration(1 GiB Hour). Monthly:vCPU_rate × 730 + memory_rate × GiB × 730
Static Web Apps
Not in the Retail Prices API. Fixed pricing — query azure.microsoft.com/pricing/details/app-service/static:
- Standard tier (floor — Free is never selected): Flat monthly per app, unlimited bandwidth, 5 custom domains, SLA, private endpoints
Log Analytics / Application Insights
Filter:
serviceName eq 'Azure Monitor' and armRegionName eq '{region}' and priceType eq 'Consumption' and isPrimaryMeterRegion eq true
Key meters:
Platform Logs Data Processed(unit: 1 GB)- Log Analytics ingestion — match
meterNamecontainingData Ingestion
Free grant: First 5 GB/month of Log Analytics data ingestion.
Monthly: retailPrice × estimatedGB (subtract 5 GB free grant).