Skip to content

Instantly share code, notes, and snippets.

@sheepla
Last active December 29, 2025 11:18
Show Gist options
  • Select an option

  • Save sheepla/74c643b20525f6d9f8760579164d5731 to your computer and use it in GitHub Desktop.

Select an option

Save sheepla/74c643b20525f6d9f8760579164d5731 to your computer and use it in GitHub Desktop.
Creating DDD-like vertical-slice architecture project for ASP.NET Core + EF Core backend and Vite + React + shadcn/ui frontend
#!/bin/sh
# Application specific configuration
SOLUTION_NAME="LibrarySystem"
FEATURES=("Users" "Books" "Lending" "Reserving")
API_PROJECT_NAME="${SOLUTION_NAME}.Presentaion.API"
DOMAIN_PROJECT_NAME="${SOLUTION_NAME}.Domain"
APPLICATION_PROJECT_NAME="${SOLUTION_NAME}.Application"
DATABASE_PROJECT_NAME="${SOLUTION_NAME}.Infrastructure.Database"
API_PROJECT_DIR="src/${API_PROJECT_NAME}"
DOMAIN_PROJECT_DIR="src/${DOMAIN_PROJECT_NAME}"
APPLICATION_PROJECT_DIR="src/${APPLICATION_PROJECT_NAME}"
DATABASE_PROJECT_DIR="src/${DATABASE_PROJECT_NAME}"
mkdir src
mkdir tests
echo "Creating API layer project..."
dotnet new webapi -o "${API_PROJECT_DIR}"
echo "Creating domain layer project..."
dotnet new classlib -o "${DOMAIN_PROJECT_DIR}"
rm "${DOMAIN_PROJECT_DIR}/Class1.cs"
echo "Creating application layer project..."
dotnet new classlib -o "${APPLICATION_PROJECT_DIR}"
echo "Creating database layer project..."
dotnet new classlib -o "${DATABASE_PROJECT_DIR}"
rm "${DATABASE_PROJECT_DIR}/Class1.cs"
echo "Creating solution..."
dotnet new sln # Create an empty '*.sln' file
dotnet sln migrate # Migrate from '*.sln' to '*.slnx' (a new simplified format for .NET solution file)
rm "${SOLUTION_NAME}.sln" # Remove old '*.sln' file
# Add '*.csproj' references
dotnet sln add "${API_PROJECT_DIR}"
dotnet sln add "${DOMAIN_PROJECT_DIR}"
dotnet sln add "${APPLICATION_PROJECT_DIR}"
dotnet sln add "${DATABASE_PROJECT_DIR}"
# Add each layers references
dotnet add "${API_PROJECT_DIR}" reference "${DOMAIN_PROJECT_DIR}" # To refer domain models
dotnet add "${API_PROJECT_DIR}" reference "${APPLICATION_PROJECT_DIR}" # To call application services
dotnet add "${API_PROJECT_DIR}" reference "${DATABASE_PROJECT_DIR}" # Just for DI
dotnet add "${APPLICATION_PROJECT_DIR}" reference "${DOMAIN_PROJECT_DIR}" # To refer domain models
dotnet add "${DATABASE_PROJECT_DIR}" reference "${DOMAIN_PROJECT_DIR}" # To refer domain models
echo "Installing dependencies (libraries)..."
# Compile-time generate type-safe object mapper (alternative for AutoMapper)
dotnet add "${API_PROJECT_DIR}" package Riok.Mapperly
# OpenAPI document generator
dotnet add "${API_PROJECT_DIR}" package Swashbuckle.AspNetCore
# Alternative UI for Swagger UI
dotnet add "${API_PROJECT_DIR}" package Scalar.AspNetCore
# Compile-time generate type-safe object mapper (alternative for AutoMapper)
dotnet add "${APPLICATION_PROJECT_DIR}" package Riok.Mapperly
# Error handling library with 'Result' type for .NET
dotnet add "${APPLICATION_PROJECT_DIR}" package FluentResults
# EFCore - ORM framework
dotnet add "${DATABASE_PROJECT_DIR}" package Microsoft.EntityFrameworkCore
# PostgreSQL
dotnet add "${DATABASE_PROJECT_DIR}" package Npgsql.EntityFrameworkCore.PostgreSQL
# EFCore tools
dotnet add "${DATABASE_PROJECT_DIR}" package Microsoft.EntityFrameworkCore.Tools
echo "Installing dependencies (tools)..."
dotnet tool install dotnet-ef
echo "Creating features dirs"
mkdir -p "${API_PROJECT_DIR}/Abstractions"
for feature in "${FEATURES[@]}"
do
mkdir -p "${API_PROJECT_DIR}/Features/${feature}"
done
mkdir -p "${DOMAIN_PROJECT_DIR}/Abstractions"
for feature in "${FEATURES[@]}"
do
mkdir -p "${DOMAIN_PROJECT_DIR}/Features/${feature}"
done
mkdir -p "${APPLICATION_PROJECT_DIR}/Abstractions"
for feature in "${FEATURES[@]}"
do
mkdir -p "${APPLICATION_PROJECT_DIR}/Features/${feature}"
done
mkdir -p "${DATABASE_PROJECT_DIR}/Abstractions"
for feature in "${FEATURES[@]}"
do
mkdir -p "${DATABASE_PROJECT_DIR}/Features/${feature}"
done
#!/bin/sh
PROJECT_DIR="frontend"
pnpm create vite@latest "${PROJECT_DIR}" --template react-swc-ts --no-interactive
cd "${PROJECT_DIR}"
echo "Installing dependencies..."
pnpm install
echo "Initializing TailwindCSS..."
pnpm add tailwindcss @tailwindcss/vite
cat << EOF > src/index.css
@import "tailwindcss";
EOF
echo "Configuring TypeScript..."
pnpm add -D @types/node
cat << EOF > tsconfig.json
{
"files": [],
"references": [
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.node.json"
}
],
/* import-alias for shadcn/ui */
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}
EOF
cat << EOF > tsconfig.app.json
{
"compilerOptions": {
"ignoreDeprecations": "6.0",
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2022",
"useDefineForClassFields": true,
"lib": [
"ES2022",
"DOM",
"DOM.Iterable"
],
"module": "ESNext",
"types": [
"vite/client"
],
"skipLibCheck": true,
/* import-alias for shadcn/ui */
"baseUrl": "./",
"paths": {
"@/*": [
"./src/*"
]
},
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": [
"src"
]
}
EOF
echo "Configuring Vite..."
pnpm add -D @vitejs/plugin-react
cat << EOF > vite.config.ts
import path from "path"
import tailwindcss from "@tailwindcss/vite"
import react from "@vitejs/plugin-react"
import { defineConfig } from "vite"
// https://vite.dev/config/
export default defineConfig({
plugins: [react(), tailwindcss()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
server: {
proxy: {
'/api': {
target: 'http://localhost:5000', // TODO: Fix with the actual backend server URL
changeOrigin: true,
secure: false,
}
}
}
})
EOF
echo "Initializing shadcn/ui CLI..."
pnpm dlx shadcn@latest init --base-color neutral
pnpm dlx shadcn@latest add button
echo "Initializing shadcn/ui sample component..."
cat << EOF > src/App.tsx
import { useState } from 'react'
import { Button } from '@/components/ui/button'
function App() {
const [count, setCount] = useState(0)
const handleClick = () => {
setCount(count + 1)
}
return (
<div>
<div className="flex min-h-svh flex-col items-center justify-center">
<Button onClick={handleClick}>Count: {count}</Button>
</div>
</div>
)
}
export default App
EOF
echo "Creating project dirs..."
mkdir -p src/shared
mkdir -p src/api
mkdir -p src/features
echo "Creating OpenAPI dir..."
mkdir api
echo "Removing unnecessary assets..."
rm src/assets/react.svg
rm public/vite.svg
cd ..
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment