⚠️ This repository is in an early, non-production-ready state. Interfaces, behavior, and database schema are expected to change frequently.
MissSolitude is an exploratory .NET 8 Web API that experiments with a layered architecture for simple user management. It exposes CRUD-style endpoints backed by PostgreSQL via Entity Framework Core. Passwords are hashed using ASP.NET Core Identity primitives, and login returns JWT access/refresh tokens issued by a configurable token service.
- Domain-driven structure with separate
Domain,Application,Infrastructure, andAPIlayers. - PostgreSQL persistence through EF Core with migrations stored in
MissSolitude.Infrastructure/Migrations. - Token issuance via
JWTTokenServicewith adjustable issuer, audience, and signing key settings. - Docker Compose definition for running the API and PostgreSQL together.
MissSolitude.Domain— Domain entities such asUserand value objects likeEmailAddress.MissSolitude.Application— Commands, results, and service contracts (e.g.,IUserService,IPasswordHasher).MissSolitude.Infrastructure— EF Core data access (DatabaseContext), migrations, and concrete service implementations (password hashing, token service, user persistence).MissSolitude.API— ASP.NET Core Web API host with controllers and Swagger setup.compose.yaml— Docker Compose definition for the API and PostgreSQL database.
- .NET SDK 8.0+
- PostgreSQL 16+ (local instance or Docker)
- EF Core CLI (
dotnet tool install --global dotnet-ef) for running migrations locally
Set the connection string named ConnectionStrings:Default for the API host:
- Development default (from
appsettings.Development.json):"ConnectionStrings": { "Default": "Host=localhost;Port=5432;Database=MissSolitude;Username=postgres;Password=postgres" }
- Or override via environment variables (useful for Docker):
export ConnectionStrings__Default="Host=<host>;Port=5432;Database=<db>;Username=<user>;Password=<password>"
JWT issuance uses the Tokens configuration section. Override the defaults in production and keep the signing key private:
export Tokens__Issuer="MissSolitude"
export Tokens__Audience="MissSolitude.Api"
export Tokens__SigningKey="<at-least-32-characters-random-string>"
export Tokens__AccessTokenMinutes=15
export Tokens__RefreshTokenDays=30- Restore dependencies:
dotnet restore
- Apply EF Core migrations to provision the database (requires the connection string above):
dotnet ef database update --project MissSolitude.Infrastructure --startup-project MissSolitude.API
- Run the API:
dotnet run --project MissSolitude.API
- Visit Swagger UI at
https://localhost:7083/swagger(or the HTTP profile athttp://localhost:5016/swagger) to explore endpoints.
The provided compose.yaml spins up the API alongside PostgreSQL:
docker compose up --buildCreate a .env file (copy from .env.example) or export variables before running:
POSTGRES_USER=misssolitude
POSTGRES_PASSWORD=misssolitude
POSTGRES_DB=misssolitude
ASPNETCORE_Kestrel__Certificates__Default__Password=changeitThe API will be available on port 8080 by default.
The API can also listen on https://localhost:8443 when provided a certificate. Docker Compose is preconfigured to load a PFX from ./certificates/misssolitude.pfx and pass the password via ASPNETCORE_Kestrel__Certificates__Default__Password. A standalone .key file is not sufficient for Kestrel; you need a PKCS#12 bundle (PFX) that includes the certificate and private key.
- Generate a development certificate (uses OpenSSL) and export it to
./certificates/misssolitude.pfx:./scripts/generate-dev-certificate.sh
- Set
ASPNETCORE_Kestrel__Certificates__Default__Password(orPFX_PASSWORD) beforehand to choose a password. - If you already have a
misssolitude.keyandmisssolitude.crt, the script will reuse them to create the PFX. If only one of those files exists, delete the leftover and re-run the script so it can produce both.
- Set
- Add the same password to your environment (or
.env) before running Compose:export ASPNETCORE_Kestrel__Certificates__Default__Password="changeit"
- Start the stack and reach the API at
https://localhost:8443.
Create new migrations from the solution root:
dotnet ef migrations add <MigrationName> --project MissSolitude.Infrastructure --startup-project MissSolitude.APIApply migrations to the configured database:
dotnet ef database update --project MissSolitude.Infrastructure --startup-project MissSolitude.APIPOST /api/user— Create a user.{ "username": "alice", "password": "Sup3rS3cret!", "email": "alice@example.com" }GET /api/user/{id}— Retrieve a single user by ID.PUT /api/user— Update a user's username and email.{ "id": "<user-id-guid>", "username": "alice-updated", "email": "new-email@example.com" }DELETE /api/user/{id}— Remove a user by ID.POST /api/user/login— Authenticate a user and receive JWT tokens.Response:{ "identifier": "alice", // username or email "password": "Sup3rS3cret!" }{ "accessToken": "<jwt>", "refreshToken": "<refresh-token>", "user": { "id": "<user-id-guid>", "username": "alice", "email": "alice@example.com" } }
Note: There is no authentication, authorization, or comprehensive input validation yet. Use only in controlled, non-production environments.
Contributions and feedback are welcome, but expect rapid iteration and breaking changes while the project stabilizes.