Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
root = true

[*]
charset = utf-8
end_of_line = crlf
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true

[*.cs]
# Indentation
indent_size = 4
tab_width = 4

# New line preferences
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true

# Spacing
csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_around_binary_operators = before_and_after
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false

# Wrapping
csharp_preserve_single_line_statements = true
csharp_preserve_single_line_blocks = true

# Using directives
csharp_using_directive_placement = outside_namespace:suggestion
dotnet_sort_system_directives_first = true
dotnet_separate_import_directive_groups = false

# this. qualification
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_event = false:suggestion

# Language keywords vs BCL types
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
dotnet_style_predefined_type_for_member_access = true:suggestion

# var preferences
csharp_style_var_for_built_in_types = false:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
csharp_style_var_elsewhere = false:suggestion

# Expression-bodied members
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_properties = true:silent

# Pattern matching
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion

# Null checking
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion

# Modifier preferences
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion

# Code style
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion

[*.{csproj,props,targets}]
indent_size = 2

[*.{json,yml,yaml}]
indent_size = 2

[*.md]
trim_trailing_whitespace = false
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
/**/*/obj
/**/*/bin
/.vs
site/
92 changes: 92 additions & 0 deletions DOCUMENTATION_RULE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Żelazna Zasada Dokumentacji — TailoredApps SharedComponents

Każda nowa biblioteka w tym repo MUSI posiadać stronę dokumentacji w `docs/Libraries/`.

## Wymagania dla każdej strony dokumentacji:

1. Opis działania w języku **polskim** i **angielskim**
2. Instrukcja instalacji (`dotnet add package`)
3. Przykład rejestracji w DI (`Program.cs`)
4. Przykład użycia (realny kod C#)
5. Sekcja **🤖 AI Agent Prompt** — gotowy prompt do wklejenia w kontekst agenta AI
6. Aktualizacja `mkdocs.yml` nav
7. Aktualizacja tabeli na `docs/index.md`

## Weryfikacja:

PR bez dokumentacji = PR odrzucony.

---

## Szczegółowa struktura strony dokumentacji

Każda strona musi zawierać następujące sekcje (w tej kolejności):

### 1. Header + badges

```markdown
# TailoredApps.Shared.XXXXX
[![NuGet](badge)] [![License](badge)]
```

### 2. Opis działania (dwujęzyczny)

```markdown
## 🇵🇱 Opis
[Pełny opis po polsku — problem, rozwiązanie, kiedy używać]

## 🇬🇧 Description
[Full description in English]
```

### 3. Instalacja

```bash
dotnet add package TailoredApps.Shared.XXXXX
```

### 4. Rejestracja w DI

```csharp
// Program.cs
builder.Services.AddXxx();
```

### 5. Przykład użycia

Realny, kompletny przykład kodu C# — nie toy example.

### 6. API Reference

Tabela głównych typów publicznych z opisem.

### 7. 🤖 AI Agent Prompt

```markdown
## TailoredApps.Shared.XXXXX — Instrukcja dla agenta AI

Używasz biblioteki TailoredApps.Shared.XXXXX w projekcie .NET.

### Rejestracja
[jak zarejestrować — kod]

### Użycie
[jak używać — konkretne wzorce kodu]

### Zasady
- [zasada 1]
- [zasada 2]
```

---

## Checklist PR

- [ ] Plik `docs/Libraries/<Nazwa>/index.md` (lub odpowiednia strona) istnieje
- [ ] Zawiera opis PL i EN
- [ ] Zawiera przykład DI registration
- [ ] Zawiera realny przykład użycia
- [ ] Zawiera sekcję 🤖 AI Agent Prompt
- [ ] `mkdocs.yml` nav zaktualizowany
- [ ] `docs/index.md` tabela zaktualizowana
- [ ] `mkdocs build --strict` przechodzi bez błędów
174 changes: 174 additions & 0 deletions docs/Libraries/DateTime/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
# TailoredApps.Shared.DateTime

[![NuGet](https://img.shields.io/nuget/v/TailoredApps.Shared.DateTime)](https://www.nuget.org/packages/TailoredApps.Shared.DateTime/)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/tailored-apps/SharedComponents/blob/master/LICENSE)

---

## 🇵🇱 Opis

Biblioteka rozwiązuje jeden z fundamentalnych problemów testowalności aplikacji .NET — bezpośrednie użycie `System.DateTime.Now` w kodzie produkcyjnym, które uniemożliwia pisanie deterministycznych testów jednostkowych.

`TailoredApps.Shared.DateTime` dostarcza interfejs `IDateTimeProvider` i jego domyślną implementację `DateTimeProvider`. Zamiast wywoływać `DateTime.Now` wprost, wstrzykujesz `IDateTimeProvider` przez DI i wywołujesz `provider.Now`. W testach wymieniasz implementację na mock zwracający dowolny punkt w czasie — dzięki temu testy są powtarzalne i niezależne od zegara systemowego.

## 🇬🇧 Description

This library solves one of the fundamental testability problems in .NET — direct use of `System.DateTime.Now` in production code, which prevents writing deterministic unit tests.

`TailoredApps.Shared.DateTime` provides the `IDateTimeProvider` interface and its default implementation `DateTimeProvider`. Instead of calling `DateTime.Now` directly, you inject `IDateTimeProvider` via DI and call `provider.Now`. In tests you swap the implementation for a mock that returns any point in time — making tests repeatable and independent of the system clock.

---

## Instalacja

```bash
dotnet add package TailoredApps.Shared.DateTime
```

---

## Rejestracja w DI

```csharp
// Program.cs
using TailoredApps.Shared.DateTime;

builder.Services.AddSingleton<IDateTimeProvider, DateTimeProvider>();
```

---

## Przykład użycia

### Kod produkcyjny

```csharp
public class OrderService
{
private readonly IDateTimeProvider _dateTime;

public OrderService(IDateTimeProvider dateTime)
{
_dateTime = dateTime;
}

public Order CreateOrder(string customerId, decimal amount)
{
return new Order
{
Id = Guid.NewGuid(),
CustomerId = customerId,
Amount = amount,
CreatedAt = _dateTime.UtcNow, // zamiast DateTime.UtcNow
ExpiresAt = _dateTime.UtcNow.AddDays(30)
};
}

public bool IsOrderExpired(Order order)
{
return order.ExpiresAt < _dateTime.UtcNow;
}
}
```

### Test jednostkowy (Moq)

```csharp
using Moq;
using TailoredApps.Shared.DateTime;
using Xunit;

public class OrderServiceTests
{
[Fact]
public void CreateOrder_ShouldSetCreatedAtToCurrentUtcTime()
{
// Arrange
var fixedTime = new DateTime(2024, 6, 1, 12, 0, 0, DateTimeKind.Utc);
var dateTimeMock = new Mock<IDateTimeProvider>();
dateTimeMock.Setup(d => d.UtcNow).Returns(fixedTime);

var service = new OrderService(dateTimeMock.Object);

// Act
var order = service.CreateOrder("customer-1", 99.99m);

// Assert
Assert.Equal(fixedTime, order.CreatedAt);
Assert.Equal(fixedTime.AddDays(30), order.ExpiresAt);
}

[Fact]
public void IsOrderExpired_WhenExpiresInPast_ReturnsTrue()
{
// Arrange
var now = new DateTime(2024, 6, 1, DateTimeKind.Utc);
var dateTimeMock = new Mock<IDateTimeProvider>();
dateTimeMock.Setup(d => d.UtcNow).Returns(now);

var service = new OrderService(dateTimeMock.Object);
var expiredOrder = new Order { ExpiresAt = now.AddDays(-1) };

// Act & Assert
Assert.True(service.IsOrderExpired(expiredOrder));
}
}
```

---

## API Reference

| Typ | Rodzaj | Opis |
|-----|--------|------|
| `IDateTimeProvider` | Interfejs | Główny kontrakt — wszystkie właściwości do pobierania czasu |
| `DateTimeProvider` | Klasa | Implementacja produkcyjna — deleguje do `System.DateTime` |
| `IDateTimeProvider.Now` | Właściwość | Aktualny czas lokalny (`DateTime.Now`) |
| `IDateTimeProvider.UtcNow` | Właściwość | Aktualny czas UTC (`DateTime.UtcNow`) |
| `IDateTimeProvider.Today` | Właściwość | Aktualna data lokalna (`DateTime.Today`) |
| `IDateTimeProvider.UtcToday` | Właściwość | Aktualna data UTC (`DateTime.UtcNow.Date`) |
| `IDateTimeProvider.TimeOfDay` | Właściwość | Pora dnia (lokalnie) jako `TimeSpan` |
| `IDateTimeProvider.UtcTimeOfDaty` | Właściwość | Pora dnia UTC jako `TimeSpan` |

---

## 🤖 AI Agent Prompt

```markdown
## TailoredApps.Shared.DateTime — Instrukcja dla agenta AI

Używasz biblioteki TailoredApps.Shared.DateTime w projekcie .NET.

### Rejestracja
```csharp
// Program.cs
builder.Services.AddSingleton<IDateTimeProvider, DateTimeProvider>();
```

### Użycie
- Nigdy nie używaj `DateTime.Now` ani `DateTime.UtcNow` bezpośrednio w kodzie produkcyjnym
- Wstrzykuj `IDateTimeProvider` przez konstruktor
- Używaj `provider.UtcNow` dla timestampów w bazie danych
- Używaj `provider.Now` tylko gdy potrzebujesz czasu lokalnego (np. do wyświetlania)

```csharp
// ✅ Poprawnie
public class MyService
{
private readonly IDateTimeProvider _dateTime;
public MyService(IDateTimeProvider dateTime) => _dateTime = dateTime;
public DateTime GetExpiry() => _dateTime.UtcNow.AddHours(1);
}

// ❌ Niepoprawnie
public class MyService
{
public DateTime GetExpiry() => DateTime.UtcNow.AddHours(1); // nie testowalny!
}
```

### Zasady
- Zawsze używaj `IDateTimeProvider` zamiast `System.DateTime` bezpośrednio
- W testach mockuj interfejs, aby zwracał stały punkt w czasie
- Preferuj `UtcNow`/`UtcToday` dla wartości zapisywanych w bazie danych
```
Loading