# Core Concepts

The CLI persists a small set of artifacts and orchestrates AWS calls around them. Once you understand the artifacts and how `deploy` weaves them together, every command is obvious.

**You'll learn**

- Name the artifacts the CLI persists — manifest, lockfile, stage files, deployment ledger
- Trace how `service.name` derives every downstream AWS resource name
- Understand stages and the three forms an `env` value can take
- See how cross-repo dependencies and the ledger power `sync` and `rollback`

## The artifacts

```bash
project-root/
├── kanject-cli/
│   ├── manifest.json              ← service identity + cross-repo deps + stages
│   ├── manifest.lock.json         ← pinned commits + content hashes (sync output)
│   ├── stages/
│   │   ├── dev.json               ← per-stage region/profile/stack/bucket/env
│   │   ├── stage.json
│   │   └── prod.json
│   └── (preview.json)             ← optional: ephemeral-deployment policy
└── (s3://<artifactBucket>/_ledger/versions/*.json)   ← deployment history
```

The first five live in git so reviewers see every change. The deployment ledger lives in S3 so every deploy is auditable independently of the working copy. The per-stage `aws-lambda-tools.<stage>.json` is regenerated by `deploy` from inputs — never hand-edit it.

For every field in `manifest.json` and the stage files, see the [Manifest Reference](https://www.kanject.com/docs/manifest/).

## Service identity

`manifest.json → service.name` is the canonical identifier for everything downstream — CloudFormation stack (`{stage}-{service}`), ECR repository, artifact bucket (`{stage}-{service}-artifacts`), Parameter Store path (`/{service}/{stage}/`), and the deployment-ledger prefix all derive from it. The name is normalized: lowercase, hyphens, must start with a letter.

## Stages

A stage is a deployment target — typically `dev`, `stage`, `prod`, but the CLI doesn't care: `qa-eu`, `staging-row`, `canary` all work. Every stage in `manifest.json → aws.stages` needs a matching `kanject-cli/stages/<stage>.json` pinning region, profile, stack, artifact bucket, parameter-store path, and the `env` map.

`env` values come in three flavours:

```bash
# Plain string — baked into Lambda env config at deploy
ASPNETCORE_ENVIRONMENT=Development

# Parameter Store reference — resolved at deploy time
DATABASE_URL=param:DATABASE_URL

# Secrets Manager reference — resolved at deploy time
JWT_SIGNING_KEY=secret:kanject-analytics/dev/jwt#key
```

References are resolved **once at deploy** then baked into the Lambda function config. The Lambda runtime never calls Parameter Store / Secrets Manager — it just reads the env var. Cold-starts stay fast.

> **Security note:** Resolved values are baked into the Lambda function config — anyone with `lambda:GetFunctionConfiguration` can read them. Treat the function config as production-secret material.

## Cross-repo dependencies

Most teams have shared class libraries living in sibling repos. The traditional `<ProjectReference Include="..\..\sibling\Foo.csproj" />` works only on machines with the right relative paths — CI breaks first. Kanject's answer: declare cross-repo deps in `manifest.json → dependencies[]` with a git URL + ref + project path:

```json
"dependencies": [
  {
    "name": "Kanject.Identity.Data",
    "repository": "git@github.com:kanject/kanject-platform.git",
    "ref": "main",
    "projectPath": "services/identity/src/Kanject.Identity.Data/Kanject.Identity.Data.csproj",
    "consumers": ["src/Kanject.Analytics.Api/Kanject.Analytics.Api.csproj"]
  }
]
```

`kanject sync` resolves each ref to a SHA, clones into `.kanject/cache/<repo>-<sha>/`, pins every dependency/consumer edge in `manifest.lock.json`, and writes deterministic `kanject.g.props` / `kanject.g.targets` imports. Consumer csprojs are never edited and no local NuGet package is created.

See [Dependency Sources & Resolution](https://www.kanject.com/docs/cli-dependencies/) for the full workflow — declaring sources, the lockfile, reproducible CI, and private-repo auth.

## Deployment ledger

Every successful `kanject aws deploy` writes a JSON snapshot to `s3://<artifactBucket>/_ledger/versions/<lambda-version>.json` recording the published version ARN, timestamp + identity, commit SHA, lockfile hash, and per-env-value hashes. A pointer at `_ledger/current.json` tracks the latest entry.

The ledger is the source of truth for **audit** and **rollback** — `kanject aws rollback` reads it and flips the alias to a prior immutable artifact without rebuilding. The ledger is append-only; rollback writes a new entry.

## What kanject does NOT own

- `dotnet new` — kanject calls it, doesn't replace it. Templates are a separate NuGet pack.
- `dotnet build` / `dotnet test` — vanilla. The CLI doesn't proxy them.
- `dotnet lambda deploy-serverless` — the deploy backend. Kanject sets up inputs, then calls the AWS-supplied tool.
- Your CloudFormation template — kanject orchestrates the deploy, but `serverless.template` is yours.
- Your CI provider — `pipeline init` scaffolds CodePipeline; if you want GitHub Actions or GitLab, you write the workflow.
- Your code — kanject never edits anything in `src/`.

**Recap**

- The CLI persists a small artifact set in git, plus an append-only deployment ledger in S3.
- `manifest.json → service.name` is the canonical id every AWS resource name derives from.
- `env` values are plain strings, `param:` references, or `secret:` references — resolved once at deploy, then baked into Lambda config.
- `sync` turns cross-repo `<ProjectReference>`s into pinned packages; the ledger powers audit and alias-flip `rollback`.

---
_Source: https://www.kanject.com/docs/concepts/ · Kanject Docs_
