Bootstraps a new solution for this stack from scratch with the dotnet and Angular CLIs - Web API (controllers) + Services + DataAccess + NUnit tests, SQLite (app.db) as the starting database, ASP.NET Core Identity with JWT, central package management, development configuration in appsettings.Development.json, and an Angular + PrimeNG + Tailwind app. Use when starting a new project or repo, or when asked how to set one up.
Resources
1Install
npx skillscat add gitquuu/qugents/dotnet-new-solution Install via the SkillsCat registry.
New solution: Web API + Identity/JWT + Angular
Start from dotnet new webapi --use-controllers, not from an MVC template with Individual auth. The MVC + Individual template brings cookie authentication, Razor views, Identity UI pages, static files and a Controller-based setup that all have to be removed again, and it is easy to leave something behind (cookie schemes, AddDefaultIdentity, _Layout). The Web API template has nothing to strip; Identity is added with two packages and AddIdentityCore, which gives users, roles, password hashing and lockout without cookies or UI. The result is the same as a well-stripped MVC project, minus the cleanup.
Run the commands from the new repo root. Replace Shop with the solution name. Commands work in PowerShell and Bash. Requires the .NET 10 SDK and Node 22.22+ (Angular 22).
1. Solution and projects
dotnet new sln -n Shop # .NET 10 creates Shop.slnx
dotnet new gitignore
dotnet new editorconfig
dotnet new globaljson --sdk-version 10.0.100 --roll-forward latestFeature # use your installed 10.0.x
dotnet new buildprops # Directory.Build.props (shared settings)
dotnet new packagesprops # Directory.Packages.props (central package versions)
dotnet new webapi --use-controllers -n Shop.Api -o src/Shop.Api # then set launchSettings.json to https://localhost:5001
dotnet new classlib -n Shop.Services -o src/Shop.Services
dotnet new classlib -n Shop.DataAccess -o src/Shop.DataAccess
dotnet new nunit -n Shop.Tests -o tests/Shop.Tests
dotnet sln add src/Shop.Api src/Shop.Services src/Shop.DataAccess tests/Shop.Tests
dotnet add src/Shop.Api reference src/Shop.Services
dotnet add src/Shop.Services reference src/Shop.DataAccess
dotnet add tests/Shop.Tests reference src/Shop.Api src/Shop.Services src/Shop.DataAccessDelete the samples: WeatherForecast.cs, Controllers/WeatherForecastController.cs, and Class1.cs in both class libraries.
Central package management (Directory.Packages.props) replaces a separate "Packages" project: every version lives in one file, and dotnet add package writes it there.
2. Packages
# DataAccess: EF Core (SQLite to start, see section 4) + Identity stores
dotnet add src/Shop.DataAccess package Microsoft.EntityFrameworkCore.Sqlite
dotnet add src/Shop.DataAccess package Microsoft.AspNetCore.Identity.EntityFrameworkCore
# Services: mapping + JWT creation
dotnet add src/Shop.Services package Mapster
dotnet add src/Shop.Services package Microsoft.IdentityModel.JsonWebTokens
# Api: JWT validation, versioning, Swagger UI over the built-in OpenAPI document, EF tooling
dotnet add src/Shop.Api package Microsoft.AspNetCore.Authentication.JwtBearer
dotnet add src/Shop.Api package Asp.Versioning.Mvc
dotnet add src/Shop.Api package Swashbuckle.AspNetCore.SwaggerUI
dotnet add src/Shop.Api package Microsoft.EntityFrameworkCore.Design
# Tests
dotnet add tests/Shop.Tests package FakeItEasy
dotnet add tests/Shop.Tests package Microsoft.EntityFrameworkCore.Sqlite
# EF CLI as a local tool (versioned with the repo)
dotnet new tool-manifest
dotnet tool install dotnet-efAdd later, only when a feature needs them: Hangfire.AspNetCore + storage (background jobs), Sentry.AspNetCore (error tracking).
3. Code skeleton
Create, in this order (templates in the referenced skills):
dotnet-n-layer:ServiceResult<T>,IBaseRepository<T>/BaseRepository<T>,IUnitOfWork/UnitOfWork,ResponseService,AddDataAccess/AddServicesextensions,ICacheService.dotnet-identity-jwt:ApplicationUser,RefreshToken,AppDbContext : IdentityDbContext<ApplicationUser>,AddIdentityCoreinAddDataAccess,JwtOptions,TokenService, the Auth module,AuthController,AddJwtAuthentication,GetUserId(),RoleSeeder.Program.cs,Directory.Build.props,appsettings.json,appsettings.Development.jsonandShop.Api.httpfromreferences/solution-templates.md.
4. Database (SQLite app.db) and configuration
New solutions start on SQLite with a local app.db file: no database server to install, and the project owner switches provider when they need to.
- All development configuration goes in
appsettings.Development.json: the connection string"Data Source=app.db", a generated dev JWT signing key and the CORS origin. No user secrets. The file starts with a// DEV ONLYcomment saying these values must be replaced via environment variables or a vault before production, andappsettings.jsonleavesSigningKeyand the connection string empty so production cannot start without them. - Run
dotnet runanddotnet effromsrc/Shop.Api, so the relative path always resolves tosrc/Shop.Api/app.db. Pass-- --environment Developmenttodotnet efso it readsappsettings.Development.json(dotnet rungets Development fromlaunchSettings.json). - Ignore the database files in git: add
*.db,*.db-shmand*.db-walto.gitignore.
dotnet dev-certs https --trust # once per machine: the API runs on https://localhost:5001
# generate the dev signing key for appsettings.Development.json
openssl rand -base64 48 # PowerShell: [Convert]::ToBase64String([Security.Cryptography.RandomNumberGenerator]::GetBytes(48))
cd src/Shop.Api
dotnet ef migrations add InitialIdentity --project ../Shop.DataAccess -- --environment Development
dotnet ef database update --project ../Shop.DataAccess -- --environment Development
dotnet runSQLite limits to design around (EF Core can store these types but not compare or order them in SQL, so such queries throw):
- Use
DateTimein UTC for entity timestamps, notDateTimeOffset. - Don't filter or sort on
decimalcolumns in queries (prices, amounts) until the move to a server database, or store minor units aslong(øre/cents).
Switching database later (e.g. SQL Server or PostgreSQL):
- Replace the package in DataAccess (
Microsoft.EntityFrameworkCore.SqlServerorNpgsql.EntityFrameworkCore.PostgreSQL) andUseSqlitewithUseSqlServer/UseNpgsqlinAddDataAccess. - Put the new dev connection string in
appsettings.Development.json; production gets its own viaConnectionStrings__Default(environment variable or vault). - Migrations are provider-specific: delete the
Migrationsfolder and create a freshInitialmigration (data inapp.dbis not migrated). - The
DateTime/decimallimits above no longer apply.
5. Angular app
npx @angular/cli@latest new web --style=css --ssr=false --skip-git
cd web
npm install primeng @primeuix/themes @angular/cdk tailwindcss @tailwindcss/postcss postcss tailwindcss-primeuiThen follow the angular-frontend skill: .postcssrc.json, src/styles.css, providePrimeNG (with license key), interceptors, AuthStore + provideAppInitializer.
Ports and HTTPS in development:
| Part | URL |
|---|---|
| API | https://localhost:5001 (launchSettings.json) |
| Angular dev server | https://localhost:4200 |
environment.apiUrl = 'https://localhost:5001'andCors:Origins = ["https://localhost:4200"]inappsettings.Development.json.- The Angular dev server must run on HTTPS: with
http://localhost:4200the browser treats the API as cross-site and never sends theSameSite=Strictrefresh cookie. Reuse the trusted ASP.NET Core dev certificate:
# from web/
dotnet dev-certs https --export-path ./certs/localhost.pem --format Pem --no-password # writes localhost.pem + localhost.keyIn angular.json → projects.web.architect.serve.options: "ssl": true, "sslCert": "certs/localhost.pem", "sslKey": "certs/localhost.key". Add web/certs/ to .gitignore.
6. Done when
dotnet buildhas no warnings (warnings are errors viaDirectory.Build.props) anddotnet testis green.dotnet run(fromsrc/Shop.Api) listens on https://localhost:5001;app.dbsits insrc/Shop.Apiand is git-ignored;https://localhost:5001/openapi/v1.jsonandhttps://localhost:5001/swaggerload.- The
Shop.Api.httprequests work in order: register → login (cookie set, access token returned) → a protected endpoint with the token → refresh → logout. npx ng buildandnpx ng test --watch=falsepass inweb/, andnpx ng serveruns on https://localhost:4200.- Dev values exist only in
appsettings.Development.jsonwith the// DEV ONLYcomment;appsettings.jsonhas emptySigningKeyand connection string.
Before production (not part of the bootstrap, but say it in the hand-off): generate a new signing key and set Jwt__SigningKey, ConnectionStrings__Default and Cors__Origins through environment variables or a vault. The dev key in the repo must never be used outside development.
7. Branches and CI/CD
After the first commit, hand over to the devops agent (skill devops-github-actions): it creates development/staging/prod, sets development as default branch, adds the CI, deploy, release and back-merge workflows plus the ruleset, and lists the secrets/variables to create per environment.
If the repo starts from the ai-agent-dotnet-template, apply the same structure inside it instead of creating a new solution file.
References
references/solution-templates.md:Program.cs,Directory.Build.props,appsettings.json,appsettings.Development.jsonandShop.Api.httpfor the auth flow.