<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Juhani Ränkimies</title>
    <description>The latest articles on DEV Community by Juhani Ränkimies (@juranki).</description>
    <link>https://dev.to/juranki</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F457674%2F5dd93da4-601b-472a-a852-6fdba83a18da.jpeg</url>
      <title>DEV Community: Juhani Ränkimies</title>
      <link>https://dev.to/juranki</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/juranki"/>
    <language>en</language>
    <item>
      <title>Change Management When Specs Are Living Documents</title>
      <dc:creator>Juhani Ränkimies</dc:creator>
      <pubDate>Mon, 09 Mar 2026 19:43:48 +0000</pubDate>
      <link>https://dev.to/juranki/change-management-when-specs-are-living-documents-1mjb</link>
      <guid>https://dev.to/juranki/change-management-when-specs-are-living-documents-1mjb</guid>
      <description>&lt;p&gt;If your spec is the source of truth, what happens when the truth needs to change?&lt;/p&gt;

&lt;p&gt;This is the question most spec-first approaches handle poorly. Either the spec becomes stale (everyone ignores it after the first sprint), or updating it becomes ceremony (three documents to change before you can write a line of code). Both failure modes kill the approach.&lt;/p&gt;

&lt;p&gt;Living specs need living change management. But the change management has to be lightweight enough that developers actually use it, and structured enough that AI can reason about what's happening.&lt;/p&gt;

&lt;p&gt;There's a third failure mode that's less obvious: &lt;strong&gt;coupling work breakdown to specs.&lt;/strong&gt; Most spec-first approaches do this -- user stories have subtasks, BDD features have scenarios that double as work items, spec documents accumulate task lists. This works for the initial build when one team writes one spec and implements it. It breaks when the spec is a living document.&lt;/p&gt;

&lt;p&gt;A living spec gets touched by multiple changes over time. CR-001 adds acceptance criteria. CR-007 modifies one of them. CR-012 deprecates another. Each change has its own scope, its own tasks, its own timeline. If tasks live on the spec, you end up with competing task lists from different changes colliding on the same document. The spec becomes a project management artifact instead of a contract.&lt;/p&gt;

&lt;p&gt;The fix is recognizing that specs and change management are &lt;strong&gt;orthogonal concerns:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;spec&lt;/strong&gt; defines what must be true (current contract)&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;change record&lt;/strong&gt; defines what's changing and why (delta)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tasks&lt;/strong&gt; belong to the change, not the spec&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This separation is why change records in this approach live in their own folders (&lt;code&gt;changes/CR-001-slug/&lt;/code&gt;) with their own task breakdowns, rather than being embedded in or attached to spec documents. A spec can be touched by many changes. A change can touch many specs. Neither owns the other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why git history isn't enough
&lt;/h2&gt;

&lt;p&gt;The instinctive response is: "We have git. Changes are tracked. What more do we need?"&lt;/p&gt;

&lt;p&gt;Git history tracks &lt;em&gt;what&lt;/em&gt; changed. It doesn't track:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why&lt;/strong&gt; the change was made&lt;/li&gt;
&lt;li&gt;Whether the change was &lt;strong&gt;intentional or accidental&lt;/strong&gt; drift&lt;/li&gt;
&lt;li&gt;Which &lt;strong&gt;contract&lt;/strong&gt; (behavioral commitment) was affected&lt;/li&gt;
&lt;li&gt;Whether &lt;strong&gt;proof obligations&lt;/strong&gt; changed&lt;/li&gt;
&lt;li&gt;What the &lt;strong&gt;migration or compatibility&lt;/strong&gt; implications are&lt;/li&gt;
&lt;li&gt;Whether this change is &lt;strong&gt;part of a larger effort&lt;/strong&gt; or standalone&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a human reads a git log, they can sometimes reconstruct this from commit messages and PR descriptions. When AI reads a git log, it gets a sequence of diffs with variable-quality commentary. It has no reliable way to distinguish "intentional contract change" from "implementation refactor" from "accidental behavior change."&lt;/p&gt;

&lt;p&gt;Explicit change records solve this by classifying intent alongside implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The change record
&lt;/h2&gt;

&lt;p&gt;A change record is a lightweight document that captures what's changing and why. It lives in its own folder alongside optional supporting material:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docs/changes/
  CR-001-repository-bootstrap/
    change.md
    tasks.md          # optional: implementation breakdown
  CR-002-quality-baseline/
    change.md
    tasks.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each change record covers problem, motivation, scope (in/out), proposed contract delta, affected artifacts, and risks. It also classifies the change -- is this adding new behavior, modifying existing behavior, or an internal quality improvement? Is it breaking for consumers? Does it deprecate something? These classifications let both humans and AI reason quickly about impact without reading the full record.&lt;/p&gt;

&lt;h2&gt;
  
  
  When is a change record required?
&lt;/h2&gt;

&lt;p&gt;Not every commit needs a change record. The overhead would kill adoption. The rule is a six-question test:&lt;/p&gt;

&lt;p&gt;A change record is required if &lt;strong&gt;any&lt;/strong&gt; answer is yes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does public or externally observable behavior change?&lt;/li&gt;
&lt;li&gt;Does any acceptance criterion change, get added, removed, or deprecated?&lt;/li&gt;
&lt;li&gt;Do proof obligations change materially?&lt;/li&gt;
&lt;li&gt;Does the implementation introduce a new component, boundary crossing, runtime dependency, or integration?&lt;/li&gt;
&lt;li&gt;Does responsibility move between modules or layers in a way future work must understand?&lt;/li&gt;
&lt;li&gt;Does rollout, migration, or compatibility handling need explicit coordination?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If all answers are no, it's a simple fix. Fix it, commit it, move on.&lt;/p&gt;

&lt;p&gt;Examples of simple fixes that don't need a CR:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Typo or comment correction&lt;/li&gt;
&lt;li&gt;Bug fix that restores already-specified behavior within the same module&lt;/li&gt;
&lt;li&gt;Local performance improvement with no contract or structure change&lt;/li&gt;
&lt;li&gt;Test stabilization when the proof obligation itself doesn't change&lt;/li&gt;
&lt;li&gt;Logging improvement within an existing flow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples of small changes that still need a CR:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adding a new config flag visible to consumers&lt;/li&gt;
&lt;li&gt;Changing timeout behavior that users can feel&lt;/li&gt;
&lt;li&gt;Introducing a new database table or integration&lt;/li&gt;
&lt;li&gt;Splitting logic into a new module that changes responsibility boundaries&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The change package as workbench
&lt;/h2&gt;

&lt;p&gt;Here's where the approach differs from traditional change management.&lt;/p&gt;

&lt;p&gt;During active implementation, the change record is the &lt;strong&gt;workbench&lt;/strong&gt; -- the central coordination surface. But the spec and verification map move &lt;em&gt;ahead&lt;/em&gt; to the target state before implementation catches up.&lt;/p&gt;

&lt;p&gt;The sequence:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create the change record.&lt;/strong&gt; Document what's changing and why.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Update spec.md to the target state.&lt;/strong&gt; The spec now describes what the system &lt;em&gt;should&lt;/em&gt; do after the change, not what it currently does. This intentionally creates a temporary mismatch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Update verification.yaml.&lt;/strong&gt; The proof map reflects the new contract. Some tests don't exist yet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write or update tests.&lt;/strong&gt; Tests align with the new spec. They may fail because the old implementation doesn't satisfy the new contract.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implement.&lt;/strong&gt; Make the tests pass.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify.&lt;/strong&gt; All tests pass, all quality gates pass.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Re-establish alignment.&lt;/strong&gt; Confirm that specs, verification map, tests, and implementation all agree.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The key insight: &lt;strong&gt;specs move first.&lt;/strong&gt; The living spec represents the intended target contract during active work, not the current implementation state. The change record tracks what's in flight. When the change completes, everything realigns.&lt;/p&gt;

&lt;p&gt;This avoids the two common failure modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spec becomes stale (can't happen -- spec moves &lt;em&gt;before&lt;/em&gt; code)&lt;/li&gt;
&lt;li&gt;Spec change feels like ceremony (it's part of the change flow, not separate from it)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Temporary misalignment is intentional
&lt;/h2&gt;

&lt;p&gt;This point deserves emphasis because it's counterintuitive.&lt;/p&gt;

&lt;p&gt;In the middle of a change, the spec says one thing and the implementation does another. Tests may be failing. That's fine. The change record exists to track this in-progress state. The spec is the target, not a description of current reality.&lt;/p&gt;

&lt;p&gt;The rule is: &lt;strong&gt;temporary in-progress misalignment can be acceptable. Done means alignment is restored.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This only works with discipline. The change must close. Alignment must be verified. Specs that moved ahead but never got implemented are drift, not progress.&lt;/p&gt;

&lt;h2&gt;
  
  
  A real example
&lt;/h2&gt;

&lt;p&gt;From the SitePilot2 bootstrap, CR-002 (development quality baseline) shows this pattern in a real change:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Even with a Rust project in place, contributors lack a shared local workflow. Quality expectations are documented but not enforceable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Proposed contract delta:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Spec delta:&lt;/em&gt; The repository gains an explicit local development workflow. Quality policy documentation changes from hypothetical commands to actual baseline commands. The repository baseline includes a Bun-first Playwright toolchain for browser proof.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Verification delta:&lt;/em&gt; Add proof that documented local commands execute successfully. Add proof that quality and tech-stack docs reflect the implemented toolchain. Add proof that sample Playwright tests pass.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;What happened:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Playwright scaffolding was added&lt;/li&gt;
&lt;li&gt;CI workflow was created running all quality checks&lt;/li&gt;
&lt;li&gt;Local developer commands were defined and documented&lt;/li&gt;
&lt;li&gt;quality-policy.md was updated from aspirational to actual&lt;/li&gt;
&lt;li&gt;docs/tech-stack.md was updated to reflect real tooling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Status log:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2026-03-08 - created
2026-03-08 - activated: Playwright baseline scaffolding added
2026-03-08 - updated: normalized CI to Bun-based installation
2026-03-08 - updated: defined canonical Cargo commands and Bun wrappers
2026-03-08 - updated: expanded CI to run full quality baseline
2026-03-08 - verified: all docs synchronized, bun run verify passes
2026-03-08 - merged
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each status log entry is a sentence. The whole change record is readable in two minutes. But it captures intent, scope, contract delta, and verification in a way that git history alone never would.&lt;/p&gt;

&lt;h2&gt;
  
  
  Branch alignment
&lt;/h2&gt;

&lt;p&gt;Branches map one-to-one to change records:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One CR -&amp;gt; one branch&lt;/li&gt;
&lt;li&gt;One branch -&amp;gt; one PR&lt;/li&gt;
&lt;li&gt;One PR -&amp;gt; one observable contract delta&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Naming convention: &lt;code&gt;cr/001-repository-bootstrap&lt;/code&gt;, &lt;code&gt;cr/002-development-quality-baseline&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This keeps spec changes, proof changes, and code changes visible as one coherent unit. A PR reviewer can look at the change record to understand what contract delta they're reviewing, rather than trying to reconstruct intent from diffs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mixed-change escalation
&lt;/h2&gt;

&lt;p&gt;Sometimes work starts as a simple fix and expands. You're fixing a bug, and you realize the fix requires changing an acceptance criterion. Or you're refactoring, and you discover the module boundary needs to move.&lt;/p&gt;

&lt;p&gt;The rule: if work starts as a simple fix but expands into contract or structural change:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Stop treating it as exempt&lt;/li&gt;
&lt;li&gt;Create a CR immediately&lt;/li&gt;
&lt;li&gt;Capture the already-discovered delta&lt;/li&gt;
&lt;li&gt;Continue only after readiness is re-evaluated if the new scope is material&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This prevents the common pattern where "quick fixes" silently evolve into undocumented contract changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Supporting artifacts
&lt;/h2&gt;

&lt;p&gt;Not every change needs the same documentation depth. Trigger rules keep overhead proportional to complexity:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;design.md is mandatory when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More than one viable implementation approach exists&lt;/li&gt;
&lt;li&gt;A new dependency, component, or architectural boundary is introduced&lt;/li&gt;
&lt;li&gt;The change spans multiple feature packages&lt;/li&gt;
&lt;li&gt;A security, performance, or reliability tradeoff must be chosen&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;tasks.md is mandatory when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implementation requires more than three dependent steps&lt;/li&gt;
&lt;li&gt;Rollout or migration must happen in sequence&lt;/li&gt;
&lt;li&gt;Multiple specs must change in a controlled order&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;ADR input is mandatory when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The change revisits a durable technology choice&lt;/li&gt;
&lt;li&gt;The change alters a cross-cutting architectural rule&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Simple additive changes may need only &lt;code&gt;change.md&lt;/code&gt;. Complex cross-cutting changes may need all supporting artifacts. The trigger rules prevent both under-documentation and over-documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this costs
&lt;/h2&gt;

&lt;p&gt;Honest accounting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A simple change record takes ~10 minutes to write&lt;/li&gt;
&lt;li&gt;A complex one with tasks.md takes ~30 minutes&lt;/li&gt;
&lt;li&gt;Updating specs before implementation takes ~5-15 minutes depending on the change&lt;/li&gt;
&lt;li&gt;Re-establishing alignment at the end takes ~5 minutes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Against this: every future developer (human or AI) who touches the affected feature can understand what changed, why, and how the contract evolved. The audit trail is explicit, not reconstructed from git archaeology.&lt;/p&gt;

&lt;p&gt;The tradeoff sharpens when AI is doing most of the implementation. AI can generate code in seconds. The bottleneck is ensuring that code satisfies the right contract. Change records make the contract explicit. Without them, you're back to reviewing diffs and hoping you can reconstruct intent -- which is the trust problem from &lt;a href="//01-trust-problem.md"&gt;Part 1&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Drift: the real enemy
&lt;/h2&gt;

&lt;p&gt;The biggest risk to living specs isn't that they change -- it's that they drift. Code changes without spec updates. Tests pass but don't cover new behavior. Quality gates exist but aren't enforced.&lt;/p&gt;

&lt;p&gt;Drift is silent. Each individual change is small enough to ignore. Over weeks, the spec describes a system that doesn't exist anymore.&lt;/p&gt;

&lt;p&gt;Detection examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Acceptance criteria with no linked tests&lt;/li&gt;
&lt;li&gt;Tests tagged to deleted criteria&lt;/li&gt;
&lt;li&gt;Behavior changes with no spec or change-record update&lt;/li&gt;
&lt;li&gt;Quality checks required by policy but absent in CI&lt;/li&gt;
&lt;li&gt;ADR commitments violated by module structure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some drift can be caught deterministically (missing test linkage, absent CI checks). Some requires judgment (does this behavior change constitute a contract change?). The approach uses automation where possible and review questions where not.&lt;/p&gt;

&lt;p&gt;The PR review checklist makes this concrete:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Did the contract change? If yes, where is the change record?&lt;/li&gt;
&lt;li&gt;Did acceptance criteria change? If yes, where is the updated proof mapping?&lt;/li&gt;
&lt;li&gt;Does the implementation satisfy the updated contract without introducing undocumented behavior?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These questions are as important when reviewing AI-generated PRs as human-generated ones. More important, arguably, because AI doesn't flag its own contract violations.&lt;/p&gt;

</description>
      <category>ai</category>
    </item>
    <item>
      <title>Bootstrapping a Project with AI and Specs</title>
      <dc:creator>Juhani Ränkimies</dc:creator>
      <pubDate>Mon, 09 Mar 2026 19:42:19 +0000</pubDate>
      <link>https://dev.to/juranki/bootstrapping-a-project-with-ai-and-specs-2om8</link>
      <guid>https://dev.to/juranki/bootstrapping-a-project-with-ai-and-specs-2om8</guid>
      <description>&lt;p&gt;Theory is useful. Seeing it work on a real project is better.&lt;/p&gt;

&lt;p&gt;This post walks through bootstrapping a project using spec-driven development with AI tooling. The project is real -- a SaaS product called SitePilot2 -- and the artifacts shown are the actual artifacts generated during the bootstrap. Nothing has been cleaned up for presentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The starting point
&lt;/h2&gt;

&lt;p&gt;An empty repository. A product idea. An AI assistant (OpenCode with GPT 5.4) as the primary development tool.&lt;/p&gt;

&lt;p&gt;The goal: establish a project baseline where AI has enough structured context to work reliably on future features, with change management and quality enforcement in place before writing any product code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Bootstrap the artifact structure
&lt;/h2&gt;

&lt;p&gt;The first action isn't writing code. It's creating the context documents that AI will need for every future task.&lt;/p&gt;

&lt;p&gt;A custom command (&lt;code&gt;/sdd-init&lt;/code&gt;) handles this. It inspects the repository, discovers what exists, and creates the minimal artifact structure. The command follows explicit rules:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If &lt;code&gt;docs/changes/&lt;/code&gt; or &lt;code&gt;docs/specs/&lt;/code&gt; exists, use &lt;code&gt;docs/&lt;/code&gt; as the artifact root&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;changes/&lt;/code&gt; or &lt;code&gt;specs/&lt;/code&gt; exists at the repo root, use the repo root&lt;/li&gt;
&lt;li&gt;Otherwise, create under &lt;code&gt;docs/&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For a fresh project, this produces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docs/
  product.md
  structure.md
  tech-stack.md
  architecture.md
  quality-policy.md
  specs/
  changes/
  planning/
  adr/
  .templates/
    spec.md
    verification.yaml
    planning-item.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The AI populates these based on what it can discover. For a new project, most content is placeholder. For an existing project, it reads package files, source code, CI config, and fills in what it finds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Fill in product context
&lt;/h2&gt;

&lt;p&gt;The AI generates an initial product.md from a conversation about the product. Here's what came out for SitePilot2:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Product: SitePilot2&lt;/span&gt;

&lt;span class="gu"&gt;## What&lt;/span&gt;

SitePilot2 is a SaaS product that helps non-technical business owners 
create and maintain professional business websites without external 
implementation help.

&lt;span class="gu"&gt;## For Whom&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Solo entrepreneurs operating locally
&lt;span class="p"&gt;-&lt;/span&gt; Small agencies serving local clients
&lt;span class="p"&gt;-&lt;/span&gt; Small teams that need multiple collaborators to maintain one or 
  more business websites

&lt;span class="gu"&gt;## Key User Problems&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; Launching a website is difficult for non-technical owners.
&lt;span class="p"&gt;2.&lt;/span&gt; Ongoing maintenance is neglected because the team lacks web skills.
&lt;span class="p"&gt;3.&lt;/span&gt; Long periods without updates lead to costly re-implementation 
   instead of incremental improvement.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isn't documentation for documentation's sake. Every time AI touches this project in the future, it can load this file and know: simplicity for non-technical users is the primary constraint. That single piece of context prevents an entire class of over-engineering decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Make architecture decisions explicit
&lt;/h2&gt;

&lt;p&gt;Before writing any code, twelve ADRs were created to capture key decisions:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ADR&lt;/th&gt;
&lt;th&gt;Decision&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ADR-001&lt;/td&gt;
&lt;td&gt;Backend-driven UI with Datastar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ADR-002&lt;/td&gt;
&lt;td&gt;Hexagonal backend architecture&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ADR-003&lt;/td&gt;
&lt;td&gt;Site-centered tenancy and collaboration model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ADR-004&lt;/td&gt;
&lt;td&gt;Passwordless email OTP authentication for v1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ADR-005&lt;/td&gt;
&lt;td&gt;Defer Rust web framework selection until Datastar spike&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ADR-007&lt;/td&gt;
&lt;td&gt;Playwright for UI interaction proof&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ADR-008&lt;/td&gt;
&lt;td&gt;HTML-first server rendering with reusable fragments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ADR-009&lt;/td&gt;
&lt;td&gt;AWS SES for email delivery via port/adapter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ADR-010&lt;/td&gt;
&lt;td&gt;Minimal role-based access model for v1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ADR-011&lt;/td&gt;
&lt;td&gt;Security scanning baseline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ADR-012&lt;/td&gt;
&lt;td&gt;Analytics via pluggable site-level integration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Some are accepted. Some are proposed. ADR-005 explicitly defers a decision (framework selection) until evidence from a spike is available.&lt;/p&gt;

&lt;p&gt;The point: when AI later implements authentication, it loads ADR-004 and knows the decision is email OTP, not passwords. When it structures code, ADR-002 tells it hexagonal architecture. These aren't suggestions in a long design doc -- they're discrete, loadable decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Plan the work
&lt;/h2&gt;

&lt;p&gt;Five planning items were created to sequence the bootstrap:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;PLN&lt;/th&gt;
&lt;th&gt;Goal&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PLN-001&lt;/td&gt;
&lt;td&gt;Establish working Rust project and local workflows&lt;/td&gt;
&lt;td&gt;Done&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PLN-002&lt;/td&gt;
&lt;td&gt;Framework selection spike (Datastar compatibility)&lt;/td&gt;
&lt;td&gt;Active&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PLN-003&lt;/td&gt;
&lt;td&gt;Authentication (email OTP)&lt;/td&gt;
&lt;td&gt;Proposed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PLN-004&lt;/td&gt;
&lt;td&gt;First-time site creation and onboarding&lt;/td&gt;
&lt;td&gt;Proposed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PLN-005&lt;/td&gt;
&lt;td&gt;Ongoing site management&lt;/td&gt;
&lt;td&gt;Proposed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Planning items aren't feature specs. They answer "what work is worth doing and in what order" -- a different question from "what must this feature do." PLN-001 and PLN-002 must complete before feature work starts. PLN-003 through PLN-005 are sequenced by dependency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Execute through change records
&lt;/h2&gt;

&lt;p&gt;Now implementation begins -- but through change records, not ad-hoc coding.&lt;/p&gt;

&lt;h3&gt;
  
  
  CR-001: Repository bootstrap
&lt;/h3&gt;

&lt;p&gt;The first change record creates the Rust project baseline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CR-001&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;repository bootstrap&lt;/span&gt;
&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;implemented&lt;/span&gt;
&lt;span class="na"&gt;change_type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;additive&lt;/span&gt;
&lt;span class="na"&gt;branch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cr/001-repository-bootstrap&lt;/span&gt;
&lt;span class="na"&gt;planning&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PLN-001&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scope is explicit:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In scope:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create initial Rust project structure&lt;/li&gt;
&lt;li&gt;Add a minimal runnable binary&lt;/li&gt;
&lt;li&gt;Add initial test layout and smoke test&lt;/li&gt;
&lt;li&gt;Update structure documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Out of scope:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web framework selection&lt;/li&gt;
&lt;li&gt;Real product features&lt;/li&gt;
&lt;li&gt;Production deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The implementation was minimal by design:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Cargo.toml&lt;/code&gt;: Standard binary project, no dependencies&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;src/main.rs&lt;/code&gt;: Placeholder with comments indicating future architecture&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tests/smoke_test.rs&lt;/code&gt;: Integration test verifying the binary builds and runs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/structure.md&lt;/code&gt;: Updated to reflect actual state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A branch &lt;code&gt;cr/001-repository-bootstrap&lt;/code&gt; was created, a PR opened, and the change merged. The change record documents what happened and why.&lt;/p&gt;

&lt;h3&gt;
  
  
  CR-002: Development quality baseline
&lt;/h3&gt;

&lt;p&gt;The second change record establishes the quality enforcement baseline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CR-002&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;development quality baseline&lt;/span&gt;
&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;merged&lt;/span&gt;
&lt;span class="na"&gt;change_type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;internal-quality&lt;/span&gt;
&lt;span class="na"&gt;branch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cr/002-development-quality-baseline&lt;/span&gt;
&lt;span class="na"&gt;planning&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PLN-001&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This change:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Added Playwright scaffolding with Bun as package manager&lt;/li&gt;
&lt;li&gt;Created CI workflow running rustfmt, clippy, cargo check, cargo test, and Playwright&lt;/li&gt;
&lt;li&gt;Defined local developer commands (&lt;code&gt;bun run verify&lt;/code&gt; chains all checks)&lt;/li&gt;
&lt;li&gt;Documented environment conventions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The quality-policy.md was updated from aspirational to actual:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Mandatory Automated Checks&lt;/span&gt;

&lt;span class="gu"&gt;### Formatting&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Tool**&lt;/span&gt;: &lt;span class="sb"&gt;`rustfmt`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Command**&lt;/span&gt;: &lt;span class="sb"&gt;`cargo fmt --all -- --check`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**When**&lt;/span&gt;: On every pull request and before merge

&lt;span class="gu"&gt;### Linting&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Tool**&lt;/span&gt;: &lt;span class="sb"&gt;`clippy`&lt;/span&gt;  
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Command**&lt;/span&gt;: &lt;span class="sb"&gt;`cargo clippy --all-targets --all-features -- -D warnings`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**When**&lt;/span&gt;: On every pull request and before merge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After CR-002 merged, every future change has automated quality enforcement. The system verification lane from &lt;a href="//01-trust-problem.md"&gt;Part 1&lt;/a&gt; is operational.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the bootstrap produced
&lt;/h2&gt;

&lt;p&gt;After two change records and one day of work, the project has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Product context&lt;/strong&gt; that AI can load to understand what the system is for&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Engineering context&lt;/strong&gt; (structure, tech stack, architecture, quality policy) that tells AI how to operate safely&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;12 ADRs&lt;/strong&gt; capturing decisions AI needs to respect&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;5 planning items&lt;/strong&gt; sequencing future work&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2 completed change records&lt;/strong&gt; with full audit trail&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI pipeline&lt;/strong&gt; enforcing formatting, linting, type checking, tests, and browser proof&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Templates&lt;/strong&gt; for future specs, verification maps, and planning items&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the actual implementation? A placeholder binary and a smoke test. Almost no code.&lt;/p&gt;

&lt;p&gt;That's the point. The value of the bootstrap isn't code -- it's context and infrastructure. When the first real feature gets implemented, AI starts with structured knowledge about the product, architecture, tech choices, and quality requirements. It doesn't start cold.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the AI did vs. what I did
&lt;/h2&gt;

&lt;p&gt;Being honest about the division of labor:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI generated:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Initial drafts of all context documents (product.md, structure.md, tech-stack.md, architecture.md, quality-policy.md)&lt;/li&gt;
&lt;li&gt;ADR drafts based on architectural discussions&lt;/li&gt;
&lt;li&gt;Change record structure and content&lt;/li&gt;
&lt;li&gt;Cargo project scaffolding&lt;/li&gt;
&lt;li&gt;Playwright setup and CI workflow&lt;/li&gt;
&lt;li&gt;Documentation updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;I did:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Decided what the product is and who it's for&lt;/li&gt;
&lt;li&gt;Made architectural decisions (hexagonal, Datastar, OTP)&lt;/li&gt;
&lt;li&gt;Reviewed and corrected AI-generated artifacts&lt;/li&gt;
&lt;li&gt;Decided the sequencing (what to do first, what to defer)&lt;/li&gt;
&lt;li&gt;Decided when to stop (minimal bootstrap, not over-designed)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The human role was contract design and judgment. The AI role was execution and documentation. This is the division of labor from &lt;a href="//01-trust-problem.md"&gt;Part 1&lt;/a&gt; playing out in practice.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's missing
&lt;/h2&gt;

&lt;p&gt;Two things this bootstrap deliberately doesn't have yet:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;No feature specs.&lt;/strong&gt; The &lt;code&gt;docs/specs/&lt;/code&gt; directory is empty. Feature specs arrive when feature work begins (starting with PLN-002's framework spike and then PLN-003's authentication).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No filled verification maps.&lt;/strong&gt; Templates exist, but no concrete spec-to-test mapping because there are no features to map yet.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These aren't gaps -- they're sequencing. The bootstrap establishes context and infrastructure. Features build on that foundation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The cost
&lt;/h2&gt;

&lt;p&gt;Total overhead for the documentation approach versus just coding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;~1 hour for initial context documents (product, structure, tech stack, architecture, quality policy)&lt;/li&gt;
&lt;li&gt;~30 minutes per ADR (most were quick decisions with clear rationale)&lt;/li&gt;
&lt;li&gt;~15 minutes per change record (problem, scope, verification delta)&lt;/li&gt;
&lt;li&gt;~15 minutes per planning item&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a bootstrap that took about a day total, roughly half was documentation and half was implementation. That ratio will shrink as features get built -- context documents are a one-time investment, and change records for feature work are smaller than bootstrap scaffolding.&lt;/p&gt;

&lt;p&gt;Whether that investment pays off depends on what comes next. If the project dies after bootstrap, it was wasted ceremony. If it grows into a real product with months of AI-assisted development, the context documents will save far more time than they cost.&lt;/p&gt;

</description>
      <category>ai</category>
    </item>
    <item>
      <title>What AI Needs to Know (and What It Doesn't)</title>
      <dc:creator>Juhani Ränkimies</dc:creator>
      <pubDate>Mon, 09 Mar 2026 19:41:15 +0000</pubDate>
      <link>https://dev.to/juranki/what-ai-needs-to-know-and-what-it-doesnt-imi</link>
      <guid>https://dev.to/juranki/what-ai-needs-to-know-and-what-it-doesnt-imi</guid>
      <description>&lt;p&gt;Ask an AI coding assistant to implement a feature. Give it access to your whole codebase. Watch what happens.&lt;/p&gt;

&lt;p&gt;It reads too much. Or too little. It picks up conventions from one module and applies them where they don't belong. It misses architectural boundaries because they're implicit. It generates code that works but doesn't fit because it lacks context about &lt;em&gt;why&lt;/em&gt; the system is shaped the way it is.&lt;/p&gt;

&lt;p&gt;The problem isn't AI capability. It's context management.&lt;/p&gt;

&lt;h2&gt;
  
  
  The context problem
&lt;/h2&gt;

&lt;p&gt;AI agents don't understand your system the way a developer who's worked on it for months does. A tenured developer has absorbed product intent, architectural constraints, technology choices, module boundaries, and unwritten conventions through osmosis. They know what matters without being told.&lt;/p&gt;

&lt;p&gt;AI has none of this ambient knowledge. Every session starts cold. What the AI can work with is exactly what you give it -- no more, no less.&lt;/p&gt;

&lt;p&gt;This creates two failure modes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Too much context.&lt;/strong&gt; Dump the entire repo into the prompt and the AI drowns. It can't distinguish product requirements from implementation details, current conventions from legacy code, stable architecture from experimental branches. Signal gets lost in noise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Too little context.&lt;/strong&gt; Point the AI at a single file and it works in a vacuum. It makes locally reasonable decisions that violate global constraints. It duplicates utilities that already exist. It breaks architectural rules it doesn't know about.&lt;/p&gt;

&lt;p&gt;The sweet spot is &lt;strong&gt;selective context loading&lt;/strong&gt;: give the AI exactly the knowledge it needs for the task at hand, organized so each document answers one clear question.&lt;/p&gt;

&lt;h2&gt;
  
  
  A layered knowledge model
&lt;/h2&gt;

&lt;p&gt;The approach that works in practice organizes project knowledge into layers, each serving a different purpose. When the AI needs to implement a feature, you don't give it everything -- you load the layers relevant to that task.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 1: Product context
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What question it answers:&lt;/strong&gt; What is this product and who is it for?&lt;/p&gt;

&lt;p&gt;This is the document most teams skip and AI most needs. It captures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What the product does&lt;/li&gt;
&lt;li&gt;Who the users are&lt;/li&gt;
&lt;li&gt;What problems it solves&lt;/li&gt;
&lt;li&gt;What's explicitly out of scope&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without this, AI makes product decisions by inference. It guesses at user intent from code patterns. Sometimes it guesses right. Often it doesn't.&lt;/p&gt;

&lt;p&gt;A real example from a project bootstrapped with this approach:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;SitePilot2 is a SaaS product that helps non-technical business owners create and maintain professional business websites without external implementation help. It combines AI-assisted onboarding, guided content generation, and ongoing site maintenance workflows.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Three sentences. Enough for an AI to know that "simplicity for non-technical users" is the product constraint, not "flexibility for developers."&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 2: Engineering context
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What question it answers:&lt;/strong&gt; How do I operate safely inside this repository?&lt;/p&gt;

&lt;p&gt;Four documents cover this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;structure.md&lt;/strong&gt; -- where code goes, what modules do, dependency boundaries. When AI needs to add a new handler, it knows to put it in &lt;code&gt;src/infrastructure/&lt;/code&gt; not &lt;code&gt;src/domain/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;tech-stack.md&lt;/strong&gt; -- approved technologies, preferred libraries, forbidden choices. Prevents AI from pulling in a new ORM when one is already chosen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;architecture.md&lt;/strong&gt; -- high-level system shape, components, data flow. Tells AI that the system uses hexagonal architecture &lt;em&gt;before&lt;/em&gt; it generates code that couples the domain to the HTTP framework.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;quality-policy.md&lt;/strong&gt; -- mandatory automated checks and how to run them. AI knows it needs to pass rustfmt, clippy, and cargo test -- not just make the feature work.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Layer 3: Feature package
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What question it answers:&lt;/strong&gt; What exactly must this feature do?&lt;/p&gt;

&lt;p&gt;This is where the spec-driven approach from &lt;a href="//01-trust-problem.md"&gt;Part 1&lt;/a&gt; lives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;spec.md&lt;/strong&gt; -- problem, user story, acceptance criteria with stable IDs, invariants, non-goals.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;verification.yaml&lt;/strong&gt; -- maps each acceptance criterion to specific tests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;design.md&lt;/strong&gt; (optional) -- explains how a non-trivial solution will satisfy the contract.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key distinction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;spec.md&lt;/code&gt; defines what must be true&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;verification.yaml&lt;/code&gt; defines how that truth is proven&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;design.md&lt;/code&gt; explains how the solution works&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These live together because they describe the same feature from different angles. An AI implementing that feature needs all three; an AI working on a different feature needs none of them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 4: Technical decisions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What question it answers:&lt;/strong&gt; Why was this decision made, and what are the consequences?&lt;/p&gt;

&lt;p&gt;Architecture Decision Records (ADRs) capture decisions that are expensive to revisit: framework choices, authentication strategies, data model commitments. They record the decision, alternatives considered, rationale, and consequences.&lt;/p&gt;

&lt;p&gt;ADRs are not the whole design system. They capture &lt;em&gt;why&lt;/em&gt;, not the full current shape. But when AI is about to make a decision that conflicts with an existing ADR, having that context loaded prevents costly mistakes.&lt;/p&gt;

&lt;p&gt;A project might have ADRs like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ADR-001: Backend-driven UI with Datastar&lt;/li&gt;
&lt;li&gt;ADR-002: Hexagonal backend architecture&lt;/li&gt;
&lt;li&gt;ADR-004: Passwordless email OTP authentication for v1&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When AI starts implementing authentication, loading ADR-004 tells it the decision is OTP via email, not passwords. Without that context, it defaults to whatever pattern is most common in its training data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 5: Change management
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What question it answers:&lt;/strong&gt; What is changing and why?&lt;/p&gt;

&lt;p&gt;Change records track how the system evolves. They're separate from specs because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;spec.md&lt;/code&gt; is current truth -- what the system must do right now&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;change.md&lt;/code&gt; is historical delta -- what's changing, why, and what it affects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This distinction matters for AI because it prevents a common failure: AI reading a change record and treating a &lt;em&gt;proposed&lt;/em&gt; change as the &lt;em&gt;current&lt;/em&gt; contract, or reading an old change record and implementing something that's already been superseded.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 6: Planning
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What question it answers:&lt;/strong&gt; What work is worth doing and in what order?&lt;/p&gt;

&lt;p&gt;Planning items describe goals, priorities, and sequencing. AI needs this when selecting or proposing work, but not when implementing an already-defined feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the split matters
&lt;/h2&gt;

&lt;p&gt;If these concerns are collapsed into one large design document, agents either miss important context or load too much irrelevant material.&lt;/p&gt;

&lt;p&gt;The split lets agents load only what they need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Product intent when defining behavior&lt;/li&gt;
&lt;li&gt;Repo structure when editing code&lt;/li&gt;
&lt;li&gt;Tech constraints when choosing tools&lt;/li&gt;
&lt;li&gt;The specific feature package when implementing behavior&lt;/li&gt;
&lt;li&gt;ADRs when a decision touches an existing architectural commitment&lt;/li&gt;
&lt;li&gt;Change records when evaluating whether behavior is intentionally changing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn't just theory. In practice, the difference between "implement this feature given the whole codebase" and "implement this feature given the spec, the architecture doc, the structure guide, and the tech stack" is the difference between fighting the AI and collaborating with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The minimal shape
&lt;/h2&gt;

&lt;p&gt;A repository doesn't need all of this on day one. The minimal useful shape is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docs/
  product.md
  structure.md
  tech-stack.md
  architecture.md
  quality-policy.md
  specs/
    &amp;lt;feature&amp;gt;/
      spec.md
      verification.yaml
  changes/
    CR-001-descriptive-slug/
      change.md
  adr/
    ADR-001.md
  planning/
    PLN-001.md
tests/
src/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start with the five core documents. Add specs and change records as you build features. Add ADRs when you make significant decisions. The structure grows with the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this doesn't solve
&lt;/h2&gt;

&lt;p&gt;Context management helps AI make better decisions, but it doesn't eliminate the need for verification. A well-informed AI still needs its output checked against contracts and quality gates. The artifact model reduces how often AI goes wrong; the spec and proof model catches it when it does.&lt;/p&gt;

&lt;p&gt;The two work together. Without good context, you write specs and AI still struggles. Without specs and proof, you provide context and AI still produces unverifiable output. You need both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical implications
&lt;/h2&gt;

&lt;p&gt;If you're working with AI coding assistants today:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Write a product.md.&lt;/strong&gt; Even three paragraphs about what your system does and who it's for will improve AI output more than any prompt engineering trick.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document where code goes.&lt;/strong&gt; A structure.md that says "handlers go in src/handlers, domain logic goes in src/domain, never import infrastructure from domain" prevents an entire class of AI mistakes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State your tech choices.&lt;/strong&gt; If you've chosen Axum over Actix, say so. If you've decided on Turso over Postgres, say so. AI defaults to popularity, not your decisions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep quality policy explicit.&lt;/strong&gt; Don't rely on AI knowing to run clippy or that you require 80% test coverage. Write it down where the AI can read it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These four documents take an hour to write. They pay for themselves in the first week of AI-assisted development.&lt;/p&gt;

</description>
      <category>ai</category>
    </item>
    <item>
      <title>The Trust Problem: Why Code Review Breaks When AI Writes the Code</title>
      <dc:creator>Juhani Ränkimies</dc:creator>
      <pubDate>Mon, 09 Mar 2026 19:40:05 +0000</pubDate>
      <link>https://dev.to/juranki/the-trust-problem-why-code-review-breaks-when-ai-writes-the-code-chf</link>
      <guid>https://dev.to/juranki/the-trust-problem-why-code-review-breaks-when-ai-writes-the-code-chf</guid>
      <description>&lt;p&gt;Something breaks when AI starts writing most of your code.&lt;/p&gt;

&lt;p&gt;Not the code itself -- that's often fine. What breaks is how you know it's fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  The old trust model
&lt;/h2&gt;

&lt;p&gt;For decades, the trust model for software has been code review. A human reads the diff, reasons about what it does, checks it against what was intended, and either approves or pushes back. The reviewer's judgment is the quality gate.&lt;/p&gt;

&lt;p&gt;This works when a human writes code at human speed. The reviewer can match the pace of production. They can hold the intent and implementation in their head simultaneously. They have time to think about edge cases, architectural fit, and whether the change actually solves the stated problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changes with AI
&lt;/h2&gt;

&lt;p&gt;AI generates code faster than humans can meaningfully inspect it. This isn't a theoretical concern -- it's the daily experience of anyone using Cursor, Copilot, or Claude Code on non-trivial projects.&lt;/p&gt;

&lt;p&gt;The practical result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Volume overwhelms review.&lt;/strong&gt; A 200-line AI-generated diff takes the same review effort as a 200-line human diff, but AI produces them in seconds. The bottleneck shifts entirely to the reviewer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plausibility replaces correctness.&lt;/strong&gt; AI output looks reasonable. It passes a quick scan. It often compiles and even passes existing tests. But "looks reasonable" is not the same as "does what was intended."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intent becomes invisible.&lt;/strong&gt; When a human writes code, the reviewer can usually reconstruct intent from the diff -- naming choices, structure, comments reveal what the author was thinking. AI-generated code has no intent. It has statistical patterns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cumulative drift goes unnoticed.&lt;/strong&gt; Each AI-generated change might be individually acceptable. Over weeks, the codebase drifts in ways nobody explicitly chose. Architecture erodes. Conventions fragment. Nobody can explain &lt;em&gt;why&lt;/em&gt; the system looks the way it does.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The honest version: most developers using AI assistants have already stopped doing thorough code review of AI output. They scan it, run the tests, and merge. The old trust model is already broken in practice. We just haven't replaced it with anything explicit.&lt;/p&gt;

&lt;h2&gt;
  
  
  The wrong response
&lt;/h2&gt;

&lt;p&gt;One common response is to try harder at code review. Slow down. Read every line. Understand every choice.&lt;/p&gt;

&lt;p&gt;This doesn't work for the same reason manual testing didn't scale -- it requires effort proportional to output volume, and the volume is growing. You can't outrun AI generation speed with human review effort.&lt;/p&gt;

&lt;p&gt;Another response is to trust the AI. It's getting better. It mostly works. Ship it.&lt;/p&gt;

&lt;p&gt;This works until it doesn't. Until the AI confidently implements something you didn't ask for, or subtly changes behavior in a way that passes tests but violates a business constraint that was never written down. The cost of these failures grows with system complexity.&lt;/p&gt;

&lt;h2&gt;
  
  
  What replaces code review?
&lt;/h2&gt;

&lt;p&gt;The question isn't whether AI can write good code. It often can. The question is: &lt;strong&gt;how do you know the code does what it should?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Code review answered this by having a human verify intent against implementation. If that doesn't scale, something else needs to carry the trust.&lt;/p&gt;

&lt;p&gt;The answer is contracts and proof.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;contract&lt;/strong&gt; defines what must be true -- in concrete, testable terms, written before implementation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proof&lt;/strong&gt; demonstrates that the contract holds -- through automated tests, quality checks, and verification that can run without human judgment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn't new. It's the spec-and-test model that's been around for decades. What's new is that with AI doing the implementation, this model shifts from "nice to have" to "necessary." When you can't rely on reviewing implementation, you must be able to rely on verifying outcomes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spec first. Proof second. Code third.
&lt;/h2&gt;

&lt;p&gt;The operating model is simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Spec first.&lt;/strong&gt; Define what the change must accomplish. Write acceptance criteria in concrete, testable terms. Be explicit about what's in scope and what's not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proof second.&lt;/strong&gt; Map each criterion to automated verification. Write or update tests before implementation. Define the quality gates that must pass.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code third.&lt;/strong&gt; Implementation comes last and is free to change as long as the proof still holds. AI can generate it, refactor it, rewrite it entirely -- the contract and proof are what matter.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The human role shifts. You're no longer primarily a code reviewer. You're a &lt;strong&gt;contract designer&lt;/strong&gt; and &lt;strong&gt;proof architect.&lt;/strong&gt; You decide what must be true. You design how to verify it. AI handles the implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two verification lanes
&lt;/h2&gt;

&lt;p&gt;One lesson from working this way: there are two kinds of trust you need, and they require different verification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Feature verification&lt;/strong&gt; proves the system does what the spec says. This is the obvious one -- acceptance tests, integration tests, behavioral scenarios. Did the feature work? Does it handle the edge cases? Does it respect the boundaries?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;System verification&lt;/strong&gt; proves the codebase remains healthy. This is the one that erodes silently -- linting, type checking, security scanning, architectural constraints, dependency hygiene. The system can pass every feature test and still be rotting structurally.&lt;/p&gt;

&lt;p&gt;Both are mandatory. Passing feature tests is not enough if the code violates architecture or introduces security vulnerabilities. Passing quality gates is not enough if the required behavior is missing.&lt;/p&gt;

&lt;p&gt;When AI writes code, it optimizes for making tests pass. It does not inherently care about architectural consistency, security posture, or maintainability. Both lanes need automated enforcement, not just one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this looks like in practice
&lt;/h2&gt;

&lt;p&gt;A concrete example. You're adding a health endpoint to a Rust web service. Under the old model, you'd write the code, write a test or two, open a PR, and a colleague reviews it.&lt;/p&gt;

&lt;p&gt;Under spec-driven development:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Spec&lt;/strong&gt;: "The service exposes GET /health returning 200 with &lt;code&gt;{"status": "ok"}&lt;/code&gt;. The endpoint requires no authentication. Response time must be under 50ms."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verification map&lt;/strong&gt;: AC-1 maps to an integration test. AC-2 maps to an auth-bypass test. AC-3 maps to a performance assertion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests&lt;/strong&gt;: Written or updated to match the spec. They may initially fail.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implementation&lt;/strong&gt;: AI generates the handler. The tests pass or they don't. If they pass, you don't need to read the handler line by line. The contract is satisfied.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quality gates&lt;/strong&gt;: rustfmt, clippy, cargo check, security scan -- all green. The system is still healthy.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The AI's implementation is accepted based on passing proof, not on how convincing the code looks.&lt;/p&gt;

&lt;h2&gt;
  
  
  What good looks like
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Specs talk about user outcomes and system behavior, not implementation.&lt;/li&gt;
&lt;li&gt;Tests are traceable to requirements. You can point at any test and say which acceptance criterion it proves.&lt;/li&gt;
&lt;li&gt;CI can show which requirements are proven by which checks.&lt;/li&gt;
&lt;li&gt;Refactoring is safe because verification protects intent, not implementation.&lt;/li&gt;
&lt;li&gt;AI can move fast without turning the codebase into an unreviewable black box.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Anti-patterns
&lt;/h2&gt;

&lt;p&gt;Some things look like spec-driven development but aren't:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Acceptance criteria that describe implementation.&lt;/strong&gt; "Use a HashMap for caching" is not a contract. "Repeated queries for the same key return cached results within 5ms" is.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests with no requirement linkage.&lt;/strong&gt; A test suite that passes tells you something. A test suite where each test maps to a specific acceptance criterion tells you much more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code coverage as a proxy for contract coverage.&lt;/strong&gt; 90% line coverage means nothing if the untested 10% contains the critical business logic. Requirement traceability matters more than coverage percentages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quality checks treated as optional.&lt;/strong&gt; If linting, type checking, and security scanning aren't mandatory gates, they'll erode when AI accelerates output.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The honest version
&lt;/h2&gt;

&lt;p&gt;This approach has real costs. Writing specs takes time. Maintaining verification maps is overhead. When you're moving fast on a solo project, it can feel like ceremony.&lt;/p&gt;

&lt;p&gt;The tradeoff is explicit: you invest in contracts and proof upfront so you can trust AI output without reading every line. Whether that tradeoff pays for itself depends on your context -- system complexity, team size, how much AI is generating, how costly a behavioral mistake would be.&lt;/p&gt;

&lt;p&gt;For a weekend project, it's probably overkill. For a system you're building to last, where AI is writing most of the code, the question isn't whether you need a trust mechanism beyond code review. The question is what that mechanism should be.&lt;/p&gt;

&lt;p&gt;This series explores one answer.&lt;/p&gt;

</description>
      <category>ai</category>
    </item>
    <item>
      <title>SvelteKit/CDK exercise plan</title>
      <dc:creator>Juhani Ränkimies</dc:creator>
      <pubDate>Sun, 11 Apr 2021 05:45:21 +0000</pubDate>
      <link>https://dev.to/juranki/sveltekit-cdk-exercise-plan-2a3m</link>
      <guid>https://dev.to/juranki/sveltekit-cdk-exercise-plan-2a3m</guid>
      <description>&lt;p&gt;I've dabbled with an &lt;a href="https://dev.to/juranki/diy-sveltekit-cdk-adapter-3enp"&gt;adapter&lt;/a&gt; that deploys &lt;a href="https://kit.svelte.dev/"&gt;SvelteKit&lt;/a&gt; project to a &lt;a href="https://aws.amazon.com/cdk/"&gt;CDK&lt;/a&gt; stack, but deploying the sample page doesn't really test the adapter much.&lt;/p&gt;

&lt;p&gt;So, to find (and hopefully fix, too) at least some of the weak spots of my custom CDK adapter, I'll develop a simple app featuring passwordless sign-in and profile picture. The app will protect users from themselves by rejecting reckless profile pictures, like cats and adult content. It'll be hosted on &lt;a href="https://prudent-profile.com"&gt;prudent-profile.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It shouldn't be too complicated, but still exercises new areas of the adapter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;applying svelte kit in more realistic scenario&lt;/li&gt;
&lt;li&gt;session cookies with &lt;a href="https://aws.amazon.com/cloudfront/"&gt;Cloudfront&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;handling non-JSON request payload&lt;/li&gt;
&lt;li&gt;external dependencies in SSR bundle&lt;/li&gt;
&lt;li&gt;more involved CDK stack

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/dynamodb/"&gt;DynamoDB&lt;/a&gt; for session management&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/ses/"&gt;SES&lt;/a&gt; for confirmation emails&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/rekognition/"&gt;Rekognition&lt;/a&gt; to ensure "quality" of profile images&lt;/li&gt;
&lt;li&gt;DNS, TLS certificates, ...&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>svelte</category>
      <category>sveltekit</category>
      <category>aws</category>
      <category>cdk</category>
    </item>
    <item>
      <title>DIY SvelteKit CDK adapter</title>
      <dc:creator>Juhani Ränkimies</dc:creator>
      <pubDate>Mon, 05 Apr 2021 23:52:09 +0000</pubDate>
      <link>https://dev.to/juranki/diy-sveltekit-cdk-adapter-3enp</link>
      <guid>https://dev.to/juranki/diy-sveltekit-cdk-adapter-3enp</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Update on 2021-10-30&lt;/p&gt;

&lt;p&gt;You should also check out &lt;a href="https://github.com/juranki/sveltekit-cdk" rel="noopener noreferrer"&gt;my SvelteKit-CDK adapter&lt;/a&gt;.&lt;br&gt;
It covers everything discussed in this article. While not even close to stable, it's cleaner and has better structure. And has a wrapper for Lambda@Edge, too. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Below are notes of me putting together &lt;a href="https://kit.svelte.dev/" rel="noopener noreferrer"&gt;sveltekit&lt;/a&gt; and &lt;a href="https://aws.amazon.com/cdk/" rel="noopener noreferrer"&gt;AWS CDK&lt;/a&gt;. Explanations are minimal. Familiarity with both SvelteKit and CDK is probably required to follow. &lt;/p&gt;

&lt;p&gt;At the moment &lt;a href="https://www.npmjs.com/package/@sveltejs/kit" rel="noopener noreferrer"&gt;@sveltejs/kit&lt;/a&gt; version is 1.0.0-next.71, and the adapter interface is not stable, so this solution is likely to break as time passes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2g8uj65ot7i8xgl7uzg3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2g8uj65ot7i8xgl7uzg3.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Init SvelteKit project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;sveltekit-cdk
~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;sveltekit-cdk/
~/sveltekit-cdk&lt;span class="nv"&gt;$ &lt;/span&gt;npm init svelte@next
   ...
   &lt;span class="o"&gt;(&lt;/span&gt;I chose typescript/CSS/no eslint/no prettier&lt;span class="o"&gt;)&lt;/span&gt;
   ...
~/sveltekit-cdk&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
~/sveltekit-cdk&lt;span class="nv"&gt;$ &lt;/span&gt;git init
~/sveltekit-cdk&lt;span class="nv"&gt;$ &lt;/span&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
~/sveltekit-cdk&lt;span class="nv"&gt;$ &lt;/span&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"init svelte"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  2. Init CDK project for adapter
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/sveltekit-cdk&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;adapter
~/sveltekit-cdk&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;adapter
~/sveltekit-cdk/adapter&lt;span class="nv"&gt;$ &lt;/span&gt;npx cdk init &lt;span class="nt"&gt;--language&lt;/span&gt; typescript
~/sveltekit-cdk/adapter&lt;span class="nv"&gt;$ &lt;/span&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
~/sveltekit-cdk/adapter&lt;span class="nv"&gt;$ &lt;/span&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"init CDK"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  3. Replace node adapter with a dummy adapter
&lt;/h3&gt;

&lt;p&gt;This is our dummy adapter (&lt;a href="https://github.com/juranki/diy-sveltekit-cdk-adapter/blob/a73ce710cf25b6cc43d8b0e740df34d8c81f7e68/adapter" rel="noopener noreferrer"&gt;adapter/adapter.ts&lt;/a&gt;)&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Adapter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@sveltejs/kit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Adapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MAGIC&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;adapt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TODO...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;To be able to use typescript for the adapter without extra compilation steps, lets add a little &lt;a href="https://github.com/TypeStrong/ts-node" rel="noopener noreferrer"&gt;ts-node&lt;/a&gt; wrapper (&lt;a href="https://github.com/juranki/diy-sveltekit-cdk-adapter/blob/a73ce710cf25b6cc43d8b0e740df34d8c81f7e68/adapter/index.js" rel="noopener noreferrer"&gt;adapter/index.js&lt;/a&gt;)&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ts-node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./adapter.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;adapter&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Finally, node adapter is replaced in &lt;a href="https://github.com/juranki/diy-sveltekit-cdk-adapter/blob/a73ce710cf25b6cc43d8b0e740df34d8c81f7e68/svelte.config.cjs" rel="noopener noreferrer"&gt;svelte.config.js&lt;/a&gt; with our adapter&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- const node = require('@sveltejs/adapter-node');
&lt;/span&gt;&lt;span class="gi"&gt;+ const cdkAdapter = require('./adapter/index.js')
&lt;/span&gt;&lt;span class="err"&gt;

&lt;/span&gt;&lt;span class="gd"&gt;-       // By default, `npm run build` will create a standard Node app.
-       // You can create optimized builds for different platforms by
-       // specifying a different adapter
-       adapter: node(),
&lt;/span&gt;&lt;span class="gi"&gt;+       adapter: cdkAdapter,
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;To make ts-node wrapper work, I had to comment out &lt;code&gt;"module": "es2020",&lt;/code&gt; from tsconfig.json. &lt;a href="https://github.com/juranki/diy-sveltekit-cdk-adapter/commit/a73ce710cf25b6cc43d8b0e740df34d8c81f7e68" rel="noopener noreferrer"&gt;Full commit here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And try it out&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm run build

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; sveltekit-cdk@0.0.1 build /workspaces/sveltekit-cdk
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; svelte-kit build

vite v2.1.5 building &lt;span class="k"&gt;for &lt;/span&gt;production...
✓ 18 modules transformed.
.svelte/output/client/_app/manifest.json                            0.67kb
.svelte/output/client/_app/assets/start-d4cd1237.css                0.29kb / brotli: 0.18kb
.svelte/output/client/_app/assets/pages/index.svelte-27172613.css   0.69kb / brotli: 0.26kb
.svelte/output/client/_app/pages/index.svelte-f28bc36b.js           1.58kb / brotli: 0.68kb
.svelte/output/client/_app/chunks/vendor-57a96aae.js                5.14kb / brotli: 2.00kb
.svelte/output/client/_app/start-ff890ac9.js                        15.52kb / brotli: 5.29kb
vite v2.1.5 building SSR bundle &lt;span class="k"&gt;for &lt;/span&gt;production...
✓ 16 modules transformed.
.svelte/output/server/app.js   70.57kb

Run npm start to try your app locally.

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Using MAGIC
TODO...
  ✔ &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  4. Capture Svelte output
&lt;/h3&gt;

&lt;p&gt;Svelte files are copied to a place that is easy to include to CDK stack.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;export const adapter: Adapter = {
&lt;/span&gt;    name: 'MAGIC',
    async adapt(utils): Promise&amp;lt;void&amp;gt; {
&lt;span class="gd"&gt;-        console.log('TODO...')
&lt;/span&gt;&lt;span class="gi"&gt;+        const contentPath = path.join(__dirname, 'content')
+        rmRecursive(contentPath)
+        const serverPath = path.join(contentPath, 'server')
+        const staticPath = path.join(contentPath, 'static')
+        utils.copy_server_files(serverPath)
+        utils.copy_client_files(staticPath)
+        utils.copy_static_files(staticPath)
&lt;/span&gt;    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Svelte kit provides nice utilities for storing the files to desired folders. Here, the SSR implementation is put to server folder, and will be later deployed to a lambda function. And client and static files are stored to static folder, and will be later deployed to S3.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm25qsjo69nfnfggcsgz2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm25qsjo69nfnfggcsgz2.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/juranki/diy-sveltekit-cdk-adapter/commit/55090be4942ab3f01b56826d6bac88b0e4f3b869" rel="noopener noreferrer"&gt;Full commit&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  5. Create a Lambda wrapper for SSR
&lt;/h3&gt;

&lt;p&gt;This lambda handler maps the &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html" rel="noopener noreferrer"&gt;API gateway request and response&lt;/a&gt; to what SSR implementation expects.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;URLSearchParams&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../content/server/app.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;multiValueQueryStringParameters&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;multiValueQueryStringParameters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;multiValueQueryStringParameters&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;multiValueQueryStringParameters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="nx"&gt;vs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rendered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;requestContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domainName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;httpMethod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// TODO: other payload types&lt;/span&gt;
        &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rendered&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
            &lt;span class="na"&gt;multiValueHeaders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
            &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rendered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rendered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rendered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rendered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;multiValueHeaders&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;resp&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Not found.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And it needs to be bundled for deployment to lambda&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;export const adapter: Adapter = {
&lt;/span&gt;    name: 'MAGIC',
    async adapt(utils): Promise&amp;lt;void&amp;gt; {
        const contentPath = path.join(__dirname, 'content')
        rmRecursive(contentPath)
        const serverPath = path.join(contentPath, 'server')
        const staticPath = path.join(contentPath, 'static')
        utils.copy_server_files(serverPath)
        utils.copy_client_files(staticPath)
        utils.copy_static_files(staticPath)
&lt;span class="gi"&gt;+  
+       const bundler = new ParcelBundler(
+            [path.join(__dirname, 'lambda', 'index.js')],
+            {
+                outDir: path.join(contentPath, 'server-bundle'),
+                bundleNodeModules: true,
+                target: 'node',
+                sourceMaps: false,
+                minify: false,
+            },
+        )
+        await bundler.bundle()
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://github.com/juranki/diy-sveltekit-cdk-adapter/commit/442ee7cf89c1126415af4dcb3a877d376fa875c0" rel="noopener noreferrer"&gt;Full commit here.&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  6. Create CDK Stack
&lt;/h3&gt;

&lt;p&gt;This is a barebones stack for deploying the site. The only non-trivial parts are the routing configuration that is generated from the contents of the static folder, and that I configured CDN to pass session cookies through to SSR handler.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt;  &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/aws-lambda&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;gw&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/aws-apigatewayv2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;  &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/aws-s3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;s3depl&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/aws-s3-deployment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LambdaProxyIntegration&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/aws-apigatewayv2-integrations&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdn&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-cdk/aws-cloudfront&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;AdapterProps&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StackProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;serverPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;staticPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AdapterStack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AdapterProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;handler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AssetCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;serverPath&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.handler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODEJS_14_X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;gw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HttpApi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addRoutes&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/{proxy+}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;gw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HttpMethod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ANY&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;integration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LambdaProxyIntegration&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;payloadFormatVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;gw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PayloadFormatVersion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VERSION_1_0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;staticBucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;staticBucket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;staticDeployment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;s3depl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BucketDeployment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;staticDeployment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;destinationBucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;staticBucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;sources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;s3depl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;staticPath&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;staticID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cdn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;OriginAccessIdentity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;staticID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;staticBucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;grantRead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;staticID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;distro&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cdn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CloudFrontWebDistribution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;distro&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;priceClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PriceClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PRICE_CLASS_100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;defaultRootObject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;originConfigs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;customOriginSource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;domainName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;://&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apiEndpoint&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="na"&gt;originProtocolPolicy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OriginProtocolPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HTTPS_ONLY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;behaviors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;allowedMethods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CloudFrontAllowedMethods&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ALL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;forwardedValues&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;queryString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="na"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;whitelist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="na"&gt;whitelistedNames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sid.sig&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="na"&gt;isDefaultBehavior&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;s3OriginSource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;s3BucketSource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;staticBucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;originAccessIdentity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;staticID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;behaviors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;mkStaticRoutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;staticPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;mkStaticRoutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;staticPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;cdn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Behavior&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;staticPath&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fullPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;staticPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;statSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fullPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isDirectory&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;pathPattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/*`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;pathPattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Check &lt;a href="https://github.com/juranki/diy-sveltekit-cdk-adapter/commit/43cb58e62f1c96d204e0e884b24b60ece470c46e" rel="noopener noreferrer"&gt;full commit&lt;/a&gt; to see &lt;a href="https://github.com/juranki/diy-sveltekit-cdk-adapter/blob/43cb58e62f1c96d204e0e884b24b60ece470c46e/adapter/adapter.ts#L44-L57" rel="noopener noreferrer"&gt;how cdk deploy is invoked&lt;/a&gt; and &lt;a href="https://github.com/juranki/diy-sveltekit-cdk-adapter/blob/43cb58e62f1c96d204e0e884b24b60ece470c46e/adapter/bin/adapter.ts#L8-L13" rel="noopener noreferrer"&gt;parameters passed to the stack&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ACCOUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;234......23
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;eu-north-1
&lt;span class="nv"&gt;$ &lt;/span&gt;npm run build
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; sveltekit-cdk@0.0.1 build /workspaces/sveltekit-cdk&amp;gt; svelte-kit build

vite v2.1.5 building &lt;span class="k"&gt;for &lt;/span&gt;production...
✓ 18 modules transformed.
.svelte/output/client/_app/manifest.json                            0.67kb
.svelte/output/client/_app/assets/start-d4cd1237.css                0.29kb / brotli: 0.18kb
.svelte/output/client/_app/assets/pages/index.svelte-27172613.css   0.69kb / brotli: 0.26kb
.svelte/output/client/_app/pages/index.svelte-f28bc36b.js           1.58kb / brotli: 0.68kb
.svelte/output/client/_app/chunks/vendor-57a96aae.js                5.14kb / brotli: 2.00kb
.svelte/output/client/_app/start-ff890ac9.js                        15.52kb / brotli: 5.29kb
vite v2.1.5 building SSR bundle &lt;span class="k"&gt;for &lt;/span&gt;production...
✓ 16 modules transformed.
.svelte/output/server/app.js   70.57kb

Run npm start to try your app locally.

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Using MAGIC
✨  Built &lt;span class="k"&gt;in &lt;/span&gt;1.45s.

adapter/content/server-bundle/index.js    83.97 KB    1.14s
  ✔ &lt;span class="k"&gt;done
&lt;/span&gt;AdapterStack: deploying...
&lt;span class="o"&gt;[&lt;/span&gt;0%] start: Publishing 77fee73b537c2786a56a5ae730eecc3d1121be2512b210c0ad7f92a87ba52125:current
&lt;span class="o"&gt;[&lt;/span&gt;25%] success: Published 77fee73b537c2786a56a5ae730eecc3d1121be2512b210c0ad7f92a87ba52125:current
&lt;span class="o"&gt;[&lt;/span&gt;25%] start: Publishing e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68:current
&lt;span class="o"&gt;[&lt;/span&gt;50%] success: Published e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68:current
&lt;span class="o"&gt;[&lt;/span&gt;50%] start: Publishing c24b999656e4fe6c609c31bae56a1cf4717a405619c3aa6ba1bc686b8c2c86cf:current
&lt;span class="o"&gt;[&lt;/span&gt;75%] success: Published c24b999656e4fe6c609c31bae56a1cf4717a405619c3aa6ba1bc686b8c2c86cf:current
&lt;span class="o"&gt;[&lt;/span&gt;75%] start: Publishing 9ab01d8ba7648b72beed50ec3fad310aef1e1af2bf56f3912d53a56e03579ece:current
&lt;span class="o"&gt;[&lt;/span&gt;100%] success: Published 9ab01d8ba7648b72beed50ec3fad310aef1e1af2bf56f3912d53a56e03579ece:current
AdapterStack: creating CloudFormation changeset...
  0/18 | 11:07:37 PM | REVIEW_IN_PROGRESS   | AWS::CloudFormation::Stack                      | AdapterStack User Initiated
  0/18 | 11:07:43 PM | CREATE_IN_PROGRESS   | AWS::CloudFormation::Stack                      | AdapterStack User Initiated
  1/18 | 11:08:16 PM | CREATE_IN_PROGRESS   | AWS::IAM::Role                                  | handler/ServiceRole &lt;span class="o"&gt;(&lt;/span&gt;handlerServiceRole187D5A5A&lt;span class="o"&gt;)&lt;/span&gt; 
  1/18 | 11:08:16 PM | CREATE_IN_PROGRESS   | AWS::S3::Bucket                                 | staticBucket &lt;span class="o"&gt;(&lt;/span&gt;staticBucket49CE0992&lt;span class="o"&gt;)&lt;/span&gt; 
  1/18 | 11:08:16 PM | CREATE_IN_PROGRESS   | AWS::IAM::Role                                  | handler/ServiceRole &lt;span class="o"&gt;(&lt;/span&gt;handlerServiceRole187D5A5A&lt;span class="o"&gt;)&lt;/span&gt; Resource creation Initiated
  1/18 | 11:08:16 PM | CREATE_IN_PROGRESS   | AWS::CloudFront::CloudFrontOriginAccessIdentity | staticID &lt;span class="o"&gt;(&lt;/span&gt;staticID76F07208&lt;span class="o"&gt;)&lt;/span&gt; 
  1/18 | 11:08:16 PM | CREATE_IN_PROGRESS   | AWS::ApiGatewayV2::Api                          | api &lt;span class="o"&gt;(&lt;/span&gt;apiC8550315&lt;span class="o"&gt;)&lt;/span&gt; 
  1/18 | 11:08:16 PM | CREATE_IN_PROGRESS   | AWS::CDK::Metadata                              | CDKMetadata/Default &lt;span class="o"&gt;(&lt;/span&gt;CDKMetadata&lt;span class="o"&gt;)&lt;/span&gt; 
  1/18 | 11:08:16 PM | CREATE_IN_PROGRESS   | AWS::IAM::Role                                  | Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole &lt;span class="o"&gt;(&lt;/span&gt;CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265&lt;span class="o"&gt;)&lt;/span&gt; 
  1/18 | 11:08:16 PM | CREATE_IN_PROGRESS   | AWS::Lambda::LayerVersion                       | staticDeployment/AwsCliLayer &lt;span class="o"&gt;(&lt;/span&gt;staticDeploymentAwsCliLayerCF83B634&lt;span class="o"&gt;)&lt;/span&gt; 
  1/18 | 11:08:17 PM | CREATE_IN_PROGRESS   | AWS::IAM::Role                                  | Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole &lt;span class="o"&gt;(&lt;/span&gt;CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265&lt;span class="o"&gt;)&lt;/span&gt; Resource creation Initiated
  1/18 | 11:08:17 PM | CREATE_IN_PROGRESS   | AWS::S3::Bucket                                 | staticBucket &lt;span class="o"&gt;(&lt;/span&gt;staticBucket49CE0992&lt;span class="o"&gt;)&lt;/span&gt; Resource creation Initiated
  1/18 | 11:08:18 PM | CREATE_IN_PROGRESS   | AWS::CDK::Metadata                              | CDKMetadata/Default &lt;span class="o"&gt;(&lt;/span&gt;CDKMetadata&lt;span class="o"&gt;)&lt;/span&gt; Resource creation Initiated
  1/18 | 11:08:18 PM | CREATE_COMPLETE      | AWS::CDK::Metadata                              | CDKMetadata/Default &lt;span class="o"&gt;(&lt;/span&gt;CDKMetadata&lt;span class="o"&gt;)&lt;/span&gt; 
  1/18 | 11:08:18 PM | CREATE_IN_PROGRESS   | AWS::CloudFront::CloudFrontOriginAccessIdentity | staticID &lt;span class="o"&gt;(&lt;/span&gt;staticID76F07208&lt;span class="o"&gt;)&lt;/span&gt; Resource creation Initiated
  4/18 | 11:08:18 PM | CREATE_COMPLETE      | AWS::CloudFront::CloudFrontOriginAccessIdentity | staticID &lt;span class="o"&gt;(&lt;/span&gt;staticID76F07208&lt;span class="o"&gt;)&lt;/span&gt; 
  4/18 | 11:08:18 PM | CREATE_IN_PROGRESS   | AWS::ApiGatewayV2::Api                          | api &lt;span class="o"&gt;(&lt;/span&gt;apiC8550315&lt;span class="o"&gt;)&lt;/span&gt; Resource creation Initiated
  4/18 | 11:08:18 PM | CREATE_COMPLETE      | AWS::ApiGatewayV2::Api                          | api &lt;span class="o"&gt;(&lt;/span&gt;apiC8550315&lt;span class="o"&gt;)&lt;/span&gt; 
  4/18 | 11:08:20 PM | CREATE_IN_PROGRESS   | AWS::ApiGatewayV2::Stage                        | api/DefaultStage &lt;span class="o"&gt;(&lt;/span&gt;apiDefaultStage04B80AC9&lt;span class="o"&gt;)&lt;/span&gt; 
  4/18 | 11:08:22 PM | CREATE_IN_PROGRESS   | AWS::ApiGatewayV2::Stage                        | api/DefaultStage &lt;span class="o"&gt;(&lt;/span&gt;apiDefaultStage04B80AC9&lt;span class="o"&gt;)&lt;/span&gt; Resource creation Initiated
  4/18 | 11:08:22 PM | CREATE_COMPLETE      | AWS::ApiGatewayV2::Stage                        | api/DefaultStage &lt;span class="o"&gt;(&lt;/span&gt;apiDefaultStage04B80AC9&lt;span class="o"&gt;)&lt;/span&gt; 
  5/18 | 11:08:32 PM | CREATE_IN_PROGRESS   | AWS::Lambda::LayerVersion                       | staticDeployment/AwsCliLayer &lt;span class="o"&gt;(&lt;/span&gt;staticDeploymentAwsCliLayerCF83B634&lt;span class="o"&gt;)&lt;/span&gt; Resource creation Initiated
  5/18 | 11:08:33 PM | CREATE_COMPLETE      | AWS::Lambda::LayerVersion                       | staticDeployment/AwsCliLayer &lt;span class="o"&gt;(&lt;/span&gt;staticDeploymentAwsCliLayerCF83B634&lt;span class="o"&gt;)&lt;/span&gt; 
  9/18 | 11:08:34 PM | CREATE_COMPLETE      | AWS::IAM::Role                                  | handler/ServiceRole &lt;span class="o"&gt;(&lt;/span&gt;handlerServiceRole187D5A5A&lt;span class="o"&gt;)&lt;/span&gt; 
  9/18 | 11:08:35 PM | CREATE_COMPLETE      | AWS::IAM::Role                                  | Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole &lt;span class="o"&gt;(&lt;/span&gt;CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265&lt;span class="o"&gt;)&lt;/span&gt; 
  9/18 | 11:08:37 PM | CREATE_IN_PROGRESS   | AWS::Lambda::Function                           | handler &lt;span class="o"&gt;(&lt;/span&gt;handlerE1533BD5&lt;span class="o"&gt;)&lt;/span&gt; 
  9/18 | 11:08:37 PM | CREATE_IN_PROGRESS   | AWS::Lambda::Function                           | handler &lt;span class="o"&gt;(&lt;/span&gt;handlerE1533BD5&lt;span class="o"&gt;)&lt;/span&gt; Resource creation Initiated
  9/18 | 11:08:37 PM | CREATE_COMPLETE      | AWS::Lambda::Function                           | handler &lt;span class="o"&gt;(&lt;/span&gt;handlerE1533BD5&lt;span class="o"&gt;)&lt;/span&gt; 
  9/18 | 11:08:38 PM | CREATE_COMPLETE      | AWS::S3::Bucket                                 | staticBucket &lt;span class="o"&gt;(&lt;/span&gt;staticBucket49CE0992&lt;span class="o"&gt;)&lt;/span&gt; 
 12/18 | 11:08:39 PM | CREATE_IN_PROGRESS   | AWS::Lambda::Permission                         | api/ANY--&lt;span class="o"&gt;{&lt;/span&gt;proxy+&lt;span class="o"&gt;}&lt;/span&gt;/AdapterStackapiANYproxy1E757BCE-Permission &lt;span class="o"&gt;(&lt;/span&gt;apiANYproxyAdapterStackapiANYproxy1E757BCEPermission4DD3BE97&lt;span class="o"&gt;)&lt;/span&gt; 
 12/18 | 11:08:39 PM | CREATE_IN_PROGRESS   | AWS::ApiGatewayV2::Integration                  | api/ANY--&lt;span class="o"&gt;{&lt;/span&gt;proxy+&lt;span class="o"&gt;}&lt;/span&gt;/HttpIntegration-addabd80f5f992d479db94f5bda52ee5 &lt;span class="o"&gt;(&lt;/span&gt;apiANYproxyHttpIntegrationaddabd80f5f992d479db94f5bda52ee5449897FD&lt;span class="o"&gt;)&lt;/span&gt; 
 12/18 | 11:08:40 PM | CREATE_IN_PROGRESS   | AWS::IAM::Policy                                | Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/DefaultPolicy &lt;span class="o"&gt;(&lt;/span&gt;CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF&lt;span class="o"&gt;)&lt;/span&gt; 
 12/18 | 11:08:40 PM | CREATE_IN_PROGRESS   | AWS::Lambda::Permission                         | api/ANY--&lt;span class="o"&gt;{&lt;/span&gt;proxy+&lt;span class="o"&gt;}&lt;/span&gt;/AdapterStackapiANYproxy1E757BCE-Permission &lt;span class="o"&gt;(&lt;/span&gt;apiANYproxyAdapterStackapiANYproxy1E757BCEPermission4DD3BE97&lt;span class="o"&gt;)&lt;/span&gt; Resource creation Initiated
 12/18 | 11:08:40 PM | CREATE_IN_PROGRESS   | AWS::S3::BucketPolicy                           | staticBucket/Policy &lt;span class="o"&gt;(&lt;/span&gt;staticBucketPolicyA47383C0&lt;span class="o"&gt;)&lt;/span&gt; 
 12/18 | 11:08:41 PM | CREATE_IN_PROGRESS   | AWS::ApiGatewayV2::Integration                  | api/ANY--&lt;span class="o"&gt;{&lt;/span&gt;proxy+&lt;span class="o"&gt;}&lt;/span&gt;/HttpIntegration-addabd80f5f992d479db94f5bda52ee5 &lt;span class="o"&gt;(&lt;/span&gt;apiANYproxyHttpIntegrationaddabd80f5f992d479db94f5bda52ee5449897FD&lt;span class="o"&gt;)&lt;/span&gt; Resource creation Initiated
 12/18 | 11:08:41 PM | CREATE_COMPLETE      | AWS::ApiGatewayV2::Integration                  | api/ANY--&lt;span class="o"&gt;{&lt;/span&gt;proxy+&lt;span class="o"&gt;}&lt;/span&gt;/HttpIntegration-addabd80f5f992d479db94f5bda52ee5 &lt;span class="o"&gt;(&lt;/span&gt;apiANYproxyHttpIntegrationaddabd80f5f992d479db94f5bda52ee5449897FD&lt;span class="o"&gt;)&lt;/span&gt; 
 12/18 | 11:08:41 PM | CREATE_IN_PROGRESS   | AWS::IAM::Policy                                | Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/DefaultPolicy &lt;span class="o"&gt;(&lt;/span&gt;CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF&lt;span class="o"&gt;)&lt;/span&gt; Resource creation Initiated
 12/18 | 11:08:41 PM | CREATE_IN_PROGRESS   | AWS::S3::BucketPolicy                           | staticBucket/Policy &lt;span class="o"&gt;(&lt;/span&gt;staticBucketPolicyA47383C0&lt;span class="o"&gt;)&lt;/span&gt; Resource creation Initiated
 12/18 | 11:08:41 PM | CREATE_COMPLETE      | AWS::S3::BucketPolicy                           | staticBucket/Policy &lt;span class="o"&gt;(&lt;/span&gt;staticBucketPolicyA47383C0&lt;span class="o"&gt;)&lt;/span&gt; 
 12/18 | 11:08:43 PM | CREATE_IN_PROGRESS   | AWS::ApiGatewayV2::Route                        | api/ANY--&lt;span class="o"&gt;{&lt;/span&gt;proxy+&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;apiANYproxy1413EA65&lt;span class="o"&gt;)&lt;/span&gt; 
 12/18 | 11:08:43 PM | CREATE_IN_PROGRESS   | AWS::ApiGatewayV2::Route                        | api/ANY--&lt;span class="o"&gt;{&lt;/span&gt;proxy+&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;apiANYproxy1413EA65&lt;span class="o"&gt;)&lt;/span&gt; Resource creation Initiated
 12/18 | 11:08:44 PM | CREATE_COMPLETE      | AWS::ApiGatewayV2::Route                        | api/ANY--&lt;span class="o"&gt;{&lt;/span&gt;proxy+&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;apiANYproxy1413EA65&lt;span class="o"&gt;)&lt;/span&gt; 
 13/18 | 11:08:50 PM | CREATE_COMPLETE      | AWS::Lambda::Permission                         | api/ANY--&lt;span class="o"&gt;{&lt;/span&gt;proxy+&lt;span class="o"&gt;}&lt;/span&gt;/AdapterStackapiANYproxy1E757BCE-Permission &lt;span class="o"&gt;(&lt;/span&gt;apiANYproxyAdapterStackapiANYproxy1E757BCEPermission4DD3BE97&lt;span class="o"&gt;)&lt;/span&gt; 
 14/18 | 11:08:58 PM | CREATE_IN_PROGRESS   | AWS::CloudFront::Distribution                   | distro/CFDistribution &lt;span class="o"&gt;(&lt;/span&gt;distroCFDistributionB272DD5C&lt;span class="o"&gt;)&lt;/span&gt; 
 14/18 | 11:08:58 PM | CREATE_COMPLETE      | AWS::IAM::Policy                                | Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/DefaultPolicy &lt;span class="o"&gt;(&lt;/span&gt;CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF&lt;span class="o"&gt;)&lt;/span&gt; 
 14/18 | 11:09:00 PM | CREATE_IN_PROGRESS   | AWS::Lambda::Function                           | Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C &lt;span class="o"&gt;(&lt;/span&gt;CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C81C01536&lt;span class="o"&gt;)&lt;/span&gt; 
 14/18 | 11:09:02 PM | CREATE_IN_PROGRESS   | AWS::CloudFront::Distribution                   | distro/CFDistribution &lt;span class="o"&gt;(&lt;/span&gt;distroCFDistributionB272DD5C&lt;span class="o"&gt;)&lt;/span&gt; Resource creation Initiated
 15/18 | 11:09:04 PM | CREATE_IN_PROGRESS   | AWS::Lambda::Function                           | Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C &lt;span class="o"&gt;(&lt;/span&gt;CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C81C01536&lt;span class="o"&gt;)&lt;/span&gt; Resource creation Initiated
 15/18 | 11:09:05 PM | CREATE_COMPLETE      | AWS::Lambda::Function                           | Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C &lt;span class="o"&gt;(&lt;/span&gt;CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C81C01536&lt;span class="o"&gt;)&lt;/span&gt; 
 15/18 | 11:09:07 PM | CREATE_IN_PROGRESS   | Custom::CDKBucketDeployment                     | staticDeployment/CustomResource/Default &lt;span class="o"&gt;(&lt;/span&gt;staticDeploymentCustomResource41B995BA&lt;span class="o"&gt;)&lt;/span&gt; 
 16/18 | 11:09:39 PM | CREATE_IN_PROGRESS   | Custom::CDKBucketDeployment                     | staticDeployment/CustomResource/Default &lt;span class="o"&gt;(&lt;/span&gt;staticDeploymentCustomResource41B995BA&lt;span class="o"&gt;)&lt;/span&gt; Resource creation Initiated
 16/18 | 11:09:39 PM | CREATE_COMPLETE      | Custom::CDKBucketDeployment                     | staticDeployment/CustomResource/Default &lt;span class="o"&gt;(&lt;/span&gt;staticDeploymentCustomResource41B995BA&lt;span class="o"&gt;)&lt;/span&gt; 
16/18 Currently &lt;span class="k"&gt;in &lt;/span&gt;progress: AdapterStack, distroCFDistributionB272DD5C
 18/18 | 11:11:19 PM | CREATE_COMPLETE      | AWS::CloudFront::Distribution                   | distro/CFDistribution &lt;span class="o"&gt;(&lt;/span&gt;distroCFDistributionB272DD5C&lt;span class="o"&gt;)&lt;/span&gt; 
 18/18 | 11:11:20 PM | CREATE_COMPLETE      | AWS::CloudFormation::Stack                      | AdapterStack 

 ✅  AdapterStack

Stack ARN:
arn:aws:cloudformation:eu-north-1:3123....123:stack/AdapterStack/b653b540-9663-11eb-b7b2-0eab76d49478
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Hurrah!!
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjfeadvedmdtc7pbd9lhj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjfeadvedmdtc7pbd9lhj.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/juranki" rel="noopener noreferrer"&gt;
        juranki
      &lt;/a&gt; / &lt;a href="https://github.com/juranki/diy-sveltekit-cdk-adapter" rel="noopener noreferrer"&gt;
        diy-sveltekit-cdk-adapter
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      An exercise on deploying SvelteKit with CDK
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;






&lt;blockquote&gt;
&lt;p&gt;Cover photo by &lt;a href="https://unsplash.com/@alistairmacrobert?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Alistair MacRobert&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/tangle?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>svelte</category>
      <category>sveltekit</category>
      <category>aws</category>
      <category>cdk</category>
    </item>
  </channel>
</rss>
