Files
open-design/deploy/azure/app-service.bicep
f1a0b60c6c chore: unify product name display to OpenDesign repo-wide (#6998)
* chore: unify product name display to OpenDesign repo-wide

Rename the user-facing product name from "Open Design" to "OpenDesign"
across documentation, web/desktop UI strings, i18n locales, prompts,
plugin/skill/design-system content, changelogs, and specs, matching the
landing-page rename already in flight.

Deliberately excluded so installed-app identity stays untouched:
- packages/release PRODUCT_NAME and everything derived from it
  (app bundle names, installer/registry identity, updater feeds)
- tools/pack, tools/release, apps/packaged, landing page (PR #6983)
- mocks/ recorded traces and LICENSE
- test fixtures and comments that encode real on-disk install paths
  (Open Design.app, Program Files\Open Design, AppData paths)

Validated with pnpm guard, pnpm typecheck, and targeted web/desktop/host
test runs over the renamed strings.

* fix(web): keep two-letter author monogram for CamelCase brand names

authorInitials split words on whitespace only, so the renamed single-token
author name "OpenDesign" produced a one-letter monogram. Treat lower-to-upper
CamelCase boundaries as word breaks so the avatar fallback stays "OD".

* fix(release): restore spaced Windows source artifact names in win.ps1

tools/pack still derives builder outputs from the unchanged PRODUCT_NAME
("Open Design"), so the asset script must look for the spaced filenames.
Matches the mac/mac-intel/linux asset scripts, which were already kept on
the original names.

---------

Co-authored-by: Joey <236967869+joeylee12629-star@users.noreply.github.com>
2026-08-18 07:09:45 +00:00

137 lines
4.3 KiB
Bicep

// OpenDesign on Azure App Service for Containers (evaluation deployment).
//
// Single-instance Linux web app behind Azure's managed HTTPS. State lives on
// the container's local disk, which is EPHEMERAL — it is reset on restart,
// redeploy, or scale. This lane is for evaluation and demos, not durable data.
//
// Why no persistent volume: OpenDesign stores SQLite under OD_DATA_DIR, and
// SQLite needs real file locking. App Service's persistent storage is backed
// by Azure Files (SMB), where SQLite WAL/locking is unsupported and corrupts.
// So we deliberately keep the data dir on the container's local filesystem.
@description('Base name for the deployment. A globally-unique suffix is appended to the web app.')
param name string = 'open-design'
@description('Azure region. Defaults to the resource group location.')
param location string = resourceGroup().location
@description('Container image to run. Pin to a digest (image@sha256:...) for production.')
param image string = 'docker.io/vanjayak/open-design:latest'
@description('App Service plan SKU. B1 is the smallest tier that supports Always On and health checks.')
param appServicePlanSku string = 'B1'
@secure()
@minLength(32)
@description('Required API token guarding the daemon. Generate one with: openssl rand -hex 32')
param apiToken string
@description('Node.js heap cap passed to the container via NODE_OPTIONS.')
param nodeOptions string = '--max-old-space-size=192'
@description('Extra browser origins allowed to call /api, comma-separated. The App Service default hostname is always allowed.')
param extraAllowedOrigins string = ''
// Runtime invariants of the image, not user-facing knobs.
var containerPort = 7456
var dataDir = '/app/.od'
// Default App Service hostname is deterministic, so we derive the public URL up
// front and avoid a circular reference on the site's own appSettings.
var webAppName = '${name}-${uniqueString(resourceGroup().id)}'
var publicBaseUrl = 'https://${webAppName}.azurewebsites.net'
var allowedOrigins = empty(extraAllowedOrigins) ? publicBaseUrl : '${publicBaseUrl},${extraAllowedOrigins}'
resource plan 'Microsoft.Web/serverfarms@2023-12-01' = {
name: '${name}-plan'
location: location
kind: 'linux'
sku: {
name: appServicePlanSku
capacity: 1
}
properties: {
reserved: true // required for Linux plans
}
}
resource webApp 'Microsoft.Web/sites@2023-12-01' = {
name: webAppName
location: location
kind: 'app,linux,container'
properties: {
serverFarmId: plan.id
httpsOnly: true
siteConfig: {
linuxFxVersion: 'DOCKER|${image}'
alwaysOn: true
ftpsState: 'Disabled'
minTlsVersion: '1.2'
http20Enabled: true
healthCheckPath: '/api/health'
numberOfWorkers: 1 // SQLite is single-writer: keep one worker.
appSettings: [
{
name: 'WEBSITES_PORT' // route inbound traffic to the container port
value: '${containerPort}'
}
{
// Keep the data dir on the container's local disk (real file
// locking). Azure Files-backed storage corrupts SQLite.
name: 'WEBSITES_ENABLE_APP_SERVICE_STORAGE'
value: 'false'
}
{
name: 'WEBSITES_CONTAINER_START_TIME_LIMIT'
value: '230'
}
{
name: 'OD_BIND_HOST'
value: '0.0.0.0'
}
{
name: 'OD_PORT'
value: '${containerPort}'
}
{
name: 'OD_WEB_PORT'
value: '${containerPort}'
}
{
name: 'OD_DATA_DIR'
value: dataDir
}
{
name: 'OD_PUBLIC_BASE_URL'
value: publicBaseUrl
}
{
name: 'OD_ALLOWED_ORIGINS'
value: allowedOrigins
}
{
name: 'OD_API_TOKEN'
value: apiToken
}
{
name: 'NODE_ENV'
value: 'production'
}
{
name: 'NODE_OPTIONS'
value: nodeOptions
}
]
}
}
}
@description('Public HTTPS URL of the deployed app.')
output appUrl string = publicBaseUrl
@description('Health endpoint to poll after deployment.')
output healthUrl string = '${publicBaseUrl}/api/health'
@description('Generated web app name (includes the unique suffix).')
output webAppName string = webAppName