635a130f0b
Build and Push Docker Images / detect-changes (push) Successful in 11s
Build and Push Docker Images / build-auth-api (push) Successful in 1m0s
Build and Push Docker Images / build-employee-api (push) Successful in 1m2s
Build and Push Docker Images / build-transit-api (push) Successful in 1m1s
Build and Push Docker Images / build-error-log-api (push) Successful in 1m5s
Build and Push Docker Images / build-admin-ui (push) Successful in 1m13s
Build and Push Docker Images / build-monitoring-ui (push) Successful in 1m15s
Build and Push Docker Images / deploy-test-node (push) Successful in 3s
### 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
194 lines
8.4 KiB
Markdown
194 lines
8.4 KiB
Markdown
<!-- azure-cor-disclaimer -->
|
|
> **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.
|
|
|
|
# Bicep Patterns — Data Service Modules
|
|
|
|
Bicep module templates for database and cache services. Read when the prepare plan includes PostgreSQL, MySQL, or Redis.
|
|
|
|
For core patterns (file structure, skeleton, naming, tagging), see [bicep-patterns.md](bicep-patterns.md). For security defaults, see [bicep-patterns-security.md](bicep-patterns-security.md).
|
|
|
|
## PostgreSQL Flexible Server Module — Entra-Only
|
|
|
|
> ⛔ **Password authentication is disabled.** No `administratorLogin` / `administratorLoginPassword`. The deploying principal is set as the Entra admin so migrations/seeding run token-based; the app's managed identity is granted a DB role as a post-deploy data-plane step (see [database-post-deploy.md](../../deploy/references/database-post-deploy.md)).
|
|
|
|
```bicep
|
|
param pgName string
|
|
param location string
|
|
param tags object
|
|
|
|
// Entra admin = the deploying principal (so migrations can run token-based). No password params.
|
|
param entraAdminObjectId string
|
|
param entraAdminName string
|
|
@allowed(['User', 'Group', 'ServicePrincipal'])
|
|
param entraAdminType string = 'User'
|
|
|
|
param allowedExtensions string = 'uuid-ossp,pgcrypto,pg_trgm'
|
|
|
|
resource pg 'Microsoft.DBforPostgreSQL/flexibleServers@2024-08-01' = {
|
|
name: pgName
|
|
location: location
|
|
tags: tags
|
|
sku: { name: 'Standard_B1ms', tier: 'Burstable' }
|
|
properties: {
|
|
version: '16' // ⛔ use prepare-plan.json.services[].version (capabilities-verified) — do not guess
|
|
// ⛔ Entra-only: no password auth, no administratorLogin/Password.
|
|
authConfig: {
|
|
activeDirectoryAuth: 'Enabled'
|
|
passwordAuth: 'Disabled'
|
|
tenantId: subscription().tenantId
|
|
}
|
|
storage: { storageSizeGB: 32 }
|
|
}
|
|
}
|
|
|
|
// Entra administrator (deploying principal) — required for token-based admin + migrations.
|
|
resource pgAdmin 'Microsoft.DBforPostgreSQL/flexibleServers/administrators@2024-08-01' = {
|
|
parent: pg
|
|
name: entraAdminObjectId
|
|
properties: {
|
|
principalType: entraAdminType
|
|
principalName: entraAdminName
|
|
tenantId: subscription().tenantId
|
|
}
|
|
}
|
|
|
|
// 0.0.0.0 = all Azure services (intentional) — broad access consented at the Scaffold Gate.
|
|
resource pgFirewall 'Microsoft.DBforPostgreSQL/flexibleServers/firewallRules@2024-08-01' = {
|
|
parent: pg
|
|
name: 'AllowAllAzureServicesAndResourcesWithinAzureIps'
|
|
properties: { startIpAddress: '0.0.0.0', endIpAddress: '0.0.0.0' }
|
|
}
|
|
|
|
// Allow PG extensions (uuid-ossp, pgcrypto, pg_trgm)
|
|
resource pgExtensions 'Microsoft.DBforPostgreSQL/flexibleServers/configurations@2024-08-01' = {
|
|
parent: pg
|
|
name: 'azure.extensions'
|
|
properties: { value: allowedExtensions, source: 'user-override' }
|
|
}
|
|
```
|
|
|
|
Wire connection **parameters** (host, db name, MI username, `sslmode=require`) as plain app settings — NOT a Key Vault secret. The driver fetches an Entra access token at runtime as the password. The app's managed identity is granted a DB role post-deploy via `pgaadauth_create_principal` (see [database-post-deploy.md](../../deploy/references/database-post-deploy.md) § Grant the app managed identity a DB role).
|
|
|
|
## MySQL Flexible Server Module — Entra-Only
|
|
|
|
> ⛔ **Password authentication is disabled.** No `administratorLogin` / `administratorLoginPassword`. The deploying principal is the Entra admin; the app's MI is mapped as an AAD login post-deploy.
|
|
|
|
> ⛔ **MySQL Entra admin REQUIRES a user-assigned managed identity (UAMI).** Unlike PostgreSQL, `Microsoft.DBforMySQL/flexibleServers/administrators` will not deploy without a UAMI: the `identityResourceId` property is mandatory (the portal and `az mysql flexible-server ad-admin create --identity` both require it), and the parent server must carry that UAMI in its `identity` block. `identityResourceId: null` fails to deploy. The UAMI is what the server uses to read Microsoft Entra — grant it the **Directory Readers** role (or `User.Read.All` / `GroupMember.Read.All` / `Application.Read.All` app permissions) in Entra ID; emit a `postDeployRecommendation` for that grant since it cannot be assigned from ARM.
|
|
|
|
```bicep
|
|
param mysqlName string
|
|
param location string
|
|
param tags object
|
|
param appDbName string
|
|
|
|
// Entra admin = the deploying principal. No password params.
|
|
param entraAdminObjectId string
|
|
param entraAdminName string
|
|
|
|
// UAMI required for MySQL Entra auth — the server uses it to read Entra.
|
|
resource mysqlAadIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
|
|
name: '${mysqlName}-aad-id'
|
|
location: location
|
|
tags: tags
|
|
}
|
|
|
|
resource mysql 'Microsoft.DBforMySQL/flexibleServers@2023-12-30' = {
|
|
name: mysqlName
|
|
location: location
|
|
tags: tags
|
|
sku: { name: 'Standard_B1ms', tier: 'Burstable' }
|
|
identity: {
|
|
type: 'UserAssigned'
|
|
userAssignedIdentities: {
|
|
'${mysqlAadIdentity.id}': {}
|
|
}
|
|
}
|
|
properties: {
|
|
version: '8.0.21' // ⛔ use prepare-plan.json.services[].version (capabilities-verified) — major-only '8.0' is rejected by ARM
|
|
storage: { storageSizeGB: 32 }
|
|
}
|
|
}
|
|
|
|
// Entra administrator (deploying principal) — enables token-based admin + migrations.
|
|
resource mysqlAdmin 'Microsoft.DBforMySQL/flexibleServers/administrators@2023-12-30' = {
|
|
parent: mysql
|
|
name: 'ActiveDirectory'
|
|
properties: {
|
|
administratorType: 'ActiveDirectory'
|
|
login: entraAdminName
|
|
sid: entraAdminObjectId
|
|
tenantId: subscription().tenantId
|
|
identityResourceId: mysqlAadIdentity.id // ⛔ MANDATORY — MySQL AAD admin will not deploy without a UAMI
|
|
}
|
|
}
|
|
|
|
// Enforce Entra-only auth (disable native password auth)
|
|
resource mysqlAadOnly 'Microsoft.DBforMySQL/flexibleServers/configurations@2023-12-30' = {
|
|
parent: mysql
|
|
name: 'aad_auth_only'
|
|
properties: { value: 'ON', source: 'user-override' }
|
|
dependsOn: [ mysqlAdmin ]
|
|
}
|
|
|
|
// 0.0.0.0 = all Azure services (intentional) — broad access consented at the Scaffold Gate.
|
|
resource mysqlFirewall 'Microsoft.DBforMySQL/flexibleServers/firewallRules@2023-12-30' = {
|
|
parent: mysql
|
|
name: 'AllowAllAzureServicesAndResourcesWithinAzureIps'
|
|
properties: { startIpAddress: '0.0.0.0', endIpAddress: '0.0.0.0' }
|
|
}
|
|
|
|
// Enforce TLS
|
|
resource mysqlTls 'Microsoft.DBforMySQL/flexibleServers/configurations@2023-12-30' = {
|
|
parent: mysql
|
|
name: 'require_secure_transport'
|
|
properties: { value: 'ON', source: 'user-override' }
|
|
}
|
|
|
|
// App database from compose (e.g. MYSQLDB_DATABASE) — emit so it exists before first boot. Omit if only the default DB is used.
|
|
resource mysqlDb 'Microsoft.DBforMySQL/flexibleServers/databases@2023-12-30' = {
|
|
parent: mysql
|
|
name: appDbName
|
|
}
|
|
```
|
|
|
|
Wire connection **parameters** as plain app settings (host, db name, MI username, SSL required) — NOT a Key Vault secret. The driver fetches an Entra token at runtime. The app's MI is mapped as an AAD login post-deploy (see [database-post-deploy.md](../../deploy/references/database-post-deploy.md)).
|
|
|
|
## Redis Cache Module (Entra-Only)
|
|
|
|
> ⛔ **Access-key authentication is disabled** (`disableAccessKeyAuthentication: true`). The app's managed identity is granted data access via an access-policy assignment. Do NOT store a Redis access key in Key Vault. If the app's Redis client library cannot present an Entra token, surface it as a `FLAGGED` finding rather than re-enabling keys.
|
|
|
|
```bicep
|
|
param redisName string
|
|
param location string
|
|
param tags object
|
|
param appPrincipalId string // the app compute MI objectId
|
|
|
|
resource redis 'Microsoft.Cache/redis@2024-03-01' = {
|
|
name: redisName
|
|
location: location
|
|
tags: tags
|
|
properties: {
|
|
sku: { name: 'Basic', family: 'C', capacity: 0 }
|
|
enableNonSslPort: false
|
|
minimumTlsVersion: '1.2'
|
|
disableAccessKeyAuthentication: true // ⛔ Entra-only
|
|
redisConfiguration: {
|
|
'aad-enabled': 'true'
|
|
}
|
|
}
|
|
}
|
|
|
|
// Data-plane access for the app MI (Entra) — no keys.
|
|
resource redisAccess 'Microsoft.Cache/redis/accessPolicyAssignments@2024-03-01' = {
|
|
parent: redis
|
|
name: guid(redis.id, appPrincipalId, 'Data Owner')
|
|
properties: {
|
|
accessPolicyName: 'Data Owner'
|
|
objectId: appPrincipalId
|
|
objectIdAlias: appPrincipalId
|
|
}
|
|
}
|
|
```
|
|
|
|
Wire `redis.properties.hostName` (+ MI object id as the username) as plain app settings. The client obtains an Entra token at runtime — no key in Key Vault.
|