# Serverless Maven Plugin - Complete AI Assistant Guide

This guide provides comprehensive information for AI coding assistants to help developers create and maintain serverless configurations using the Serverless Maven Plugin.

## Quick Reference

- **Plugin GroupId**: `uk.co.taylor-made-software`
- **Plugin ArtifactId**: `plugin-maven`
- **Version**: `1.0.1-SNAPSHOT`
- **Config File**: `src/main/serverless/config.json`
- **Providers**: aws, azure, gcp
- **Schema**: https://www.taylor-made-software.co.uk/schema/serverless-config.schema.json

## Plugin Integration

### Step 1: Install the Plugin

First, build and install the plugin to your local Maven repository:

```bash
cd serverless-maven-plugin
mvn clean install
```

This installs the plugin to `~/.m2/repository/uk/co/taylor-made-software/plugin-maven/1.0.1-SNAPSHOT/`

### Step 2: Add Plugin to Your Project

Add the plugin to your project's `pom.xml`:

```xml
<build>
    <plugins>
        <plugin>
            <groupId>uk.co.taylor-made-software</groupId>
            <artifactId>plugin-maven</artifactId>
            <version>1.0.1-SNAPSHOT</version>
        </plugin>
    </plugins>
</build>
```

The plugin automatically resolves `src/main/serverless/config.json`. To specify custom paths:

```xml
<configuration>
    <configFiles>
        <configFile>${project.basedir}/src/main/serverless/config.json</configFile>
    </configFiles>
</configuration>
```

**IMPORTANT**: The parameter is `configFiles` (plural, a `<List<File>>`), not `configFile` (singular).

### Step 3: Create Configuration File

Create `src/main/serverless/config.json` with your serverless configuration (see examples below).

### Step 4: Run Maven Goals

```bash
mvn serverless:validate  # Validate configuration
mvn serverless:plan      # Preview changes
mvn serverless:deploy    # Deploy infrastructure
mvn serverless:verify    # Health check deployed resources
mvn serverless:undeploy  # Tear down infrastructure
```

## Maven Goals

- **validate**: Validates the configuration file against the schema and business rules
- **plan**: Generates a deployment plan showing what resources will be created/updated
- **deploy**: Provisions cloud resources according to the configuration
- **verify**: Runs health checks on deployed resources
- **undeploy**: Tears down all provisioned infrastructure

## Root Configuration Structure

```json
{
  "name": "Application Name",
  "description": "Optional description",
  "application": "com.example.myapp",
  "provider": "aws",
  "variables": {
    "stage": "dev",
    "version": "1.0.0"
  },
  "regions": [
    {
      "region": "eu-west-2",
      "items": [
        // components here
      ]
    }
  ]
}
```

### Root Fields

- **name** (required, string): Human-readable application name
- **description** (optional, string): Application description
- **application** (required, string): Reverse-domain notation identifier (e.g. `com.example.myapp`)
- **provider** (required, string): Cloud provider - `aws`, `azure`, or `gcp`
- **variables** (optional, object): Key-value pairs for variable substitution. Use `${variableName}` in any string field. Substitution works recursively in all string values including inside lists and nested maps in providerSettings (e.g., `corsOrigins: ["https://admin.${rootDomain}"]` or route objects with `${env}-handler` function names).
- **regions** (required, array): List of region configurations

### Region Configuration

- **region** (required, string): Region identifier (e.g. `us-east-1`, `eu-west-2`) or `"global"` for global resources
- **items** (required, array): Components to deploy in this region (can be component objects or file paths)

## Component Types

All components share this base structure:

```json
{
  "type": "component-type",
  "name": "unique-name",
  "providerSettings": {
    // component-specific configuration
  },
  "links": [
    // explicit component links
  ]
}
```

The supported `type` values are: `website`, `storage`, `api-gateway`, `function` (or its
equivalent alias `functions`), `database`, `authentication`, `email`, `sms`, `event-bus`, and
`waf`. Types are matched case-insensitively.

**Links are declared per-component**, inside each component's own `links` array — there is no
top-level `links` array (a root-level `links` block is ignored by the parser). Each link object
uses `sourceComponent`, `targetComponent`, and `linkType` (not `source`/`target`/`type`), and
`linkType` is case-sensitive.

### 1. Website Component

Static website with CDN distribution. Automatically provisions its own storage bucket (origin bucket).
Supports optional `uploads` for deploying initial static content (HTML/CSS/JS) to the origin bucket.

```json
{
  "type": "website",
  "name": "frontend",
  "providerSettings": {
    "domain": "www.example.com",
    "uploads": [
      {
        "artifact": "com.example:frontend-dist:${version}:dist:zip",
        "destination": "",
        "unpack": true
      }
    ]
  },
  "links": [
    {
      "sourceComponent": "frontend",
      "targetComponent": "main-api",
      "linkType": "WEBSITE_TO_API_GATEWAY"
    }
  ]
}
```

**Required Fields:**
- `domain` (string): Full hostname to serve from

**Optional Fields:**
- `uploads` (array): Maven artifacts to upload to the origin bucket at deploy time. Uses the same format as Storage component uploads:
  - `artifact` (required, string): Maven coordinate in extended format (see Storage component for details)
  - `destination` (required, string): Target path in the origin bucket (use `""` for root)
  - `unpack` (optional, boolean): Extract archive contents instead of uploading file
  - `classifier` (optional, string): Maven classifier (e.g. `dist`, `sources`)
  - `extension` (optional, string): Override file extension (defaults to `jar`)

**Valid Links:**
- WEBSITE_TO_API_GATEWAY
- WEBSITE_TO_STORAGE (requires `path` property, e.g. `"/assets"`)

**Region**: Any specific region (not global)

**Note:** Uploads run after the CloudFront distribution is created and the bucket policy is configured. The `${version}` interpolation works the same way as in Storage component uploads.

**Path-Based Storage Routing:**

Use `WEBSITE_TO_STORAGE` links with a `path` property to serve content from other storage buckets at specific URL paths:

```json
{
  "sourceComponent": "frontend",
  "targetComponent": "asset-store",
  "linkType": "WEBSITE_TO_STORAGE",
  "path": "/assets"
}
```

This adds the target bucket as a CloudFront origin with a cache behavior for `/assets/*`. The `path` must start with `/`. Multiple storage links are supported.

**Deployment Behavior:**
- CloudFront compression is always enabled on the default cache behavior
- Uses the AWS managed CachingOptimized cache policy (ID: 658327ea-f89d-4fab-a63d-7e88639e58f6) instead of legacy forwardedValues
- `errorDocument` (defaults to "index.html") configures custom error responses for 403/404 that respond with HTTP 200, enabling SPA client-side routing
- On redeploy (distribution already exists), the deployer updates the existing distribution with the latest configuration (compress, cache policy, error responses) instead of just returning the existing ARN
- WEBSITE_TO_STORAGE path links add additional origins and cache behaviors for path-based routing

**Access Gate (edge HTTP Basic authentication):**

An optional `accessGate` provider setting places a username/password prompt in front of the entire site at the CloudFront edge. When enabled, every viewer request must carry a valid `Authorization: Basic` header or CloudFront returns `401 Unauthorized` with a `WWW-Authenticate: Basic realm="..."` challenge (so browsers prompt for login). It is implemented as a CloudFront Function (`cloudfront-js-2.0`) associated with the distribution's default cache behavior on the `viewer-request` event.

```json
{
  "type": "website",
  "name": "marketing-site",
  "providerSettings": {
    "domain": "www.example.com",
    "accessGate": {
      "enabled": "${siteGateEnabled}",
      "credentialsSecret": "example/site-gate-credentials",
      "realm": "Example Staging"
    }
  }
}
```

`accessGate` fields:
- `enabled` (optional) — boolean, or the string `"true"`/`"false"` so it can be driven per environment via `${variable}` substitution. Absent means disabled.
- `credentialsSecret` (required when enabled) — the AWS Secrets Manager secret name or ARN that holds the credentials. **Credentials are never placed inline in configuration.**
- `realm` (optional) — the HTTP Basic realm shown in the browser prompt; defaults to `Restricted`.

Behavior and constraints:
- Credentials are read from Secrets Manager **at deploy time** only. The plugin computes the base64 `Basic` tokens and bakes those tokens (never the raw passwords) into the generated edge function. CloudFront Functions cannot make network calls at request time, so the accepted credential set is fixed at deploy; **rotate the secret and redeploy** the website to change credentials.
- The secret payload may be a JSON array of `{ "username", "password" }` objects, a JSON object mapping `username` → `password`, or newline-separated `username:password` lines (blank lines and `#` comments are ignored). Multiple credentials are supported; duplicates are de-duplicated in the allow-list.
- The function is named `<resourceName>-site-gate`; it is created or updated (idempotent), published, and associated on deploy.
- Disabling the gate (`enabled: false` or removing `accessGate`) and redeploying removes the function association (the association quantity becomes 0). `undeploy` deletes the CloudFront Function after the distribution is removed.
- The gate coexists with a WAF `WAF_TO_WEBSITE` association: only the default cache behavior's `functionAssociations` is mutated, so the distribution's `webACLId` is preserved on update.
- Deploy identity permissions required: `secretsmanager:GetSecretValue` and `cloudfront:CreateFunction`, `cloudfront:UpdateFunction`, `cloudfront:PublishFunction`, `cloudfront:DescribeFunction`, `cloudfront:DeleteFunction`.

Validation (`WebsiteRule`): `accessGate` must be an object; `enabled` must be a boolean or `"true"`/`"false"` string; `credentialsSecret` must be a non-blank string and is required when the gate is enabled; `realm`, if present, must be a non-blank string.

**Edge Functions (viewer-request):**

An optional `edgeFunctions` provider setting associates a user-provided CloudFront Function with the distribution's default cache behavior on the `viewer-request` event. The function runs on every viewer request at the edge and can inspect or rewrite the request (for example, an edge language router that rewrites a bare `/` to a localized `/{lang}/…` document based on a cookie or `Accept-Language`). It is a `cloudfront-js-2.0` function.

```json
{
  "type": "website",
  "name": "marketing-site",
  "providerSettings": {
    "domain": "www.example.com",
    "edgeFunctions": [
      {
        "event": "viewer-request",
        "runtime": "cloudfront-function",
        "source": "edge/language-router.js",
        "variables": { "supportedLanguages": "['en','fr','de']" }
      }
    ]
  }
}
```

`edgeFunctions` fields (per entry):
- `event` (required) — the CloudFront event; only `"viewer-request"` is currently supported.
- `runtime` (optional) — the runtime discriminator; only `"cloudfront-function"` is currently supported (the default). Lambda@Edge is not currently supported.
- `source` (required) — a project-relative path to the function's JavaScript source, resolved against `src/main/serverless` (the config directory). Must stay within that directory; absolute paths and `..` traversal are rejected by validation (and defensively at deploy time).
- `variables` (optional) — a map of `${key}` → value substitutions applied to the source at deploy time (string values). Unknown `${...}` placeholders are left untouched, so sources may also be fully self-contained.

Behavior and constraints:
- The source is read from disk **at deploy time**, `${...}` placeholders are substituted, and the code is published as a CloudFront Function named `{resourceName}-edge-viewer-request`, then associated on `viewer-request`. Redeploying updates the function code in place; `undeploy` deletes the function after the distribution is removed.
- **Mutually exclusive with an enabled `accessGate`.** CloudFront allows only one function association per event type per cache behavior, and both features use `viewer-request`; validation fails if a website declares both. If you need both behaviors, fold the access check into your own edge function source.
- At most one `viewer-request` entry is allowed per website.
- The single viewer-request association coexists with a WAF `WAF_TO_WEBSITE` association: only `defaultCacheBehavior.functionAssociations` is mutated, so the distribution's `webACLId` is preserved on update.
- Deploy identity permissions required: `cloudfront:CreateFunction`, `cloudfront:UpdateFunction`, `cloudfront:PublishFunction`, `cloudfront:DescribeFunction`, `cloudfront:DeleteFunction`. No Secrets Manager access is needed for edge functions.

Validation (`WebsiteRule`): `edgeFunctions` must be an array; each entry an object with `event` equal to `"viewer-request"`, an optional `runtime` equal to `"cloudfront-function"`, and a required non-blank `source` that is a project-relative path (absolute paths and `..` traversal are rejected); at most one `viewer-request` entry; and a `viewer-request` edge function may not be combined with an enabled `accessGate`.

Implementation note: at deploy time `AwsWebsiteDeployer.resolveViewerRequestFunctionArn(...)` resolves the single viewer-request function — the access gate takes precedence if enabled, otherwise the edge function is provisioned via `AwsEdgeFunctionProvisioner` — and the resulting ARN is set as the one `FunctionAssociation` on the default cache behavior. The source root (`src/main/serverless`) is threaded from `DeployMojo` through `CloudProviderStrategyFactory` and `AwsCloudProviderStrategy` into the deployer.

### 2. Storage Component

Object storage bucket with optional Maven artifact uploads.

```json
{
  "type": "storage",
  "name": "deploy-artifacts",
  "providerSettings": {
    "uploads": [
      {
        "artifact": "com.example:myapp:${version}",
        "destination": "releases/myapp/",
        "unpack": true
      },
      {
        "artifact": "com.example:assets:1.0.0:static:zip",
        "destination": "static/",
        "unpack": true
      }
    ]
  },
  "links": []
}
```

**Optional Fields:**
- `uploads` (array): Maven artifacts to upload at deploy time
  - `artifact` (required, string): Maven coordinate in extended format (see below)
  - `destination` (required, string): Target path in bucket (must end with `/`)
  - `unpack` (optional, boolean): Extract archive contents instead of uploading file
  - `classifier` (optional, string): Maven classifier (e.g. `dist`, `sources`)
  - `extension` (optional, string): Override file extension (defaults to `jar`)

**Artifact Coordinate Format:**

The `artifact` field supports 3, 4, or 5 colon-separated parts:

| Format | Example |
|--------|---------|
| `groupId:artifactId:version` | `com.example:myapp:1.0.0` |
| `groupId:artifactId:version:classifier` | `com.example:myapp:1.0.0:sources` |
| `groupId:artifactId:version:classifier:extension` | `com.example:myapp:1.0.0:dist:zip` |

When the classifier or extension is specified inline in the coordinate string, it **takes precedence** over the separate `"classifier"` and `"extension"` map fields.

**`${version}` Interpolation:**

The special token `${version}` in the artifact coordinate is automatically replaced with the Maven project version (`${project.version}`) at deploy time. This is especially useful in multi-module projects where subprojects reference their own artifacts:

```json
{
  "artifact": "uk.co.taylormadesoftware.cms:serverless-cms:${version}",
  "destination": "releases/",
  "unpack": true
}
```

If the POM version is `1.0.1-SNAPSHOT`, the resolved artifact coordinate becomes `uk.co.taylormadesoftware.cms:serverless-cms:1.0.1-SNAPSHOT`.

**Note:** This `${version}` interpolation is separate from the config-level `variables` substitution. It is performed specifically on artifact coordinate strings during the deploy phase and always resolves to the Maven project version.

**Valid Links:** None (storage is referenced by other components)

**Region**: Any specific region (not global)

### 3. API Gateway Component

REST API with routes, authentication, and pre/post processing.

```json
{
  "type": "api-gateway",
  "name": "main-api",
  "providerSettings": {
    "domain": "api.example.com",
    "preProcessFunction": "request-validator",
    "postProcessFunction": "response-logger",
    "routes": [
      {
        "path": "/users",
        "method": "GET",
        "function": "user-handler",
        "auth": "user-auth"
      },
      {
        "path": "/public",
        "method": "GET",
        "function": "public-handler"
      }
    ]
  },
  "links": []
}
```

**Required Fields:**
- `domain` (string): Full hostname to serve from
- `routes` (array): API routes (at least one)
  - `path` (required, string): URL path (must start with `/`)
  - `method` (required, string): HTTP method (GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD)
  - `function` (required, string): Function name to invoke
  - `auth` (optional, string): Authentication component name for JWT validation

**Optional Fields:**
- `preProcessFunction` (string): Function to run before every request
- `postProcessFunction` (string): Function to run after every response
- `corsOrigins` (array of strings): Specific CORS origins. When set, CORS uses those specific origins with `allowCredentials: true`. When omitted, uses `*` without credentials (works for JWT auth via Authorization header). Required for cookie-based auth.

**Valid Links:** None (uses implicit references in routes)

**Important:** Function names in `routes`, `preProcessFunction`, and `postProcessFunction` are implicit references - do NOT add them to the `links` array.

**Deployment Behavior:**
- Routes and integrations are synced declaratively — the deployer fetches existing routes/integrations, reuses integrations by URI match, creates/updates routes, and deletes stale routes and orphaned integrations
- All API Gateway SDK calls are retried with exponential backoff (5 retries, 1s base delay) on 429 Too Many Requests or 5xx errors
- ConflictException on route creation is handled gracefully (falls back to update)
- Pagination is used when fetching routes and integrations (follows nextToken)

**Region**: Any specific region (not global)

#### WebSocket APIs

Set `protocol: "websocket"` (or `protocolType: "WEBSOCKET"`) to provision an AWS API Gateway WebSocket API instead of an HTTP API. This is the serverless fit for real-time features such as group chat.

```json
{
  "type": "api-gateway",
  "name": "chat-ws",
  "providerSettings": {
    "protocol": "websocket",
    "domain": "ws.example.com",
    "routeSelectionExpression": "$request.body.action",
    "routes": [
      { "routeKey": "$connect",    "function": "chat-connect" },
      { "routeKey": "$disconnect", "function": "chat-disconnect" },
      { "routeKey": "sendMessage", "function": "chat-send" }
    ]
  },
  "links": []
}
```

**WebSocket route fields:**
- `routeKey` (required, string, unique): `$connect`, `$disconnect`, `$default`, or a custom key (e.g. `sendMessage`). Replaces `method`/`path`.
- `function` (required, string): Function name to invoke. Must exist in the configuration.

**WebSocket behaviour:**
- `routeSelectionExpression` (optional): how API Gateway selects the route key from an incoming message. Defaults to `$request.body.action`.
- Route-level authorization is `NONE`. Authenticate/authorize inside the `$connect` handler (WebSocket auth happens at connection time). `auth`, JWT authorizers, and `preProcessFunction` are ignored for WebSocket APIs.
- Integrations are Lambda proxy (`AWS_PROXY`) with payload format version `1.0`.
- The API is deployed to the `$default` stage with auto-deploy enabled.
- CORS is not configured (WebSocket APIs do not support the HTTP CORS object).
- Each backing function's execution role is automatically granted `execute-api:ManageConnections`, scoped to the specific deployed WebSocket API (`arn:aws:execute-api:{region}:{accountId}:{apiId}/*/POST/@connections/*`), allowing it to post messages back to connected clients via the `@connections` API. The grant is applied at deploy time (once the real API id is known) as an inline policy on the `{function}-exec-role`; it is not a wildcard.
- Validation checks that every route has a non-blank, unique `routeKey` and that each `function` exists.

**Region**: Any specific region (not global)

### 4. Functions Component

Groups one or more serverless functions sharing the same deployment artifact.

```json
{
  "type": "functions",
  "name": "app-functions",
  "providerSettings": {
    "codeStorage": "deploy-artifacts",
    "codePath": "releases/app-functions/app-functions-1.0.0.jar",
    "functions": [
      {
        "name": "api-handler",
        "handler": "com.example.ApiHandler::handleRequest",
        "runtime": "java21",
        "memory": 512,
        "timeout": 30,
        "environment": {
          "STAGE": "dev"
        }
      },
      {
        "name": "event-processor",
        "handler": "com.example.EventProcessor::handleRequest",
        "runtime": "java21"
      }
    ]
  },
  "links": [
    {
      "sourceComponent": "app-functions",
      "targetComponent": "app-db",
      "linkType": "FUNCTION_TO_DATABASE"
    },
    {
      "sourceComponent": "app-functions",
      "targetComponent": "transactional-email",
      "linkType": "FUNCTION_TO_EMAIL"
    }
  ]
}
```

**Required Fields:**
- `codeStorage` (string): Storage component name containing the deployment artifact
- `codePath` (string): Path to the JAR/ZIP file within the storage bucket
- `functions` (array): List of function definitions (at least one)
  - `name` (required, string): Unique function name (used in api-gateway routes and event-bus subscriptions)
  - `handler` (optional, string): Entry point. Defaults are **runtime-aware**: managed runtimes default to `index.handler`; custom (`provided.*`) runtimes default to `bootstrap`. For a Rust/Go function you can omit `handler` entirely and it deploys with handler `bootstrap`.
  - `runtime` (optional, string, default `nodejs22.x`): Runtime identifier (e.g. `java21`, `java17`, `python3.11`, `nodejs22.x`, `rust`, `go`). `rust` and `go` (and `provided`) map to the AWS `provided.al2023` custom runtime — the handler defaults to `bootstrap` and you deploy a compiled binary; `provided.al2` is preserved. Both Lambda deploy paths (the multi-function strategy and the standalone deployer) map the runtime identically. When a function is created before its real artifact is uploaded, the placeholder artifact is a `bootstrap` file for custom runtimes (never a Node `.js` file). There is **no runtime allow-list**: after that normalisation the value is forwarded verbatim to the AWS Lambda SDK, so any runtime AWS accepts works. An unrecognised value is not caught by `validate` — it fails at deploy time when AWS rejects it.
  - `memory` (optional, integer): Memory allocation in MB (default: 256, range: 128-10240)
  - `timeout` (optional, integer): Timeout in seconds (default: 30, range: 1-900)
  - `environment` (optional, object): Environment variables as key-value pairs
  - `schedule` (optional, string, AWS): an EventBridge `rate(...)`/`cron(...)` expression that invokes the function on a schedule (see Scheduled Functions below)

**Valid Links:**
- FUNCTION_TO_DATABASE
- FUNCTION_TO_STORAGE
- FUNCTION_TO_EMAIL
- FUNCTION_TO_SMS
- FUNCTION_TO_EVENT_BUS

**Important:** 
- All functions in a component share the same `codeStorage` and `codePath`
- Function names are referenced in api-gateway routes and event-bus subscriptions (implicit references)
- Links are set at the component level and apply to all functions
- Component links automatically inject env vars: target name → `UPPER_SNAKE_CASE_ARN`
- Per-function `links` array injects env vars only into that specific function
- `environment` at providerSettings level applies to all functions; per-function `environment` overrides
- `logging: true` at group or per-function level enables JSON-format CloudWatch logging

**Scheduled Functions (AWS):**

A function entry may declare a `schedule` — an AWS EventBridge schedule expression — to be invoked on a time cadence:

```json
{
  "type": "function",
  "name": "groups-functions",
  "providerSettings": {
    "codeStorage": "artifacts",
    "codePath": "releases/groups-functions-${version}.zip",
    "functions": [
      {
        "name": "group-lifecycle-scheduler",
        "handler": "dist/group-lifecycle-scheduler.handler",
        "runtime": "nodejs22.x",
        "schedule": "rate(1 day)"
      }
    ]
  }
}
```

- The expression is either `rate(value unit)` — `unit` is `minute(s)`/`hour(s)`/`day(s)`, singular when the value is 1 and plural otherwise (e.g. `rate(1 day)`, `rate(5 minutes)`) — or `cron(...)` with the six AWS cron fields (e.g. `cron(0 12 * * ? *)`).
- At deploy time the plugin provisions a classic EventBridge (CloudWatch Events) rule named `{application}-{name}-schedule` with the schedule expression, points a target at the function, and grants `events.amazonaws.com` permission to invoke it (`lambda:InvokeFunction`, source = the rule ARN, deterministic statement id `{application}-{name}-schedule`; `ResourceConflictException` is swallowed for idempotency).
- Redeploy is declarative for changes: `PutRule`/`PutTargets` upsert by name (changing the expression updates it in place; the target uses a fixed id so no duplicates accumulate). **Removing** the `schedule` field, however, does not delete an existing rule on the next deploy — only `undeploy` removes it (which deletes the rule's targets and then the rule). To drop a schedule from a live function, undeploy/redeploy or delete the rule out-of-band.
- Validation is syntactic (`rate`/`cron` shape only); AWS validates cron field contents at deploy time, so a 6-field cron that AWS rejects (e.g. concrete day-of-month and day-of-week together) passes `validate` but fails at deploy.
- Validation (`FunctionScheduleRule`) checks the expression shape before any cloud call.
- AWS-only; a `schedule` is currently ignored on Azure and GCP.
- Deploy identity permissions: `events:PutRule`, `events:PutTargets`, `events:DeleteRule`, `events:RemoveTargets`, `events:ListTargetsByRule`, and `lambda:AddPermission`.

Implementation note: the schedule wiring is done in `AwsCloudProviderStrategy.configureScheduleTrigger`, invoked from both the multi-function and single-function deploy paths right after the Lambda's ARN is known. It uses the classic EventBridge `EventBridgeClient` (`software.amazon.awssdk.services.eventbridge`); the newer Scheduler API is not used.

**Automatic Environment Variables from Links:**

| Link Type | Example Target | Env Var Injected | Value |
|-----------|---------------|------------------|-------|
| `FUNCTION_TO_DATABASE` | `Content_Store` | `CONTENT_STORE_ARN` | DynamoDB table ARN |
| `FUNCTION_TO_STORAGE` | `Asset_Store` | `ASSET_STORE_ARN` | S3 bucket ARN |
| `FUNCTION_TO_EMAIL` | `Email_Service` | `EMAIL_SERVICE_ARN` | SES identity ARN |
| `FUNCTION_TO_SMS` | `Notif_SMS` | `NOTIF_SMS_ARN` | SNS topic ARN |
| `FUNCTION_TO_EVENT_BUS` | `Order_Events` | `ORDER_EVENTS_ARN` | EventBridge bus ARN |
| `FUNCTION_TO_AUTHENTICATION` | `Auth_Service` | `AUTH_SERVICE_ARN` | Cognito User Pool ARN |
| `FUNCTION_TO_FUNCTION` | `provision-site` | `FUNCTION_PROVISION_SITE` | Target Lambda function ARN |

**Explicit Permissions (without component links):**

Use a `permissions` array to grant access to resource types that don't exist in the configuration. This is useful when functions need to create/manage resources dynamically:

```json
{
  "name": "domain-manager",
  "handler": "handler.manage",
  "runtime": "nodejs22.x",
  "permissions": ["storage:create", "storage:delete", "dns:create", "dns:update", "dns:delete"]
}
```

Available permissions: `storage:create/read/write/delete/list`, `database:create/read/write/delete`, `dns:create/update/delete/list`, `email:send`, `sms:send`, `event-bus:publish/subscribe/manage`, `authentication:create/read/update/delete`, `certificate:create/read/delete`, `website:create/read/delete/invalidate`, `queue:create/send/receive/delete`.

Permissions can also be set at the component level (applies to all functions as a fallback):
```json
"providerSettings": {
  "permissions": ["database:read", "database:write"],
  "functions": [...]
}
```

**Region**: Any specific region (not global)

### 5. Database Component

NoSQL database with one or more tables (DynamoDB on AWS, CosmosDB on Azure, Firestore on GCP).

```json
{
  "type": "database",
  "name": "app-db",
  "providerSettings": {
    "tables": [
      {
        "name": "users",
        "partitionKey": { "name": "userId", "type": "string" }
      },
      {
        "name": "orders",
        "partitionKey": { "name": "orderId", "type": "string" },
        "sortKey": { "name": "createdAt", "type": "number" }
      }
    ],
    "billingMode": "PAY_PER_REQUEST"
  }
}
```

**Required Fields:**
- `tables` (array): One or more table definitions. Each table has:
  - `name` (string, required): Unique table name within the component
  - `partitionKey` (object, required): Primary key definition
    - `name` (string): Attribute name
    - `type` (string): `"string"`, `"number"`, or `"binary"`
  - `sortKey` (object, optional): Sort/range key definition
    - `name` (string): Attribute name
    - `type` (string): `"string"`, `"number"`, or `"binary"`
  - `ttlAttribute` (string, optional, AWS): enables DynamoDB Time To Live on the named item attribute (see Time To Live below)

**Optional Fields:**
- `billingMode` (string): Billing mode
  - `PAY_PER_REQUEST` (default): On-demand pricing
  - `PROVISIONED`: Fixed capacity with auto-scaling
- `pointInTimeRecovery` (boolean): Enable PITR backups (default: false)

**Time To Live (TTL, AWS):**

Set `ttlAttribute` on a table to enable DynamoDB Time To Live using that item attribute (an epoch-seconds expiry timestamp):

```json
{
  "type": "database",
  "name": "ChatMessage",
  "providerSettings": {
    "tables": [
      {
        "name": "ChatMessage",
        "partitionKey": { "name": "chatId", "type": "string" },
        "sortKey": { "name": "ts", "type": "string" },
        "ttlAttribute": "expireAt"
      }
    ]
  }
}
```

- DynamoDB automatically deletes each item shortly (within ~48h) after the epoch-seconds timestamp in the named attribute. It is delete-only and free.
- **Items without the attribute never expire** (native DynamoDB behaviour), so you can exempt specific items simply by not writing the attribute (e.g. keep direct messages forever while ageing out group chat).
- Reconciled declaratively on every deploy: the plugin calls `DescribeTimeToLive` then `UpdateTimeToLive` to enable TTL on the attribute if not already enabled, re-point it (disable then enable) if the attribute changed, or disable it if `ttlAttribute` is removed. Same-attribute-already-enabled is a no-op. DynamoDB rate-limits TTL toggles (~one change per hour per table).
- Implementation: `AwsCloudProviderStrategy.configureTimeToLive` runs after the table is created/confirmed, wrapped in the retry executor (retries throttling, network timeouts, and `ResourceInUseException` while a freshly-created table is still `CREATING`). Undeploy needs no TTL cleanup — `deleteTable` removes the TTL config with the table.
- AWS-only; `ttlAttribute` is ignored on Azure and GCP.
- Deploy identity permissions: `dynamodb:DescribeTimeToLive`, `dynamodb:UpdateTimeToLive`.
- Validation (`DatabaseTableRule`): when present, `ttlAttribute` must be a non-blank string.

**Key Type Mapping:**
- AWS (DynamoDB): `string` → S, `number` → N, `binary` → B
- Azure (Cosmos DB): partition key path derived from `partitionKey.name`
- GCP (Firestore): document ID field set to `partitionKey.name`

**Valid Links:** None (database is referenced by functions)

**Region**: Any specific region (not global)

### 6. Authentication Component

User authentication with groups and users.

```json
{
  "type": "authentication",
  "name": "user-auth",
  "providerSettings": {
    "loginProviders": ["email", "google"],
    "registration": "open",
    "mfa": "optional",
    "passwordPolicy": {
      "minLength": 10,
      "requireUppercase": true,
      "requireNumbers": true,
      "requireSymbols": true
    },
    "groups": [
      { "name": "admin", "description": "Administrator users" },
      { "name": "editor", "description": "Content editors" },
      { "name": "member", "description": "Standard members" }
    ],
    "users": [
      { "email": "alice@example.com", "groups": ["admin", "editor"] },
      { "email": "bob@example.com", "groups": ["editor", "member"] },
      { "email": "charlie@example.com", "groups": ["member"] }
    ]
  },
  "links": [
    {
      "sourceComponent": "user-auth",
      "targetComponent": "transactional-email",
      "linkType": "AUTHENTICATION_TO_EMAIL"
    },
    {
      "sourceComponent": "user-auth",
      "targetComponent": "notification-sms",
      "linkType": "AUTHENTICATION_TO_SMS"
    }
  ]
}
```

**Optional Fields:**
- `loginProviders` (array of strings): Sign-in methods - `"email"`, `"phone"`, `"google"`, `"facebook"`, `"apple"` (default: `["email"]`)
- `registration` (string): Registration mode - `"open"` (anyone can sign up) or `"admin-only"` (admin creates users) (default: `"open"`)
- `mfa` (string): Multi-factor authentication - `"off"`, `"optional"`, or `"required"` (default: `"off"`)
- `passwordPolicy` (object): Password strength requirements
  - `minLength` (integer): Minimum password length (>= 6, default: 8)
  - `requireUppercase` (boolean): Require uppercase letters (default: true)
  - `requireNumbers` (boolean): Require numbers (default: true)
  - `requireSymbols` (boolean): Require special characters (default: false)
- `groups` (array): User groups to create
  - `name` (required, string): Unique group name (must be non-blank)
  - `description` (required, string): Human-readable description (must be non-blank)
- `users` (array): Users to invite on deploy
  - `email` (required, string): User email address (must be non-blank)
  - `groups` (optional, array of strings): Group names to assign (must reference groups defined in this component)

**Valid Links:**
- AUTHENTICATION_TO_EMAIL
- AUTHENTICATION_TO_SMS

**Email Sending via SES (AUTHENTICATION_TO_EMAIL link):**

When an `AUTHENTICATION_TO_EMAIL` link exists, the User Pool is configured to use Amazon SES (DEVELOPER mode) as the email sender for invite and password-reset emails. This removes the default Cognito email limit (50/day) and ensures emails are sent from your verified SES identity.

- The **Email component must be deployed before the Auth component** — the link ensures this ordering automatically
- The SES `sourceArn` is resolved from the linked Email component's deployment result (no manual ARN configuration needed)
- Without the link, Cognito uses its built-in email service (limited to 50 emails/day; may not work in SES sandbox mode)
- Users receive a temporary password email when first invited

**Example with Email Link:**

```json
{
  "type": "authentication",
  "name": "Auth_Service",
  "providerSettings": {
    "passwordPolicy": {
      "minimumLength": 8,
      "requireUppercase": true,
      "requireLowercase": true,
      "requireNumbers": true,
      "requireSymbols": false
    },
    "groups": [
      { "name": "admins", "description": "Full access administrators" },
      { "name": "editors", "description": "Content editors" }
    ],
    "users": [
      { "email": "admin@example.com", "groups": ["admins"] }
    ]
  },
  "links": [
    {
      "sourceComponent": "Auth_Service",
      "targetComponent": "Email_Service",
      "linkType": "AUTHENTICATION_TO_EMAIL"
    }
  ]
}
```

**Idempotent Deployment:**

Re-deploying the authentication component is safe and idempotent:
- User Pools are found by name before creating — no duplicate pools
- User Pool Clients are found by name before creating — no duplicate clients
- Users with `UsernameExistsException` are silently skipped (not re-invited)
- Groups with `GroupExistsException` are silently skipped (not duplicated)

This means you can safely run `mvn serverless:deploy` multiple times without side effects.

**Validation Rules:**
- Group names and descriptions must be non-blank
- User emails must be non-blank
- User group references must match defined group names
- Groups are provisioned before users
- `triggers` (if present) must be an object whose keys are known Cognito trigger points and whose values name functions that exist
- All validation errors are accumulated (no early exit)

**Cognito Lambda Triggers (AWS):**

An optional `providerSettings.triggers` object attaches Cognito user-pool Lambda triggers. Each entry maps a trigger point to a function name; the function is an **implicit reference** (not written in `links`).

```json
{
  "type": "authentication",
  "name": "staff-auth",
  "providerSettings": {
    "mfa": "required",
    "triggers": { "preTokenGeneration": "mfa-enforcer" }
  }
}
```

- Supported trigger points: `preSignUp`, `postConfirmation`, `preAuthentication`, `postAuthentication`, `preTokenGeneration`, `customMessage`, `defineAuthChallenge`, `createAuthChallenge`, `verifyAuthChallengeResponse`, `userMigration`.
- The parser synthesizes an implicit `AUTHENTICATION_TO_FUNCTION` link per referenced function, so functions deploy before the pool and the reference is validated against the registry.
- At deploy time the plugin sets the user pool's `LambdaConfig` (on create, and via `UpdateUserPool` for an existing pool) and grants each function `lambda:InvokeFunction` permission for `cognito-idp.amazonaws.com`, scoped to the pool ARN, with a deterministic statement id (`cognito-{poolId}-{triggerPoint}`; `ResourceConflictException` is swallowed for idempotency).
- Redeploy is declarative: repointing a trigger's function updates it, and removing a trigger (or `"triggers": {}`) clears it. A trigger whose function ARN cannot be resolved is skipped with a warning rather than failing the deploy.
- Deploy identity permissions required: `cognito-idp:*` (covers `UpdateUserPool`) plus `lambda:AddPermission`.

Implementation note: `AwsCloudProviderStrategy.deployAuthentication` resolves each trigger function's ARN via `resolveFunctionArn` (the shared `deploymentResults` cache, falling back to a live `getFunctionConfiguration` lookup), builds a `LambdaConfigType`, and grants the invoke permission. Cognito Lambda triggers are AWS-only.

**Region**: Must be `"global"`

### 7. Email Component

Transactional email service.

```json
{
  "type": "email",
  "name": "transactional-email",
  "providerSettings": {
    "fromAddress": "noreply@example.com"
  },
  "links": []
}
```

**Required Fields:**
- `fromAddress` (string): Email address to send from

**Valid Links:** None (email is referenced by authentication and functions)

**Region**: Must be `"global"`

### 8. SMS Component

SMS messaging service.

```json
{
  "type": "sms",
  "name": "notification-sms",
  "providerSettings": {},
  "links": []
}
```

**Required Fields:** None

**Valid Links:** None (SMS is referenced by authentication and functions)

**Region**: Must be `"global"`

### 9. Event Bus Component

Pub/sub event bus with subscriptions.

```json
{
  "type": "event-bus",
  "name": "order-events",
  "providerSettings": {
    "subscriptions": [
      {
        "eventPattern": "order.placed",
        "function": "order-processor"
      },
      {
        "eventPattern": "order.shipped",
        "function": "notification-sender"
      }
    ]
  },
  "links": []
}
```

**Optional Fields:**
- `subscriptions` (array): Event subscriptions
  - `eventPattern` (required, string): Event type to match
  - `function` (required, string): Function name to invoke

**Valid Links:** None (uses implicit references in subscriptions)

**Important:** Function names in `subscriptions` are implicit references - do NOT add them to the `links` array.

**Region**: Any specific region (not global)

### 10. WAF Component

Web Application Firewall. On AWS this deploys a WAFv2 Web ACL and associates it with the linked
`website` (CloudFront) and/or `api-gateway`. Its primary use is edge **geo detection and
country-based access control**: detect the visitor country at the edge, allow / block / count by
country, and forward the resolved country to downstream services.

```json
{
  "type": "waf",
  "name": "edge-waf",
  "providerSettings": {
    "geoRestriction": {
      "type": "blocklist",
      "countries": ["CU", "IR"],
      "action": "BLOCK"
    },
    "countryHeader": "x-fp-country"
  },
  "links": [
    { "sourceComponent": "edge-waf", "targetComponent": "marketing-site", "linkType": "WAF_TO_WEBSITE" },
    { "sourceComponent": "edge-waf", "targetComponent": "core-api",       "linkType": "WAF_TO_API_GATEWAY" }
  ]
}
```

**Geo restriction (`geoRestriction`):**
- `type` (required, string): `blocklist` (block the listed countries; default action for the web ACL is ALLOW) or `allowlist` (allow only the listed countries; default action becomes BLOCK).
- `countries` (required, array): ISO 3166-1 alpha-2 codes (e.g. `US`, `GB`, `CU`).
- `action` (optional, string): `ALLOW`, `BLOCK`, or `COUNT`. Overrides the action derived from `type`. `COUNT` records matches without enforcing (observe-only) — useful for validating a rule before turning on blocking.

**Country header (`countryHeader`, optional):** a request header name (e.g. `x-fp-country`) that the WAF inserts on matched requests via WAFv2 custom request handling, so downstream functions and the API receive one authoritative country signal.

**Association and scope (AWS):**
- A `WAF_TO_WEBSITE` link provisions a `CLOUDFRONT`-scope Web ACL in `us-east-1` and sets its ARN on the CloudFront distribution config (`webACLId`). CloudFront association is done through `UpdateDistribution`, not the WAFv2 `AssociateWebACL` API.
- A `WAF_TO_API_GATEWAY` link provisions a `REGIONAL`-scope Web ACL in the deploy region and associates it with the API's `$default` stage via `AssociateWebACL`.
- A single WAF linked to both a website and an api-gateway therefore produces **two** Web ACLs — one per scope — because AWS forbids associating a CLOUDFRONT-scope ACL with a regional resource (and vice-versa).
- Deploy ordering guarantees the WAF is provisioned after its targets so their ARNs can be resolved.

**Other supported `providerSettings` (validated):** `rules`, `rateLimit`, `ipAllowList`, `ipBlockList`, `managedRuleGroups`, `logging`.

**Valid Links:** `WAF_TO_WEBSITE`, `WAF_TO_API_GATEWAY`.

**Region**: Any specific region (not global). Note that CLOUDFRONT-scope Web ACLs are always created in `us-east-1` regardless of the component's region.

## Component Links

Links are declared in the `links` array on each component. Each link has three required fields:

```json
{
  "sourceComponent": "source-name",
  "targetComponent": "target-name",
  "linkType": "LINK_TYPE"
}
```

### Valid Link Types

| Link Type | Source | Target | Description |
|-----------|--------|--------|-------------|
| WEBSITE_TO_STORAGE | website | storage | Website serves content from storage bucket at a path (requires `path` property) |
| WEBSITE_TO_API_GATEWAY | website | api-gateway | Website calls API |
| API_GATEWAY_TO_FUNCTION | api-gateway | functions | API routes to function (implicit via routes) |
| API_GATEWAY_TO_AUTHENTICATION | api-gateway | authentication | API validates JWT (implicit via routes) |
| FUNCTION_TO_DATABASE | functions | database | Function accesses database |
| FUNCTION_TO_STORAGE | functions | storage | Function accesses storage |
| FUNCTION_TO_EMAIL | functions | email | Function sends emails |
| FUNCTION_TO_SMS | functions | sms | Function sends SMS |
| FUNCTION_TO_EVENT_BUS | functions | event-bus | Function publishes events |
| FUNCTION_TO_FUNCTION | functions | functions | Function invokes another function directly (target is individual function name, e.g. "provision-site") |
| FUNCTION_TO_API_GATEWAY | functions | api-gateway | Function posts messages to WebSocket clients (`execute-api:ManageConnections`) — implicit for WebSocket route functions |
| FUNCTION_TO_AUTHENTICATION | functions | authentication | Function manages users in the identity provider |
| FUNCTION_TO_DOMAIN | functions | (DNS) | Function manages DNS records |
| EVENT_BUS_TO_FUNCTION | event-bus | functions | Event bus invokes function (implicit via subscriptions) |
| AUTHENTICATION_TO_FUNCTION | authentication | functions | Cognito user-pool Lambda trigger (implicit, from `triggers`) |
| AUTHENTICATION_TO_EMAIL | authentication | email | Auth sends verification emails |
| AUTHENTICATION_TO_SMS | authentication | sms | Auth sends MFA codes |
| WAF_TO_WEBSITE | waf | website | WAF protects a website distribution |
| WAF_TO_API_GATEWAY | waf | api-gateway | WAF protects an API gateway |

### Implicit vs Explicit References

**Implicit References** (do NOT add to `links` array):
- Function names in api-gateway `routes[].function`
- Auth component names in api-gateway `routes[].auth`
- Function names in api-gateway `preProcessFunction` and `postProcessFunction`
- For WebSocket api-gateways (`protocol: "websocket"`), the `FUNCTION_TO_API_GATEWAY` ManageConnections link for each route function
- Function names in event-bus `subscriptions[].function`
- Storage component name in functions `codeStorage`

**Explicit References** (add to `links` array):
- Functions accessing database, storage, email, SMS, event-bus
- Authentication linking to email or SMS
- Website linking to api-gateway or storage

## Region Guidelines

| Component Type | Region |
|----------------|--------|
| website | Specific region (e.g. us-east-1) |
| storage | Specific region |
| api-gateway | Specific region |
| functions | Specific region |
| database | Specific region |
| event-bus | Specific region |
| authentication | **global** |
| email | **global** |
| sms | **global** |

## Common Patterns

### Pattern 1: Multi-tier Web Application

```json
{
  "name": "Web Application",
  "application": "com.example.webapp",
  "provider": "aws",
  "regions": [
    {
      "region": "global",
      "items": [
        {
          "type": "authentication",
          "name": "user-auth",
          "providerSettings": {
            "loginProviders": ["email"],
            "groups": [
              { "name": "admin", "description": "Administrators" },
              { "name": "user", "description": "Regular users" }
            ],
            "users": [
              { "email": "admin@example.com", "groups": ["admin"] }
            ]
          },
          "links": []
        },
        {
          "type": "email",
          "name": "app-email",
          "providerSettings": { "fromAddress": "noreply@example.com" },
          "links": []
        }
      ]
    },
    {
      "region": "eu-west-2",
      "items": [
        {
          "type": "storage",
          "name": "artifacts",
          "providerSettings": {
            "uploads": [
              {
                "artifact": "com.example:backend:${version}",
                "destination": "releases/backend/",
                "unpack": true
              }
            ]
          },
          "links": []
        },
        {
          "type": "database",
          "name": "app-db",
          "providerSettings": { "billingMode": "PAY_PER_REQUEST" },
          "links": []
        },
        {
          "type": "functions",
          "name": "backend",
          "providerSettings": {
            "codeStorage": "artifacts",
            "codePath": "releases/backend/backend-1.0.0.jar",
            "functions": [
              {
                "name": "api-handler",
                "handler": "com.example.ApiHandler::handleRequest",
                "runtime": "java21",
                "memory": 512
              }
            ]
          },
          "links": [
            {
              "sourceComponent": "backend",
              "targetComponent": "app-db",
              "linkType": "FUNCTION_TO_DATABASE"
            },
            {
              "sourceComponent": "backend",
              "targetComponent": "app-email",
              "linkType": "FUNCTION_TO_EMAIL"
            }
          ]
        },
        {
          "type": "api-gateway",
          "name": "api",
          "providerSettings": {
            "domain": "api.example.com",
            "routes": [
              {
                "path": "/users",
                "method": "GET",
                "function": "api-handler",
                "auth": "user-auth"
              }
            ]
          },
          "links": []
        },
        {
          "type": "website",
          "name": "frontend",
          "providerSettings": { "domain": "www.example.com" },
          "links": [
            {
              "sourceComponent": "frontend",
              "targetComponent": "api",
              "linkType": "WEBSITE_TO_API_GATEWAY"
            }
          ]
        }
      ]
    }
  ]
}
```

### Pattern 2: Event-Driven Architecture

```json
{
  "name": "Event-Driven System",
  "application": "com.example.events",
  "provider": "aws",
  "regions": [
    {
      "region": "us-east-1",
      "items": [
        {
          "type": "storage",
          "name": "artifacts",
          "providerSettings": {
            "uploads": [
              {
                "artifact": "com.example:processors:1.0.0",
                "destination": "releases/processors/",
                "unpack": true
              }
            ]
          },
          "links": []
        },
        {
          "type": "event-bus",
          "name": "events",
          "providerSettings": {
            "subscriptions": [
              { "eventPattern": "order.created", "function": "order-processor" },
              { "eventPattern": "order.shipped", "function": "notification-sender" }
            ]
          },
          "links": []
        },
        {
          "type": "functions",
          "name": "processors",
          "providerSettings": {
            "codeStorage": "artifacts",
            "codePath": "releases/processors/processors-1.0.0.jar",
            "functions": [
              {
                "name": "order-processor",
                "handler": "com.example.OrderProcessor::handleRequest",
                "runtime": "java21"
              },
              {
                "name": "notification-sender",
                "handler": "com.example.NotificationSender::handleRequest",
                "runtime": "java21"
              }
            ]
          },
          "links": [
            {
              "sourceComponent": "processors",
              "targetComponent": "events",
              "linkType": "FUNCTION_TO_EVENT_BUS"
            }
          ]
        }
      ]
    }
  ]
}
```

## Validation Rules

The plugin validates configurations with these rules:

1. **Required Fields**: All required fields must be present and non-empty
2. **Unique Names**: All component names must be unique within the configuration
3. **Valid References**: All component references (in links and implicit references) must exist
4. **Link Types**: Link types must match the source and target component types
5. **Region Constraints**: Global components must be in "global" region
6. **Authentication Groups**: Group names and descriptions must be non-blank
7. **Authentication Users**: User emails must be non-blank, group references must be valid
8. **Functions**: codeStorage must reference an existing storage component
9. **API Routes**: Function and auth references must exist
10. **Event Subscriptions**: Function references must exist
11. **Domain Names**: Base domain must exist in cloud provider DNS

## Best Practices

1. **Component Naming**: Use descriptive, kebab-case names (e.g. "user-auth", "order-api", "product-db")

2. **Region Selection**:
   - Use "global" for: authentication, email, sms
   - Use specific regions for: website, storage, api-gateway, functions, database, event-bus
   - Consider latency and data residency requirements

3. **Links vs Implicit References**:
   - Use `links` array for: FUNCTION_TO_*, AUTHENTICATION_TO_*, WEBSITE_TO_*
   - Do NOT use `links` for: function names in routes, auth in routes, subscriptions

4. **Authentication Groups**:
   - Define groups before users
   - Use clear, descriptive group names and descriptions
   - Validate that user group references match defined groups

5. **Functions Component**:
   - Group related functions together in one component
   - Share codeStorage and codePath across all functions
   - Use component-level links for shared dependencies
   - Set appropriate memory and timeout for each function

6. **Storage Uploads**:
   - Use unpack: true for JAR/ZIP files that need extraction
   - Ensure destination paths end with "/"
   - Reference the correct Maven coordinates
   - Use `${version}` instead of hard-coding versions in multi-module projects
   - Prefer inline classifier/extension in the coordinate (`groupId:artifactId:version:classifier:extension`) for clarity

7. **API Gateway**:
   - Use preProcessFunction for request validation, IP filtering, rate limiting
   - Use postProcessFunction for audit logging, response transformation, security headers
   - Override per-route with "" to disable for specific routes
   - Always specify auth component for protected routes

8. **Variables**:
   - Use variables for environment-specific values (stage, domain suffixes, etc.)
   - Reference with ${variableName} syntax in any string field

9. **Validation**:
   - Run `mvn serverless:validate` before deploy
   - Check for missing required fields, invalid references, blank values
   - Verify all component names are unique

10. **Deployment**:
    - Use `mvn serverless:plan` to preview changes before deploy
    - Deploy to dev/staging environments first
    - Use `mvn serverless:verify` after deploy to check health

## Troubleshooting

### Common Validation Errors

1. **Missing required field**: Add the required field to providerSettings
2. **Invalid component reference**: Check that the referenced component name exists
3. **Blank group/user field**: Ensure all group names, descriptions, and user emails are non-empty
4. **User references non-existent group**: Check that user's groups array only contains defined group names
5. **Invalid link type**: Verify the link type matches the source and target component types
6. **Component in wrong region**: Move authentication, email, sms to "global" region

### Debugging Tips

1. Run `mvn serverless:validate` to see all validation errors
2. Check that all component names are unique
3. Verify all implicit references (function names in routes, subscriptions) exist
4. Ensure base domains exist in cloud provider DNS
5. Check that Maven artifacts exist in repositories

## Example Prompts for AI Assistants

### Generate Complete Application

```
Generate a serverless config for a web app with:
- A React SPA (website) at www.example.com
- A REST API (api-gateway) at api.example.com backed by Java functions
- A DynamoDB database
- Cognito authentication with admin and member groups
- Email service for transactional emails
- Deploy to AWS eu-west-2

Include:
- Storage component for deployment artifacts
- Functions component with api-handler and event-processor functions
- Authentication with groups: admin, member
- Pre-invite users: admin@example.com (admin group), user@example.com (member group)
- Wire all components together with appropriate links
```

### Add Authentication with Groups

```
Add an authentication component called "user-auth" with:
- Email login provider
- Open registration
- Optional MFA
- Password policy: min 10 chars, require uppercase, numbers, and symbols
- Groups: "admin" (Administrator users), "editor" (Content editors), "viewer" (Read-only users)
- Pre-invite users:
  - admin@example.com in admin and editor groups
  - editor@example.com in editor group
  - viewer@example.com in viewer group
- Link to "transactional-email" component for verification emails
Deploy in global region
```

### Add Functions Component

```
Add a functions component called "api-functions" with:
- codeStorage: "deploy-artifacts"
- codePath: "releases/api-functions/api-functions-1.0.0.jar"
- Three functions:
  1. "user-handler" with handler "com.example.UserHandler::handleRequest", runtime java21, 512MB memory
  2. "order-handler" with handler "com.example.OrderHandler::handleRequest", runtime java21, 1024MB memory, 60s timeout
  3. "notification-handler" with handler "com.example.NotificationHandler::handleRequest", runtime java21
- Add links to "app-db" database, "transactional-email" email, and "order-events" event-bus
```

### Add API Gateway

```
Add an api-gateway component called "main-api" with:
- domain: api.example.com
- preProcessFunction: "request-validator" (runs before all routes)
- postProcessFunction: "response-logger" (runs after all routes)
- Routes:
  1. GET /users - function: "user-handler", auth: "user-auth"
  2. POST /users - function: "user-handler", auth: "user-auth"
  3. GET /orders - function: "order-handler", auth: "user-auth"
  4. GET /public/health - function: "health-check", no auth, disable pre/post processing
  5. POST /webhooks/stripe - function: "webhook-handler", no auth, preProcessFunction: "webhook-validator"
```

### Validate and Deploy

```
Run serverless:validate and explain any errors in my config.
If validation passes, show me the mvn command to deploy.
```

## Known Limitations

1. Base domain for website and api-gateway must already be registered and have a hosted zone in the cloud provider
2. Social login providers (Google, Facebook, Apple) require OAuth app credentials configured outside the plugin
3. Azure AD B2C tenant creation requires manual setup
4. GCP Firestore is project-scoped - all database components share one Firestore instance
5. AWS SES starts in sandbox mode - request production access separately
6. GCP SMS and Email use third-party services (Twilio, SendGrid) via Secret Manager
