Vertical-Slice-Architecture-diagram.excalidraw
==⚠ Switch to EXCALIDRAW VIEW in the MORE OPTIONS menu of this document. ⚠==
Vertical Slice Architecture — Horizontal Layers vs Vertical Slices
Text Elements
Horizontal Layers (Coupled across features) ^layered-label
Presentation Layer ^layer-presentation Business Logic Layer ^layer-business Data Access Layer ^layer-data
Vertical Slices (Independent per feature) ^slices-label
Create Order ^slice1-label Handler ^slice1-handler Validator ^slice1-validator Repository ^slice1-repo
Get Order ^slice2-label Handler ^slice2-handler ReadModel ^slice2-readmodel Query ^slice2-query
Cancel Order ^slice3-label Handler ^slice3-handler Saga ^slice3-saga Repository ^slice3-repo2
Shared: Domain Model, Cross-Cutting Concerns (auth, logging) ^shared-label
Each slice owns its full stack: request -> handler -> data access. No shared service layer. ^annotation
%%
Drawing
{
"type": "excalidraw",
"version": 2,
"source": "https://excalidraw.com",
"elements": [
{
"id": "layered-title",
"type": "text",
"x": 40,
"y": 20,
"width": 320,
"height": 24,
"text": "Horizontal Layers (Coupled across features)",
"fontSize": 15,
"fontFamily": 1,
"textAlign": "left",
"verticalAlign": "top",
"strokeColor": "#e03131",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 100
},
{
"id": "layer-presentation",
"type": "rectangle",
"x": 40,
"y": 56,
"width": 320,
"height": 60,
"strokeColor": "#868e96",
"backgroundColor": "#f1f3f5",
"fillStyle": "solid",
"strokeWidth": 2,
"roughness": 1,
"strokeStyle": "dashed",
"opacity": 80
},
{
"id": "layer-presentation-text",
"type": "text",
"x": 140,
"y": 78,
"width": 120,
"height": 20,
"text": "Presentation Layer",
"fontSize": 13,
"fontFamily": 1,
"textAlign": "center",
"verticalAlign": "middle",
"strokeColor": "#868e96",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 100
},
{
"id": "layer-business",
"type": "rectangle",
"x": 40,
"y": 126,
"width": 320,
"height": 60,
"strokeColor": "#868e96",
"backgroundColor": "#f1f3f5",
"fillStyle": "solid",
"strokeWidth": 2,
"roughness": 1,
"strokeStyle": "dashed",
"opacity": 80
},
{
"id": "layer-business-text",
"type": "text",
"x": 130,
"y": 148,
"width": 140,
"height": 20,
"text": "Business Logic Layer",
"fontSize": 13,
"fontFamily": 1,
"textAlign": "center",
"verticalAlign": "middle",
"strokeColor": "#868e96",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 100
},
{
"id": "layer-data",
"type": "rectangle",
"x": 40,
"y": 196,
"width": 320,
"height": 60,
"strokeColor": "#868e96",
"backgroundColor": "#f1f3f5",
"fillStyle": "solid",
"strokeWidth": 2,
"roughness": 1,
"strokeStyle": "dashed",
"opacity": 80
},
{
"id": "layer-data-text",
"type": "text",
"x": 130,
"y": 218,
"width": 140,
"height": 20,
"text": "Data Access Layer",
"fontSize": 13,
"fontFamily": 1,
"textAlign": "center",
"verticalAlign": "middle",
"strokeColor": "#868e96",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 100
},
{
"id": "slices-title",
"type": "text",
"x": 440,
"y": 20,
"width": 320,
"height": 24,
"text": "Vertical Slices (Independent per feature)",
"fontSize": 15,
"fontFamily": 1,
"textAlign": "left",
"verticalAlign": "top",
"strokeColor": "#2f9e44",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 100
},
{
"id": "band-presentation",
"type": "rectangle",
"x": 440,
"y": 56,
"width": 480,
"height": 60,
"strokeColor": "#dee2e6",
"backgroundColor": "#f8f9fa",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 60
},
{
"id": "band-presentation-label",
"type": "text",
"x": 448,
"y": 78,
"width": 100,
"height": 20,
"text": "Presentation",
"fontSize": 11,
"fontFamily": 1,
"textAlign": "left",
"verticalAlign": "middle",
"strokeColor": "#868e96",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 70
},
{
"id": "band-business",
"type": "rectangle",
"x": 440,
"y": 126,
"width": 480,
"height": 60,
"strokeColor": "#dee2e6",
"backgroundColor": "#f8f9fa",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 60
},
{
"id": "band-business-label",
"type": "text",
"x": 448,
"y": 148,
"width": 100,
"height": 20,
"text": "Business",
"fontSize": 11,
"fontFamily": 1,
"textAlign": "left",
"verticalAlign": "middle",
"strokeColor": "#868e96",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 70
},
{
"id": "band-data",
"type": "rectangle",
"x": 440,
"y": 196,
"width": 480,
"height": 60,
"strokeColor": "#dee2e6",
"backgroundColor": "#f8f9fa",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 60
},
{
"id": "band-data-label",
"type": "text",
"x": 448,
"y": 218,
"width": 100,
"height": 20,
"text": "Data Access",
"fontSize": 11,
"fontFamily": 1,
"textAlign": "left",
"verticalAlign": "middle",
"strokeColor": "#868e96",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 70
},
{
"id": "slice1",
"type": "rectangle",
"x": 460,
"y": 56,
"width": 140,
"height": 200,
"strokeColor": "#2f9e44",
"backgroundColor": "#d3f9d8",
"fillStyle": "solid",
"strokeWidth": 2,
"roughness": 1,
"opacity": 90
},
{
"id": "slice1-label",
"type": "text",
"x": 470,
"y": 64,
"width": 120,
"height": 20,
"text": "Create Order",
"fontSize": 13,
"fontFamily": 1,
"textAlign": "center",
"verticalAlign": "middle",
"strokeColor": "#2f9e44",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 100
},
{
"id": "slice1-handler",
"type": "text",
"x": 490,
"y": 100,
"width": 80,
"height": 20,
"text": "Handler",
"fontSize": 12,
"fontFamily": 1,
"textAlign": "center",
"verticalAlign": "middle",
"strokeColor": "#2f9e44",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 100
},
{
"id": "slice1-validator",
"type": "text",
"x": 490,
"y": 166,
"width": 80,
"height": 20,
"text": "Validator",
"fontSize": 12,
"fontFamily": 1,
"textAlign": "center",
"verticalAlign": "middle",
"strokeColor": "#2f9e44",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 100
},
{
"id": "slice1-repo",
"type": "text",
"x": 490,
"y": 228,
"width": 80,
"height": 20,
"text": "Repository",
"fontSize": 12,
"fontFamily": 1,
"textAlign": "center",
"verticalAlign": "middle",
"strokeColor": "#2f9e44",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 100
},
{
"id": "slice2",
"type": "rectangle",
"x": 614,
"y": 56,
"width": 140,
"height": 200,
"strokeColor": "#1971c2",
"backgroundColor": "#d0ebff",
"fillStyle": "solid",
"strokeWidth": 2,
"roughness": 1,
"opacity": 90
},
{
"id": "slice2-label",
"type": "text",
"x": 624,
"y": 64,
"width": 120,
"height": 20,
"text": "Get Order",
"fontSize": 13,
"fontFamily": 1,
"textAlign": "center",
"verticalAlign": "middle",
"strokeColor": "#1971c2",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 100
},
{
"id": "slice2-handler",
"type": "text",
"x": 644,
"y": 100,
"width": 80,
"height": 20,
"text": "Handler",
"fontSize": 12,
"fontFamily": 1,
"textAlign": "center",
"verticalAlign": "middle",
"strokeColor": "#1971c2",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 100
},
{
"id": "slice2-readmodel",
"type": "text",
"x": 638,
"y": 166,
"width": 90,
"height": 20,
"text": "ReadModel",
"fontSize": 12,
"fontFamily": 1,
"textAlign": "center",
"verticalAlign": "middle",
"strokeColor": "#1971c2",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 100
},
{
"id": "slice2-query",
"type": "text",
"x": 644,
"y": 228,
"width": 80,
"height": 20,
"text": "Query",
"fontSize": 12,
"fontFamily": 1,
"textAlign": "center",
"verticalAlign": "middle",
"strokeColor": "#1971c2",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 100
},
{
"id": "slice3",
"type": "rectangle",
"x": 768,
"y": 56,
"width": 140,
"height": 200,
"strokeColor": "#e67700",
"backgroundColor": "#ffe8cc",
"fillStyle": "solid",
"strokeWidth": 2,
"roughness": 1,
"opacity": 90
},
{
"id": "slice3-label",
"type": "text",
"x": 778,
"y": 64,
"width": 120,
"height": 20,
"text": "Cancel Order",
"fontSize": 13,
"fontFamily": 1,
"textAlign": "center",
"verticalAlign": "middle",
"strokeColor": "#e67700",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 100
},
{
"id": "slice3-handler",
"type": "text",
"x": 798,
"y": 100,
"width": 80,
"height": 20,
"text": "Handler",
"fontSize": 12,
"fontFamily": 1,
"textAlign": "center",
"verticalAlign": "middle",
"strokeColor": "#e67700",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 100
},
{
"id": "slice3-saga",
"type": "text",
"x": 798,
"y": 166,
"width": 80,
"height": 20,
"text": "Saga",
"fontSize": 12,
"fontFamily": 1,
"textAlign": "center",
"verticalAlign": "middle",
"strokeColor": "#e67700",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 100
},
{
"id": "slice3-repo2",
"type": "text",
"x": 798,
"y": 228,
"width": 80,
"height": 20,
"text": "Repository",
"fontSize": 12,
"fontFamily": 1,
"textAlign": "center",
"verticalAlign": "middle",
"strokeColor": "#e67700",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 100
},
{
"id": "shared-box",
"type": "rectangle",
"x": 440,
"y": 270,
"width": 480,
"height": 50,
"strokeColor": "#495057",
"backgroundColor": "#f8f9fa",
"fillStyle": "solid",
"strokeWidth": 2,
"roughness": 1,
"strokeStyle": "dashed",
"opacity": 100
},
{
"id": "shared-text",
"type": "text",
"x": 450,
"y": 283,
"width": 460,
"height": 24,
"text": "Shared: Domain Model, Cross-Cutting Concerns (auth, logging)",
"fontSize": 12,
"fontFamily": 1,
"textAlign": "center",
"verticalAlign": "middle",
"strokeColor": "#495057",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 100
},
{
"id": "annotation",
"type": "text",
"x": 40,
"y": 340,
"width": 880,
"height": 20,
"text": "Each slice owns its full stack: request -> handler -> data access. No shared service layer.",
"fontSize": 12,
"fontFamily": 1,
"textAlign": "center",
"verticalAlign": "middle",
"strokeColor": "#495057",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"opacity": 100
},
{
"id": "divider",
"type": "line",
"x": 400,
"y": 20,
"width": 0,
"height": 300,
"strokeColor": "#ced4da",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"roughness": 1,
"strokeStyle": "dashed",
"opacity": 80,
"points": [[0, 0], [0, 300]]
}
],
"appState": {
"gridSize": null,
"viewBackgroundColor": "#ffffff"
},
"files": {}
}%%