Initial commit: base slice (auth, roles, users, admin) scaffold

Backend: .NET 10 Clean Architecture + LiteCqrs.Net + EF Core/PostgreSQL +
Identity/JWT. Frontend: React 19 + Vite + TanStack Query/Router + Tailwind v4
with a retro CRT theme. Docker/compose deployment mirroring PnvPanel's
conventions, scoped down to the current base feature set.
This commit is contained in:
Leonid Pershin
2026-07-24 05:40:34 +03:00
commit 8a3eebc48f
156 changed files with 9335 additions and 0 deletions
@@ -0,0 +1,34 @@
namespace TeleWave.Application.Common.Models;
public enum ErrorType
{
Failure,
Validation,
NotFound,
Conflict,
Unauthorized,
Forbidden,
}
public sealed record Error(string Code, string Message, ErrorType Type = ErrorType.Failure)
{
public static readonly Error None = new(string.Empty, string.Empty);
public static Error Validation(string code, string message) =>
new(code, message, ErrorType.Validation);
public static Error NotFound(string code, string message) =>
new(code, message, ErrorType.NotFound);
public static Error Conflict(string code, string message) =>
new(code, message, ErrorType.Conflict);
public static Error Unauthorized(string code, string message) =>
new(code, message, ErrorType.Unauthorized);
public static Error Forbidden(string code, string message) =>
new(code, message, ErrorType.Forbidden);
public static Error Failure(string code, string message) =>
new(code, message, ErrorType.Failure);
}
@@ -0,0 +1,3 @@
namespace TeleWave.Application.Common.Models;
public sealed record PagedList<T>(IReadOnlyList<T> Items, int Total, int Page, int PageSize);
@@ -0,0 +1,43 @@
namespace TeleWave.Application.Common.Models;
public class Result
{
public bool IsSuccess { get; }
public Error Error { get; }
protected Result(bool isSuccess, Error error)
{
if (isSuccess && error != Error.None)
throw new InvalidOperationException("Успешный результат не может содержать ошибку.");
if (!isSuccess && error == Error.None)
throw new InvalidOperationException("Неуспешный результат обязан содержать ошибку.");
IsSuccess = isSuccess;
Error = error;
}
public static Result Success() => new(true, Error.None);
public static Result Failure(Error error) => new(false, error);
public static Result<T> Success<T>(T value) => new(value, true, Error.None);
public static Result<T> Failure<T>(Error error) => new(default, false, error);
}
public class Result<T> : Result
{
private readonly T? _value;
internal Result(T? value, bool isSuccess, Error error)
: base(isSuccess, error) => _value = value;
public T Value =>
IsSuccess
? _value!
: throw new InvalidOperationException(
"Нельзя получить значение неуспешного результата."
);
public static implicit operator Result<T>(T value) => Success(value);
}