npm package: @phila/cli
Description: CLI tool for City of Philadelphia AWS infrastructure
Latest version: 0.4.9

# @phila/cli

CLI tool for City of Philadelphia AWS infrastructure management.

## Installation

```bash
npm install -g @phila/cli
# or
pnpm add -g @phila/cli
```

## Usage

The CLI is available as the `city` command:

```bash
city [command]
```

## Commands

**`ENVIRONMENT` during package builds**: For `city deploy`, `city validate`, and `city ship`, each **package build** subprocess (frontend and Lambda npm/pnpm/yarn scripts) receives the environment variable `ENVIRONMENT` set to `dev`, `test`, or `prod`, matching the command’s target environment. Use it in build configs or backend compile steps to vary output per target. **`city deploy --https`** skips local code builds, so this variable is not applied on that path.

### `city init [appName]`

Create a new Philadelphia infrastructure project from a template. If `appName` is not provided, you will be prompted for it.

```bash
# Interactive mode
city init

# With appName argument
city init my-app
```

This command will:
- Prompt for package manager (npm, pnpm, or yarn; default: npm)
- Guide you through template selection
- Prompt for project configuration
- Scaffold the project structure
- Set up initial AWS CDK infrastructure

### `city deploy [environment]`

Deploy the project to AWS. Supports `dev`, `test`, and `prod` environments.

```bash
city deploy dev
city deploy prod
```

Options:
- `--https` - Provision an ACM certificate and enable HTTPS (see below)

#### Custom domains and per-environment subdomains

When you configure a wildcard domain during `city init`, subdomains are generated automatically for each environment. Given a wildcard of `*.my-app.phila.gov`:

| Environment | Frontend | API |
|-------------|----------|-----|
| dev | `dev.my-app.phila.gov` | `dev-api.my-app.phila.gov` |
| test | `test.my-app.phila.gov` | `test-api.my-app.phila.gov` |
| prod | `my-app.phila.gov` | `api.my-app.phila.gov` |

These values are written into `city.config.json` under each environment block (e.g., `devFrontendDomain`, `prodApiDomain`). You can change them to any subdomain you prefer — but they **must remain subdomains of the wildcard domain**. The ACM certificate covers `*.my-app.phila.gov` and the apex `my-app.phila.gov`; any domain outside that pattern will not be covered and HTTPS will fail.

```jsonc
// city.config.json — safe to customize, must stay under the wildcard
{
  "environments": {
    "dev": {
      "wildcardDomain": "*.my-app.phila.gov",
      "frontendDomain": "dev.my-app.phila.gov",   // ✓ covered by wildcard
      "apiDomain":      "dev-api.my-app.phila.gov" // ✓ covered by wildcard
    }
  }
}
```

All environments share the same wildcard domain and Route53 hosted zone, so a single NS delegation covers every environment.

#### HTTPS and certificate provisioning

Projects that configure a `wildcardDomain` in `city.config.json` follow a **two-phase deployment** process. This is required because AWS Certificate Manager (ACM) validates certificates via DNS, and the Route53 hosted zone NS records are not known until after the first deploy.

**Phase 1 — initial deploy (no flag)**

Run a normal deploy. This creates the Route53 hosted zone and outputs the NS records:

```
Outputs:
my-app-dev.DomainSetupNameServers = ns-856.awsdns-43.net, ns-102.awsdns-12.com, ...
```

Take these NS records to your domain registrar and add them as NS records for the domain. Then wait for DNS propagation (verify with `dig NS yourdomain.com`).

**Phase 2 — enable HTTPS**

Once NS delegation is publicly resolving, run:

```bash
city deploy dev --https
```

This will:
1. Confirm that NS records have been delegated
2. Skip all code builds (infrastructure-only update)
3. Create the ACM wildcard certificate (DNS validation completes quickly since NS is delegated)
4. Update CloudFront and the ALB to use HTTPS with the new certificate

> **Why two phases?** CloudFormation blocks indefinitely on `AWS::CertificateManager::Certificate` until DNS validation succeeds. If the hosted zone NS records have not been delegated yet, the certificate can never validate and the deployment hangs forever. Separating the certificate creation into a second deploy — after delegation is confirmed — prevents this.

### `city validate [environment]`

Run install, build, and CDK synth to verify the project is ready for deployment. Optionally specify an environment (`dev`, `test`, or `prod`) to synth against; if omitted, the first configured environment in `city.config.json` is used.

```bash
city validate           # Use first configured environment
city validate dev
city validate test
city validate prod
```

### `city ship [environment]`

Ship code to AWS without full infrastructure deployment. Useful for quick code updates.

```bash
city ship dev --lambda api
city ship dev --web
city ship dev --ecs       # Local Docker build
city ship dev --ecs-s3    # Remote S3/CodeBuild (recommended for Mac ARM)
city ship dev --all       # Ship all components
```

For ECS-based templates, the CLI prompts for a deployment method (local or S3) after environment selection.

Options:
- `--lambda [name]` - Ship Lambda function (optionally specify name)
- `--web` - Ship frontend to S3/CloudFront
- `--ecs` - Ship ECS container (local Docker build)
- `--ecs-s3` - Ship ECS container (remote S3/CodeBuild build)
- `--all` - Ship all components (default when no flags specified)

**Package manager**: Uses `packageManager` from `city.config.json` when set (as chosen during `city init`); otherwise detects npm, pnpm, or yarn from lock files.

**Frontend Configuration**:
- Configure custom build command: `city config set frontendBuildCommand <script>` (default: `build`)
- Configure custom dist directory: `city config set frontendDistDir <path>` (default: `dist`)

Example for Nuxt projects:
```bash
city config set frontendBuildCommand generate
city config set frontendDistDir .output/public
```

### `city destroy [environment]`

Open CloudFormation console to destroy a stack.

```bash
city destroy dev
```

### `city config`

Manage project configuration.

```bash
city config show              # Display current configuration
city config get <key>         # Get a specific configuration value
city config set <key> <value> # Set a configuration value
```

### `city map`

Navigate and query the codebase.

```bash
city map show                    # Show codebase map statistics
city map where <query>           # Find files by keyword
city map where --export <name>   # Search by export name
city map where --layer <layer>   # Filter by layer (l1, l2, l3, cli, core, etc.)
city map update                  # Regenerate codebase.json
city map check                   # Validate codebase.json
```

### `city templates`

List available project templates.

```bash
city templates        # List all templates in tree format
city templates simple  # List all templates in simple format
```

## Project Structure

When you run `city init`, it creates a project with:

- `cdk/` - AWS CDK infrastructure code
- `apps/` - Application code (Lambda functions, etc.)
- `city.config.json` - Project configuration
- `package.json` - Dependencies and scripts

## Configuration

Project configuration is stored in `city.config.json`. Common settings include:

- `packageManager` - npm, pnpm, or yarn (chosen at init, default npm; used by validate, deploy, ship)
- AWS profile and environment settings
- Application name and resource naming conventions
- Frontend build configuration:
  - `frontendBuildCommand` - Custom npm script for builds (default: `build`)
  - `frontendDistDir` - Custom distribution directory (default: `dist`)
- `ENVIRONMENT` - Not stored in the file; set automatically by `city deploy`, `city validate`, and `city ship` in build subprocesses (`dev` / `test` / `prod`). See the note at [Commands](#commands).

Use `city config set <key> <value>` to configure these settings.

## Requirements

The CLI checks for required dependencies on startup:
- Node.js (>=18.0.0)
- npm, pnpm, or yarn (automatically detected from lock files)
- AWS CLI
- AWS CDK CLI

Missing dependencies will be detected and installation instructions provided.

**Package manager**: The CLI uses `packageManager` from `city.config.json` when present (set at init). If not set, it detects npm, pnpm, or yarn from lock files and uses the appropriate commands for validate, deploy, and ship.

## Development

```bash
# Build
pnpm build

# Run tests
pnpm test

# Lint
pnpm lint
```

## License

Part of the City of Philadelphia AWS Infrastructure Library.