diff --git a/.env.local.example b/.env.local.example
new file mode 100644
index 0000000..0879020
--- /dev/null
+++ b/.env.local.example
@@ -0,0 +1,5 @@
+LOCALSTACK_AUTH_TOKEN=
+
+# Local CDK defaults
+AWS_ENDPOINT_URL=http://localhost:4566
+AWS_ENDPOINT_URL_S3=http://s3.localhost:4566
diff --git a/.github/workflows/check.yml b/.github/workflows/verify.yml
similarity index 60%
rename from .github/workflows/check.yml
rename to .github/workflows/verify.yml
index a7030c9..6d636e9 100644
--- a/.github/workflows/check.yml
+++ b/.github/workflows/verify.yml
@@ -1,19 +1,17 @@
-name: Format, Lint, and Test
+name: Verify code and infra
on:
workflow_call:
push:
jobs:
- check:
+ verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Install mise
uses: jdx/mise-action@v4
- - name: Format and lint
- run: mise run lint
- - name: Run tests
- run: mise run test
+ - name: Verify code and infra
+ run: mise run verify
env:
AWS_DEFAULT_REGION: us-east-1
diff --git a/.gitignore b/.gitignore
index 910939d..19cee17 100644
--- a/.gitignore
+++ b/.gitignore
@@ -123,6 +123,7 @@ celerybeat.pid
# Environments
.env
+.env.local
.venv
env/
venv/
@@ -171,4 +172,10 @@ cython_debug/
devcontainer-lock.json
# CDK
-cdk.out/
\ No newline at end of file
+cdk.out/
+
+# Localstack
+.localstack/
+
+# Node.js
+node_modules/
diff --git a/.vibe/specs/deploy-localstack/design.md b/.vibe/specs/deploy-localstack/design.md
new file mode 100644
index 0000000..e3d060a
--- /dev/null
+++ b/.vibe/specs/deploy-localstack/design.md
@@ -0,0 +1,37 @@
+# Design: Deploy Lambda Stacks to Local via LocalStack
+
+## System Architecture
+
+```mermaid
+flowchart TD
+ CLI["mise run local <stack>"] --> CDK["aws-cdk-local (npx)"]
+ CDK -->|"http://localhost:4566"| LS["LocalStack Container
(DynamoDB, Lambda, ApiGateway, SQS, etc.)"]
+```
+
+## Component Design
+
+### 1. `.env.local.example` & `compose.yml`
+
+- `.env.local.example`: Template configuration file defining `LOCALSTACK_AUTH_TOKEN`, local AWS credentials, and endpoint URLs.
+- `compose.yml`: Standard LocalStack Docker Compose service configuration mapping port `4566` (LocalStack Gateway) and volume mounts for persistence, loaded via `--env-file .env.local`.
+
+### 2. `mise.toml`
+
+Adds the following task configurations:
+
+- `tasks."local:up"`: Launches LocalStack via `docker compose --env-file .env.local up -d --wait localstack`.
+- `tasks."local:down"`: Stops LocalStack via `docker compose --env-file .env.local down localstack`.
+- `tasks."local:deploy"`: Executes `STACK=$usage_stack npx --package=aws-cdk --package=aws-cdk-local cdklocal deploy --require-approval=never`.
+ - Aliases: `local`, `dl`
+ - Depends on: `install-cdk`, `local:up`
+- `tasks."local:destroy"`: Executes `STACK=$usage_stack npx --package=aws-cdk --package=aws-cdk-local cdklocal destroy --force`.
+ - Alias: `Dl`
+ - Depends on: `install-cdk`, `local:up`
+- `tasks.docs-local`: Serves MkDocs documentation (`uv run mkdocs serve`).
+
+### 3. Documentation (`docs/README.md`, `AGENTS.md`)
+
+- Instruct copying `.env.local.example` to `.env.local` and obtaining auth token from `app.localstack.cloud`.
+- Add LocalStack under Prerequisites and Setup sections.
+- Update shell aliases and common commands tables.
+- Add step-by-step instructions to start LocalStack and deploy stacks locally.
diff --git a/.vibe/specs/deploy-localstack/plan.md b/.vibe/specs/deploy-localstack/plan.md
new file mode 100644
index 0000000..5b784f9
--- /dev/null
+++ b/.vibe/specs/deploy-localstack/plan.md
@@ -0,0 +1,70 @@
+# Implementation Plan - Deploy Lambda Stacks to Local using LocalStack
+
+Enable local deployment and teardown of AWS CDK Lambda stacks using LocalStack and `aws-cdk-local`.
+
+## User Review Required
+
+> [!IMPORTANT]
+> Developers must copy `.env.local.example` to `.env.local` and set `LOCALSTACK_AUTH_TOKEN` obtained from [app.localstack.cloud](https://app.localstack.cloud).
+
+## Proposed Changes
+
+### Configuration & Infrastructure
+
+#### [NEW] [compose.yml](file:///Users/amrabed/Library/CloudStorage/OneDrive-Personal/code/aws-lambda-templates/compose.yml)
+
+- Add standard LocalStack container definition exposing port `4566`.
+
+#### [NEW] [.env.local.example](file:///Users/amrabed/Library/CloudStorage/OneDrive-Personal/code/aws-lambda-templates/.env.local.example)
+
+- Add template environment file with `LOCALSTACK_AUTH_TOKEN`, local AWS credentials, and endpoint URLs.
+
+#### [MODIFY] [mise.toml](file:///Users/amrabed/Library/CloudStorage/OneDrive-Personal/code/aws-lambda-templates/mise.toml)
+
+- Add shell aliases `local = "mise run local:deploy"`, `dl = "mise run local:deploy"`, and `Dl = "mise run local:destroy"`.
+- Rename documentation local serve task to `[tasks.docs-local]`.
+- Add `[tasks."local:up"]` to start LocalStack via `docker compose --env-file .env.local up -d --wait localstack`.
+- Add `[tasks."local:down"]` to stop LocalStack via `docker compose --env-file .env.local down localstack`.
+- Add `[tasks."local:deploy"]` (aliases `local`, `dl`) to deploy stacks locally using `aws-cdk-local`.
+- Add `[tasks."local:destroy"]` (alias `Dl`) to destroy stacks locally using `aws-cdk-local`.
+
+---
+
+### Documentation
+
+#### [MODIFY] [docs/README.md](file:///Users/amrabed/Library/CloudStorage/OneDrive-Personal/code/aws-lambda-templates/docs/README.md)
+
+- Update Prerequisites section to include LocalStack / Docker.
+- Add step to copy `.env.local.example` to `.env.local` and obtain token from `app.localstack.cloud`.
+- Add "Deploy stack to local (LocalStack)" and "Destroy local stack" sub-sections under Infrastructure deployment options.
+- Update project structure tree diagram to include `compose.yml` and `.vibe/specs`.
+
+#### [MODIFY] [AGENTS.md](file:///Users/amrabed/Library/CloudStorage/OneDrive-Personal/code/aws-lambda-templates/AGENTS.md)
+
+- Add instructions to setup `.env.local` with token from `app.localstack.cloud`.
+- Add `mise run local:deploy`, `mise run local:destroy`, `mise run local:up`, and `mise run local:down` to Common Commands list.
+
+---
+
+### Specifications
+
+#### [NEW] [.vibe/specs/deploy-localstack/requirements.md](file:///Users/amrabed/Library/CloudStorage/OneDrive-Personal/code/aws-lambda-templates/.vibe/specs/deploy-localstack/requirements.md)
+
+#### [NEW] [.vibe/specs/deploy-localstack/design.md](file:///Users/amrabed/Library/CloudStorage/OneDrive-Personal/code/aws-lambda-templates/.vibe/specs/deploy-localstack/design.md)
+
+#### [NEW] [.vibe/specs/deploy-localstack/plan.md](file:///Users/amrabed/Library/CloudStorage/OneDrive-Personal/code/aws-lambda-templates/.vibe/specs/deploy-localstack/plan.md)
+
+#### [NEW] [.vibe/specs/deploy-localstack/tasks.md](file:///Users/amrabed/Library/CloudStorage/OneDrive-Personal/code/aws-lambda-templates/.vibe/specs/deploy-localstack/tasks.md)
+
+#### [NEW] [.vibe/specs/deploy-localstack/walkthrough.md](file:///Users/amrabed/Library/CloudStorage/OneDrive-Personal/code/aws-lambda-templates/.vibe/specs/deploy-localstack/walkthrough.md)
+
+## Verification Plan
+
+### Automated Tests
+
+- Run `mise run lint` (ruff format and check) to confirm code quality and formatting.
+- Run `mise run test` to verify pytest suite execution.
+
+### Manual Verification
+
+- Test synthesizing / validating localstack CDK command syntax: `STACK=api uv run npx --package=aws-cdk --package=aws-cdk-local cdklocal synth`.
diff --git a/.vibe/specs/deploy-localstack/requirements.md b/.vibe/specs/deploy-localstack/requirements.md
new file mode 100644
index 0000000..3c294b5
--- /dev/null
+++ b/.vibe/specs/deploy-localstack/requirements.md
@@ -0,0 +1,29 @@
+# Requirements: Deploy Lambda Stacks to Local via LocalStack
+
+## Overview
+
+Enable developers to deploy and tear down AWS CDK Lambda stacks locally using LocalStack without requiring an active AWS cloud account or active AWS credentials.
+
+## Functional Requirements
+
+1. **Environment & Auth Token Setup**:
+ - Provide `.env.local.example` with defaults for LocalStack and local CDK deployment.
+ - Instruct developers to copy `.env.local.example` to `.env.local` and obtain an auth token from [app.localstack.cloud](https://app.localstack.cloud) to populate `LOCALSTACK_AUTH_TOKEN`.
+2. **Local Stack Deployment**:
+ - Provide a `local:deploy` task in `mise.toml` that deploys any CDK stack defined under `infra/stacks/` to a local LocalStack instance.
+ - Command syntax: `mise run local:deploy ` (alias `local ` or `dl `).
+3. **Local Stack Destruction**:
+ - Provide a `local:destroy` task in `mise.toml` that destroys a deployed stack from LocalStack.
+ - Command syntax: `mise run local:destroy ` (alias `Dl `).
+4. **LocalStack Container Management**:
+ - Provide a standard `compose.yml` file configuring LocalStack.
+ - Provide `local:up` (`mise run local:up`) to start LocalStack with `.env.local`.
+ - Provide `local:down` (`mise run local:down`) to stop LocalStack.
+5. **Documentation Updates**:
+ - Update `docs/README.md` to document LocalStack setup, `.env.local` configuration, token retrieval from app.localstack.cloud, prerequisites, and usage of `local:deploy`, `local:destroy`, `local:up`, and `local:down`.
+ - Update `AGENTS.md` to include local deployment environment setup, commands, aliases (`local`, `dl`, `Dl`), and instructions for AI agents.
+
+## Non-Functional Requirements
+
+- Maintain backward compatibility with existing cloud CDK deployment tasks (`mise run deploy` and `mise run destroy`).
+- Pass all project linting (`mise run lint`) and tests (`mise run test`).
diff --git a/.vibe/specs/deploy-localstack/tasks.md b/.vibe/specs/deploy-localstack/tasks.md
new file mode 100644
index 0000000..f5bca0b
--- /dev/null
+++ b/.vibe/specs/deploy-localstack/tasks.md
@@ -0,0 +1,11 @@
+# Tasks: Deploy Lambda Stacks to Local via LocalStack
+
+- [x] Create `compose.yml` for LocalStack container management
+- [x] Create `.env.local.example` template environment file
+- [x] Add `tasks."local:up"`, `tasks."local:down"`, `tasks."local:deploy"`, and `tasks."local:destroy"` to `mise.toml`
+- [x] Add `local`, `dl`, and `Dl` shell aliases to `mise.toml`
+- [x] Update `docs/README.md` with `.env.local` setup, app.localstack.cloud token, and deployment instructions
+- [x] Update `AGENTS.md` with `.env.local` token guidance, `mise` tasks, and local CDK instructions
+- [x] Run `mise run lint` to verify code quality
+- [x] Run `mise run test` to verify test suite passes
+- [x] Create `walkthrough.md` with complete verification details
diff --git a/.vibe/specs/deploy-localstack/walkthrough.md b/.vibe/specs/deploy-localstack/walkthrough.md
new file mode 100644
index 0000000..19a002c
--- /dev/null
+++ b/.vibe/specs/deploy-localstack/walkthrough.md
@@ -0,0 +1,46 @@
+# Walkthrough: Deploy Lambda Stacks to Local using LocalStack
+
+We have added support for deploying and tearing down AWS CDK Lambda stacks locally using LocalStack.
+
+## Changes Made
+
+### Configuration & Infrastructure
+
+- Created `compose.yml` configured to spin up LocalStack (gateway on port 4566).
+- Created `.env.local.example` with defaults for local execution and LocalStack auth token configuration.
+- Updated `mise.toml`:
+ - Added `[tasks."local:up"]` task to start LocalStack container with `.env.local`.
+ - Added `[tasks."local:down"]` task to stop LocalStack container with `.env.local`.
+ - Added `[tasks."local:deploy"]` task with aliases `local` and `dl` to deploy CDK stacks locally via `aws-cdk-local` (depends on `install-cdk`, `local:up`).
+ - Added `[tasks."local:destroy"]` task with alias `Dl` to destroy stacks from LocalStack via `aws-cdk-local` (depends on `install-cdk`, `local:up`).
+ - Renamed documentation local preview task to `[tasks.docs-local]`.
+
+### Documentation
+
+- Updated `docs/README.md`:
+ - Added step to copy `.env.local.example` to `.env.local` and set `LOCALSTACK_AUTH_TOKEN` from [app.localstack.cloud](https://app.localstack.cloud).
+ - Added Docker under Local environment prerequisites.
+ - Added "Deploy a stack locally (LocalStack)" and "Destroy a local stack" sections with `local:up`, `local:deploy`, `local:destroy`, and `local:down`.
+ - Updated Project Structure tree diagram with `compose.yml`.
+- Updated `AGENTS.md`:
+ - Added `.env.local` token guidance, LocalStack & local CDK deployment commands (`mise run local:up`, `mise run local:deploy`, `mise run local:destroy`) and aliases.
+
+### Specifications
+
+- Updated `.vibe/specs/deploy-localstack/`:
+ - `requirements.md`
+ - `design.md`
+ - `plan.md`
+ - `tasks.md`
+ - `walkthrough.md`
+
+## Verification Results
+
+### Automated Verification
+
+1. `mise run lint`: Format & lint validations passed.
+2. `mise run test`: All 71 unit tests passed with 93% coverage.
+
+### Manual Verification
+
+- Verified `.env.local.example` content and task execution configuration.
diff --git a/AGENTS.md b/AGENTS.md
index 3e244ca..5e41b6d 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -18,8 +18,13 @@ mise run precommit # install pre-commit hooks
```bash
mise run lint # run ruff (check + format) and pyright
mise run test # run pytest with coverage
+mise run infra:synth # synthesize CDK stack(s) (alias: synth, s)
mise run docs # build and deploy docs to GitHub Pages
-mise run local # serve docs locally
+mise run docs-local # serve docs locally
+mise run local:up # start LocalStack via Docker Compose
+mise run local:deploy # deploy CDK stack to LocalStack (alias: local, dl)
+mise run local:destroy # destroy CDK stack from LocalStack (alias: Dl)
+mise run local:down # stop LocalStack via Docker Compose
```
## Code Style
@@ -48,6 +53,7 @@ templates/ # main package
tests/ # pytest tests
docs/ # MkDocs documentation
infra/ # AWS CDK infrastructure stacks
+compose.yml # LocalStack container configuration
```
## Renaming the Template
@@ -67,7 +73,12 @@ mise run rename --name="my-project" --description="My description" --author="Nam
## Infrastructure
-- Define and deploy infrastructure using AWS CDK under the `infra/` folder
+- Define infrastructure using AWS CDK under the `infra/` folder.
+- Synthesize CloudFormation templates: `mise run infra:synth [stack]` (alias `synth [stack]`, `s [stack]`).
+- Deploy to AWS: `mise run deploy ` (alias `d `).
+- Deploy locally using LocalStack: copy `.env.local.example` to `.env.local` and set token from [app.localstack.cloud](https://app.localstack.cloud), then `mise run local:deploy ` (alias `local `, `dl `).
+- Destroy locally from LocalStack: `mise run local:destroy ` (alias `Dl `).
+
## Testing Guidelines
diff --git a/cdk.json b/cdk.json
index 8e703da..2bc0551 100644
--- a/cdk.json
+++ b/cdk.json
@@ -1,4 +1,4 @@
{
- "app": "python infra/app.py",
- "requireApproval": "never"
-}
\ No newline at end of file
+ "app": "python infra/app.py",
+ "requireApproval": "never"
+}
diff --git a/compose.yml b/compose.yml
new file mode 100644
index 0000000..57d87c9
--- /dev/null
+++ b/compose.yml
@@ -0,0 +1,16 @@
+services:
+ localstack:
+ container_name: localstack
+ image: localstack/localstack:latest
+ env_file: .env.local
+ ports:
+ - "4566:4566"
+ volumes:
+ - "${LOCALSTACK_VOLUME_DIR:-./.localstack}:/var/lib/localstack"
+ - "/var/run/docker.sock:/var/run/docker.sock"
+ healthcheck:
+ test: ["CMD", "curl", "-f", "http://localhost:4566/_localstack/health"]
+ interval: 5s
+ timeout: 5s
+ retries: 10
+ start_period: 10s
diff --git a/docs/README.md b/docs/README.md
index ef67518..a39669e 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -31,6 +31,7 @@ Templates come pre-wired with:
- **Clean Architecture**: Separation of concerns using the Repository pattern for data access
- **Data Modeling**: Strong typing and validation using [Pydantic](https://docs.pydantic.dev)
- **Infrastructure as Code**: [AWS CDK](https://aws.amazon.com/cdk) stacks
+- **Local AWS Deployment**: [LocalStack](https://localstack.cloud) integration for local CDK deployment and testing without an AWS account
- **Testing**: Comprehensive [pytest](https://pytest.org) suite with [moto](http://docs.getmoto.org) for AWS mocking and [hypothesis](https://hypothesis.readthedocs.io) for property-based testing
- **Code Quality**: [ruff](https://docs.astral.sh/ruff) for linting and formatting, [pyright](https://microsoft.github.io/pyright) for type checking, and test coverage using [coverage](https://coverage.readthedocs.io)
- **Dependency Control**: [uv](https://docs.astral.sh/uv/) for dependency management and [Dependabot](https://docs.github.com/en/code-security/dependabot) for automated dependency updates
@@ -83,6 +84,7 @@ Parameter | Description
### Local environment
- [mise](https://mise.jdx.dev/)
+- Docker (for running LocalStack locally)
## Setup
@@ -120,9 +122,15 @@ mise run new # alias: n
This runs the `new` script, which builds a skeleton for the new template from `.template`.
+### Synthesize infrastructure
+Infrastructure is defined as AWS CDK stacks under `infra/stacks/`.
+The CDK entry point is `infra/app.py`.
+
+```bash
+mise run infra:synth [stack] # aliases: synth [stack], s [stack]
+```
+
### Deploy a stack
-Infrastructure is defined as AWS CDK stacks under `infra/stacks/`.
-The CDK entry point is `infra/app.py`.
```bash
mise run deploy # alias: d
@@ -138,6 +146,34 @@ mise run deploy --profile
mise run destroy # alias: D
```
+### Deploy a stack locally (LocalStack)
+To deploy CDK stacks locally without an AWS account:
+
+1. Copy `.env.local.example` to `.env.local` and set your auth token from [app.localstack.cloud](https://app.localstack.cloud):
+```bash
+cp .env.local.example .env.local
+```
+
+2. Start LocalStack via Docker Compose:
+```bash
+mise run local:up
+```
+
+3. Deploy the stack to LocalStack:
+```bash
+mise run local:deploy # aliases: local , dl
+```
+
+### Destroy a local stack
+```bash
+mise run local:destroy # alias: Dl
+```
+
+To stop the LocalStack container when finished:
+```bash
+mise run local:down
+```
+
### Generating documentation
To build and publish the project documentation to GitHub Pages, run:
@@ -150,7 +186,7 @@ That pushes the new documentation to the `gh-pages` branch. Make sure GitHub Pag
### Local preview
To serve the documentation on a local server, run:
```bash
-mise run local
+mise run docs-local
```
## Coding Conventions
@@ -182,7 +218,9 @@ mise run local
│ └── docs.yml # Workflow to publish documentation
├── .gitignore # Git-ignored file list
├── .pre-commit-config.yaml # Pre-commit configuration file
+├── .vibe # Feature specification
├── .vscode # VS Code folder
+├── compose.yml # Docker Compose configuration for LocalStack
├── mise.toml # mise configuration and tasks
├── pyproject.toml # Configuration file for different tools
├── mkdocs.yml # MkDocs configuration file
diff --git a/infra/app.py b/infra/app.py
index f166f46..0eb5ba8 100644
--- a/infra/app.py
+++ b/infra/app.py
@@ -23,13 +23,15 @@
stack_name = os.environ.get("STACK")
-if not stack_name:
- sys.exit("Error: STACK environment variable is not set. Valid values: " + ", ".join(STACK_REGISTRY))
+app = App()
-if stack_name not in STACK_REGISTRY:
- sys.exit(f"Error: unknown stack '{stack_name}'. Valid values: " + ", ".join(STACK_REGISTRY))
+if not stack_name or stack_name == "all":
+ for stack_class in STACK_REGISTRY.values():
+ stack_class(app, stack_class.__name__)
+elif stack_name in STACK_REGISTRY:
+ stack_class = STACK_REGISTRY[stack_name]
+ stack_class(app, stack_class.__name__)
+else:
+ sys.exit(f"Error: unknown stack '{stack_name}'. Valid values: all, " + ", ".join(STACK_REGISTRY))
-stack_class = STACK_REGISTRY[stack_name]
-app = App()
-stack_class(app, stack_class.__name__)
app.synth()
diff --git a/infra/stacks/graphql.py b/infra/stacks/graphql.py
index b842ef4..fa818b1 100644
--- a/infra/stacks/graphql.py
+++ b/infra/stacks/graphql.py
@@ -1,7 +1,8 @@
-from aws_cdk import Expiration, Stack
+from aws_cdk import Duration, Expiration, Stack
from aws_cdk.aws_appsync import (
ApiKeyConfig,
AuthorizationConfig,
+ AuthorizationMode,
AuthorizationType,
Definition,
GraphqlApi,
@@ -46,8 +47,10 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
name="AppSyncDynamodbApi",
definition=Definition.from_schema(SchemaFile.from_asset("templates/graphql/schema.graphql")),
authorization_config=AuthorizationConfig(
- default_authorization=AuthorizationType.API_KEY,
- api_key_config=ApiKeyConfig(expires=Expiration.after_days(365)),
+ default_authorization=AuthorizationMode(
+ authorization_type=AuthorizationType.API_KEY,
+ api_key_config=ApiKeyConfig(expires=Expiration.after(Duration.days(365))),
+ ),
),
)
diff --git a/mise.toml b/mise.toml
index 19ba62e..8e5d24b 100644
--- a/mise.toml
+++ b/mise.toml
@@ -20,6 +20,7 @@ l = "mise run lint"
t = "mise run test"
d = "mise run deploy"
D = "mise run destroy"
+v = "mise run verify"
c = "mise run clean"
m = "mise run"
@@ -30,6 +31,9 @@ gs = "git status"
ga = "git add"
gc = "git commit"
gp = "git push"
+gco = "git checkout"
+gb = "git branch"
+g = "git"
##### Scripts #####
@@ -53,7 +57,7 @@ flag "--github " help="GitHub username"
run = "uv run rename"
##### Dev setup and maintenance #####
-
+
[tasks.install]
description = "Install dependencies and project"
run = "uv sync"
@@ -91,9 +95,14 @@ uv run coverage xml
"""
alias = "t"
+[tasks.verify]
+description = "Run lint, test, and infra synth"
+depends = ["lint", "test", "infra:synth"]
+alias = "v"
+
[tasks.clean]
description = "Clean up build artifacts and temporary files"
-run = """rm -rf cdk.out .coverage .pytest_cache .ruff_cache .hypotheses"""
+run = """rm -rf cdk.out .coverage coverage.xml .pytest_cache .ruff_cache .hypothesis .localstack node_modules"""
alias = "c"
##### Docs #####
@@ -102,40 +111,87 @@ alias = "c"
description = "Install documentation dependencies"
run = "uv sync --group docs"
hide = true
+tools = { node = "latest" }
[tasks.docs]
description = "Build and deploy documentation to GitHub pages"
run = "uv run mkdocs gh-deploy --force"
depends = ["install-docs"]
-[tasks.local]
+[tasks.docs-local]
description = "Serve documentation on a local server"
run = "uv run mkdocs serve"
##### Infra #####
-[tasks.install-cdk]
+[tasks."infra:setup"]
description = "Install CDK dependencies"
run = "uv sync --group infra"
hide = true
-tools = { node = "latest" }
-[tasks.deploy]
+[tasks."infra:synth"]
+description = "Synthesize CDK stack(s)"
+usage = """
+arg "[stack]" help="CDK stack to synthesize"
+"""
+run = "STACK=${usage_stack:-all} npx aws-cdk synth"
+alias = ["synth", "s"]
+depends = ["infra:setup"]
+
+[tasks."infra:deploy"]
description = "Deploy a CDK stack"
usage = """
arg "" help="CDK stack to deploy"
flag "-p --profile " help="AWS profile to use"
"""
run = "STACK=$usage_stack npx aws-cdk deploy ${usage_profile:+--profile $usage_profile}"
-alias = "d"
-depends = ["install-cdk"]
+alias = ["d", "deploy"]
+depends = ["infra:synth"]
-[tasks.destroy]
+[tasks."infra:destroy"]
description = "Destroy a deployed CDK stack"
usage = """
arg "" help="CDK stack to destroy"
flag "-p --profile " help="AWS profile to use"
"""
run = "STACK=$usage_stack npx aws-cdk destroy --force ${usage_profile:+--profile $usage_profile}"
-alias = "D"
-depends = ["install-cdk"]
+alias = ["destroy", "D"]
+depends = ["infra:setup"]
+
+[tasks."local:setup"]
+description = "Install CDK dependencies in local environment"
+run = "pnpm i"
+hide = true
+tools = { node = "latest" }
+depends = ["infra:setup"]
+
+[tasks."local:deploy"]
+description = "Deploy a CDK stack to LocalStack"
+usage = """
+arg "" env=STACK help="CDK stack to deploy"
+"""
+run = "STACK=$usage_stack pnpm run deploy"
+alias = ["local"]
+depends = ["local:setup", "local:up"]
+
+[tasks."local:destroy"]
+description = "Destroy a deployed CDK stack from LocalStack"
+usage = """
+arg "" env=STACK help="CDK stack to destroy"
+"""
+run = "STACK=$usage_stack pnpm run destroy"
+depends = ["local:setup"]
+
+[tasks."local:up"]
+description = "Start LocalStack via docker compose"
+run = "docker compose up -d --wait localstack"
+
+[tasks."local:down"]
+description = "Stop LocalStack via docker compose"
+run = "docker compose down localstack"
+
+[tasks."local:deploy".env]
+_.file = ".env.local"
+
+[tasks."local:destroy".env]
+_.file = ".env.local"
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..113ce07
--- /dev/null
+++ b/package.json
@@ -0,0 +1,12 @@
+{
+ "scripts": {
+ "format": "prettier --write .",
+ "deploy": "cdklocal bootstrap && cdklocal deploy",
+ "destroy": "cdklocal destroy --force"
+ },
+ "dependencies": {
+ "aws-cdk": "^2.1133.0",
+ "aws-cdk-local": "^3.0.4",
+ "prettier": "^3.9.6"
+ }
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
new file mode 100644
index 0000000..3d392db
--- /dev/null
+++ b/pnpm-lock.yaml
@@ -0,0 +1,71 @@
+lockfileVersion: "9.0"
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+ .:
+ dependencies:
+ aws-cdk:
+ specifier: ^2.1133.0
+ version: 2.1133.0
+ aws-cdk-local:
+ specifier: ^3.0.4
+ version: 3.0.4
+ prettier:
+ specifier: ^3.9.6
+ version: 3.9.6
+
+packages:
+ aws-cdk-local@3.0.4:
+ resolution:
+ {
+ integrity: sha512-u8c62rfZNGqB9oW+RSW8YAqLLFAcgc5y2aQrgqQTBUVKLTN6r54g/IUbTq/dM1fqvT1GqtylzQjQ8ytACMSGTQ==,
+ }
+ hasBin: true
+
+ aws-cdk@2.1133.0:
+ resolution:
+ {
+ integrity: sha512-DGlCBwqxSHTe1u/IoT5WV+Bbd2K3UhwFHsdMqb2nQa1fkJmaQgoNFu0It+p3HxyMWeW+gKsVzT5KcjQPQ6Kzuw==,
+ }
+ engines: { node: ">= 18.0.0" }
+ hasBin: true
+
+ diff@5.2.2:
+ resolution:
+ {
+ integrity: sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==,
+ }
+ engines: { node: ">=0.3.1" }
+
+ prettier@3.9.6:
+ resolution:
+ {
+ integrity: sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==,
+ }
+ engines: { node: ">=14" }
+ hasBin: true
+
+ semver@7.8.5:
+ resolution:
+ {
+ integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==,
+ }
+ engines: { node: ">=10" }
+ hasBin: true
+
+snapshots:
+ aws-cdk-local@3.0.4:
+ dependencies:
+ diff: 5.2.2
+ semver: 7.8.5
+
+ aws-cdk@2.1133.0: {}
+
+ diff@5.2.2: {}
+
+ prettier@3.9.6: {}
+
+ semver@7.8.5: {}