claudient 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (283) hide show
  1. package/.claude-plugin/plugin.json +42 -0
  2. package/CONTEXT.md +58 -0
  3. package/README.md +165 -0
  4. package/agents/build-resolvers/de/python-resolver.md +64 -0
  5. package/agents/build-resolvers/de/typescript-resolver.md +65 -0
  6. package/agents/build-resolvers/es/python-resolver.md +64 -0
  7. package/agents/build-resolvers/es/typescript-resolver.md +65 -0
  8. package/agents/build-resolvers/fr/python-resolver.md +64 -0
  9. package/agents/build-resolvers/fr/typescript-resolver.md +65 -0
  10. package/agents/build-resolvers/nl/python-resolver.md +64 -0
  11. package/agents/build-resolvers/nl/typescript-resolver.md +65 -0
  12. package/agents/build-resolvers/python-resolver.md +62 -0
  13. package/agents/build-resolvers/typescript-resolver.md +63 -0
  14. package/agents/core/architect.md +64 -0
  15. package/agents/core/code-reviewer.md +78 -0
  16. package/agents/core/de/architect.md +66 -0
  17. package/agents/core/de/code-reviewer.md +80 -0
  18. package/agents/core/de/planner.md +63 -0
  19. package/agents/core/de/security-reviewer.md +93 -0
  20. package/agents/core/es/architect.md +66 -0
  21. package/agents/core/es/code-reviewer.md +80 -0
  22. package/agents/core/es/planner.md +63 -0
  23. package/agents/core/es/security-reviewer.md +93 -0
  24. package/agents/core/fr/architect.md +66 -0
  25. package/agents/core/fr/code-reviewer.md +80 -0
  26. package/agents/core/fr/planner.md +63 -0
  27. package/agents/core/fr/security-reviewer.md +93 -0
  28. package/agents/core/nl/architect.md +66 -0
  29. package/agents/core/nl/code-reviewer.md +80 -0
  30. package/agents/core/nl/planner.md +63 -0
  31. package/agents/core/nl/security-reviewer.md +93 -0
  32. package/agents/core/planner.md +61 -0
  33. package/agents/core/security-reviewer.md +91 -0
  34. package/guides/agent-orchestration.md +231 -0
  35. package/guides/de/agent-orchestration.md +174 -0
  36. package/guides/de/getting-started.md +164 -0
  37. package/guides/de/hooks-cookbook.md +160 -0
  38. package/guides/de/memory-management.md +153 -0
  39. package/guides/de/security.md +180 -0
  40. package/guides/de/skill-authoring.md +214 -0
  41. package/guides/de/token-optimization.md +156 -0
  42. package/guides/es/agent-orchestration.md +174 -0
  43. package/guides/es/getting-started.md +164 -0
  44. package/guides/es/hooks-cookbook.md +160 -0
  45. package/guides/es/memory-management.md +153 -0
  46. package/guides/es/security.md +180 -0
  47. package/guides/es/skill-authoring.md +214 -0
  48. package/guides/es/token-optimization.md +156 -0
  49. package/guides/fr/agent-orchestration.md +174 -0
  50. package/guides/fr/getting-started.md +164 -0
  51. package/guides/fr/hooks-cookbook.md +227 -0
  52. package/guides/fr/memory-management.md +169 -0
  53. package/guides/fr/security.md +180 -0
  54. package/guides/fr/skill-authoring.md +214 -0
  55. package/guides/fr/token-optimization.md +158 -0
  56. package/guides/getting-started.md +164 -0
  57. package/guides/hooks-cookbook.md +423 -0
  58. package/guides/memory-management.md +192 -0
  59. package/guides/nl/agent-orchestration.md +174 -0
  60. package/guides/nl/getting-started.md +164 -0
  61. package/guides/nl/hooks-cookbook.md +160 -0
  62. package/guides/nl/memory-management.md +153 -0
  63. package/guides/nl/security.md +180 -0
  64. package/guides/nl/skill-authoring.md +214 -0
  65. package/guides/nl/token-optimization.md +156 -0
  66. package/guides/security.md +229 -0
  67. package/guides/skill-authoring.md +226 -0
  68. package/guides/token-optimization.md +169 -0
  69. package/hooks/lifecycle/cost-tracker.md +49 -0
  70. package/hooks/lifecycle/cost-tracker.sh +59 -0
  71. package/hooks/lifecycle/pre-compact-save.md +56 -0
  72. package/hooks/lifecycle/pre-compact-save.sh +37 -0
  73. package/hooks/lifecycle/session-start.md +50 -0
  74. package/hooks/lifecycle/session-start.sh +47 -0
  75. package/hooks/post-tool-use/audit-log.md +53 -0
  76. package/hooks/post-tool-use/audit-log.sh +53 -0
  77. package/hooks/post-tool-use/prettier.md +53 -0
  78. package/hooks/post-tool-use/prettier.sh +49 -0
  79. package/hooks/pre-tool-use/block-dangerous.md +48 -0
  80. package/hooks/pre-tool-use/block-dangerous.sh +76 -0
  81. package/hooks/pre-tool-use/git-push-confirm.md +46 -0
  82. package/hooks/pre-tool-use/git-push-confirm.sh +36 -0
  83. package/mcp/configs/github.json +11 -0
  84. package/mcp/configs/postgres.json +11 -0
  85. package/mcp/de/recommended-servers.md +170 -0
  86. package/mcp/es/recommended-servers.md +170 -0
  87. package/mcp/fr/recommended-servers.md +170 -0
  88. package/mcp/nl/recommended-servers.md +170 -0
  89. package/mcp/recommended-servers.md +168 -0
  90. package/package.json +45 -0
  91. package/prompts/project-starters/de/fastapi-project.md +62 -0
  92. package/prompts/project-starters/de/nextjs-project.md +82 -0
  93. package/prompts/project-starters/es/fastapi-project.md +62 -0
  94. package/prompts/project-starters/es/nextjs-project.md +82 -0
  95. package/prompts/project-starters/fastapi-project.md +60 -0
  96. package/prompts/project-starters/fr/fastapi-project.md +62 -0
  97. package/prompts/project-starters/fr/nextjs-project.md +82 -0
  98. package/prompts/project-starters/nextjs-project.md +80 -0
  99. package/prompts/project-starters/nl/fastapi-project.md +62 -0
  100. package/prompts/project-starters/nl/nextjs-project.md +82 -0
  101. package/prompts/system-prompts/ai-product.md +80 -0
  102. package/prompts/system-prompts/data-pipeline.md +76 -0
  103. package/prompts/system-prompts/de/ai-product.md +82 -0
  104. package/prompts/system-prompts/de/data-pipeline.md +78 -0
  105. package/prompts/system-prompts/de/saas-backend.md +71 -0
  106. package/prompts/system-prompts/es/ai-product.md +82 -0
  107. package/prompts/system-prompts/es/data-pipeline.md +78 -0
  108. package/prompts/system-prompts/es/saas-backend.md +71 -0
  109. package/prompts/system-prompts/fr/ai-product.md +82 -0
  110. package/prompts/system-prompts/fr/data-pipeline.md +78 -0
  111. package/prompts/system-prompts/fr/saas-backend.md +71 -0
  112. package/prompts/system-prompts/nl/ai-product.md +82 -0
  113. package/prompts/system-prompts/nl/data-pipeline.md +78 -0
  114. package/prompts/system-prompts/nl/saas-backend.md +71 -0
  115. package/prompts/system-prompts/saas-backend.md +69 -0
  116. package/prompts/task-specific/changelog.md +81 -0
  117. package/prompts/task-specific/de/changelog.md +83 -0
  118. package/prompts/task-specific/de/debugging.md +78 -0
  119. package/prompts/task-specific/de/pr-description.md +69 -0
  120. package/prompts/task-specific/debugging.md +76 -0
  121. package/prompts/task-specific/es/changelog.md +83 -0
  122. package/prompts/task-specific/es/debugging.md +78 -0
  123. package/prompts/task-specific/es/pr-description.md +69 -0
  124. package/prompts/task-specific/fr/changelog.md +83 -0
  125. package/prompts/task-specific/fr/debugging.md +78 -0
  126. package/prompts/task-specific/fr/pr-description.md +69 -0
  127. package/prompts/task-specific/nl/changelog.md +83 -0
  128. package/prompts/task-specific/nl/debugging.md +78 -0
  129. package/prompts/task-specific/nl/pr-description.md +69 -0
  130. package/prompts/task-specific/pr-description.md +67 -0
  131. package/rules/common/coding-style.md +45 -0
  132. package/rules/common/de/coding-style.md +47 -0
  133. package/rules/common/de/git.md +48 -0
  134. package/rules/common/de/performance.md +40 -0
  135. package/rules/common/de/security.md +45 -0
  136. package/rules/common/de/testing.md +45 -0
  137. package/rules/common/es/coding-style.md +47 -0
  138. package/rules/common/es/git.md +48 -0
  139. package/rules/common/es/performance.md +40 -0
  140. package/rules/common/es/security.md +45 -0
  141. package/rules/common/es/testing.md +45 -0
  142. package/rules/common/fr/coding-style.md +47 -0
  143. package/rules/common/fr/git.md +48 -0
  144. package/rules/common/fr/performance.md +40 -0
  145. package/rules/common/fr/security.md +45 -0
  146. package/rules/common/fr/testing.md +45 -0
  147. package/rules/common/git.md +46 -0
  148. package/rules/common/nl/coding-style.md +47 -0
  149. package/rules/common/nl/git.md +48 -0
  150. package/rules/common/nl/performance.md +40 -0
  151. package/rules/common/nl/security.md +45 -0
  152. package/rules/common/nl/testing.md +45 -0
  153. package/rules/common/performance.md +38 -0
  154. package/rules/common/security.md +43 -0
  155. package/rules/common/testing.md +43 -0
  156. package/rules/language-specific/de/go.md +48 -0
  157. package/rules/language-specific/de/python.md +38 -0
  158. package/rules/language-specific/de/typescript.md +51 -0
  159. package/rules/language-specific/es/go.md +48 -0
  160. package/rules/language-specific/es/python.md +38 -0
  161. package/rules/language-specific/es/typescript.md +51 -0
  162. package/rules/language-specific/fr/go.md +48 -0
  163. package/rules/language-specific/fr/python.md +38 -0
  164. package/rules/language-specific/fr/typescript.md +51 -0
  165. package/rules/language-specific/go.md +46 -0
  166. package/rules/language-specific/nl/go.md +48 -0
  167. package/rules/language-specific/nl/python.md +38 -0
  168. package/rules/language-specific/nl/typescript.md +51 -0
  169. package/rules/language-specific/python.md +36 -0
  170. package/rules/language-specific/typescript.md +49 -0
  171. package/scripts/cli.js +161 -0
  172. package/scripts/link-skills.sh +35 -0
  173. package/scripts/list-skills.sh +34 -0
  174. package/skills/ai-engineering/agent-construction.md +285 -0
  175. package/skills/ai-engineering/claude-api.md +248 -0
  176. package/skills/ai-engineering/de/agent-construction.md +287 -0
  177. package/skills/ai-engineering/de/claude-api.md +250 -0
  178. package/skills/ai-engineering/es/agent-construction.md +287 -0
  179. package/skills/ai-engineering/es/claude-api.md +250 -0
  180. package/skills/ai-engineering/fr/agent-construction.md +287 -0
  181. package/skills/ai-engineering/fr/claude-api.md +250 -0
  182. package/skills/ai-engineering/nl/agent-construction.md +287 -0
  183. package/skills/ai-engineering/nl/claude-api.md +250 -0
  184. package/skills/backend/dotnet/csharp.md +304 -0
  185. package/skills/backend/dotnet/de/csharp.md +306 -0
  186. package/skills/backend/dotnet/es/csharp.md +306 -0
  187. package/skills/backend/dotnet/fr/csharp.md +306 -0
  188. package/skills/backend/dotnet/nl/csharp.md +306 -0
  189. package/skills/backend/go/de/go.md +307 -0
  190. package/skills/backend/go/es/go.md +307 -0
  191. package/skills/backend/go/fr/go.md +307 -0
  192. package/skills/backend/go/go.md +305 -0
  193. package/skills/backend/go/nl/go.md +307 -0
  194. package/skills/backend/nodejs/de/nestjs.md +274 -0
  195. package/skills/backend/nodejs/de/nextjs.md +222 -0
  196. package/skills/backend/nodejs/es/nestjs.md +274 -0
  197. package/skills/backend/nodejs/es/nextjs.md +222 -0
  198. package/skills/backend/nodejs/fr/nestjs.md +274 -0
  199. package/skills/backend/nodejs/fr/nextjs.md +222 -0
  200. package/skills/backend/nodejs/nestjs.md +272 -0
  201. package/skills/backend/nodejs/nextjs.md +220 -0
  202. package/skills/backend/nodejs/nl/nestjs.md +274 -0
  203. package/skills/backend/nodejs/nl/nextjs.md +222 -0
  204. package/skills/backend/python/de/django.md +285 -0
  205. package/skills/backend/python/de/fastapi.md +244 -0
  206. package/skills/backend/python/django.md +283 -0
  207. package/skills/backend/python/es/django.md +285 -0
  208. package/skills/backend/python/es/fastapi.md +244 -0
  209. package/skills/backend/python/fastapi.md +242 -0
  210. package/skills/backend/python/fr/django.md +285 -0
  211. package/skills/backend/python/fr/fastapi.md +244 -0
  212. package/skills/backend/python/nl/django.md +285 -0
  213. package/skills/backend/python/nl/fastapi.md +244 -0
  214. package/skills/data-ml/dbt-data-pipelines.md +155 -0
  215. package/skills/data-ml/de/dbt-data-pipelines.md +157 -0
  216. package/skills/data-ml/de/pandas-polars.md +147 -0
  217. package/skills/data-ml/de/pytorch-tensorflow.md +171 -0
  218. package/skills/data-ml/es/dbt-data-pipelines.md +157 -0
  219. package/skills/data-ml/es/pandas-polars.md +147 -0
  220. package/skills/data-ml/es/pytorch-tensorflow.md +171 -0
  221. package/skills/data-ml/fr/dbt-data-pipelines.md +157 -0
  222. package/skills/data-ml/fr/pandas-polars.md +147 -0
  223. package/skills/data-ml/fr/pytorch-tensorflow.md +171 -0
  224. package/skills/data-ml/nl/dbt-data-pipelines.md +157 -0
  225. package/skills/data-ml/nl/pandas-polars.md +147 -0
  226. package/skills/data-ml/nl/pytorch-tensorflow.md +171 -0
  227. package/skills/data-ml/pandas-polars.md +145 -0
  228. package/skills/data-ml/pytorch-tensorflow.md +169 -0
  229. package/skills/database/de/graphql.md +181 -0
  230. package/skills/database/es/graphql.md +181 -0
  231. package/skills/database/fr/graphql.md +181 -0
  232. package/skills/database/graphql.md +179 -0
  233. package/skills/database/nl/graphql.md +181 -0
  234. package/skills/devops-infra/de/docker.md +133 -0
  235. package/skills/devops-infra/de/github-actions.md +179 -0
  236. package/skills/devops-infra/de/kubernetes.md +129 -0
  237. package/skills/devops-infra/de/terraform.md +130 -0
  238. package/skills/devops-infra/docker.md +131 -0
  239. package/skills/devops-infra/es/docker.md +133 -0
  240. package/skills/devops-infra/es/github-actions.md +179 -0
  241. package/skills/devops-infra/es/kubernetes.md +129 -0
  242. package/skills/devops-infra/es/terraform.md +130 -0
  243. package/skills/devops-infra/fr/docker.md +133 -0
  244. package/skills/devops-infra/fr/github-actions.md +179 -0
  245. package/skills/devops-infra/fr/kubernetes.md +129 -0
  246. package/skills/devops-infra/fr/terraform.md +130 -0
  247. package/skills/devops-infra/github-actions.md +177 -0
  248. package/skills/devops-infra/kubernetes.md +127 -0
  249. package/skills/devops-infra/nl/docker.md +133 -0
  250. package/skills/devops-infra/nl/github-actions.md +179 -0
  251. package/skills/devops-infra/nl/kubernetes.md +129 -0
  252. package/skills/devops-infra/nl/terraform.md +130 -0
  253. package/skills/devops-infra/terraform.md +128 -0
  254. package/skills/finance-payments/de/stripe.md +187 -0
  255. package/skills/finance-payments/es/stripe.md +187 -0
  256. package/skills/finance-payments/fr/stripe.md +187 -0
  257. package/skills/finance-payments/nl/stripe.md +187 -0
  258. package/skills/finance-payments/stripe.md +185 -0
  259. package/workflows/code-review.md +151 -0
  260. package/workflows/de/code-review.md +153 -0
  261. package/workflows/de/debugging-session.md +146 -0
  262. package/workflows/de/feature-development.md +155 -0
  263. package/workflows/de/new-project-bootstrap.md +175 -0
  264. package/workflows/de/refactor-safely.md +150 -0
  265. package/workflows/debugging-session.md +144 -0
  266. package/workflows/es/code-review.md +153 -0
  267. package/workflows/es/debugging-session.md +146 -0
  268. package/workflows/es/feature-development.md +155 -0
  269. package/workflows/es/new-project-bootstrap.md +175 -0
  270. package/workflows/es/refactor-safely.md +150 -0
  271. package/workflows/feature-development.md +153 -0
  272. package/workflows/fr/code-review.md +153 -0
  273. package/workflows/fr/debugging-session.md +146 -0
  274. package/workflows/fr/feature-development.md +155 -0
  275. package/workflows/fr/new-project-bootstrap.md +175 -0
  276. package/workflows/fr/refactor-safely.md +150 -0
  277. package/workflows/new-project-bootstrap.md +173 -0
  278. package/workflows/nl/code-review.md +153 -0
  279. package/workflows/nl/debugging-session.md +146 -0
  280. package/workflows/nl/feature-development.md +155 -0
  281. package/workflows/nl/new-project-bootstrap.md +175 -0
  282. package/workflows/nl/refactor-safely.md +150 -0
  283. package/workflows/refactor-safely.md +148 -0
@@ -0,0 +1,306 @@
1
+ > 🇩🇪 Dies ist die deutsche Übersetzung. [Englische Version](../csharp.md).
2
+
3
+ # C#/.NET Skill
4
+
5
+ ## Wann aktivieren
6
+ - Eine .NET Web API bauen (minimale API oder controller-basiert)
7
+ - Entity Framework Core mit Migrationen einrichten
8
+ - Den .NET Dependency Injection-Container konfigurieren
9
+ - Hintergrunddienste mit `IHostedService` oder `BackgroundService` schreiben
10
+ - Middleware-Pipeline-Komponenten implementieren
11
+ - LINQ-Abfragen schreiben und deferred Execution verstehen
12
+ - async/await in ASP.NET Core korrekt einrichten
13
+
14
+ ## Wann NICHT verwenden
15
+ - Node.js- oder Python-Dienste
16
+ - .NET Framework (vor .NET 5) Legacy-Codebasen — Muster unterscheiden sich
17
+ - Blazor oder MAUI-Frontend — andere Belange
18
+ - Unity-Spielentwicklung — andere Laufzeitumgebung
19
+
20
+ ## Anweisungen
21
+
22
+ ### Projektstruktur
23
+ ```
24
+ MyApi/
25
+ ├── MyApi.sln
26
+ ├── src/
27
+ │ └── MyApi/
28
+ │ ├── Program.cs # Einstiegspunkt + DI-Container
29
+ │ ├── appsettings.json
30
+ │ ├── appsettings.Development.json
31
+ │ ├── Controllers/ # Controller-basierte API
32
+ │ ├── Endpoints/ # Minimale API-Erweiterungen
33
+ │ ├── Models/ # EF Core-Entitäten
34
+ │ ├── DTOs/ # Anfrage-/Antwortformen
35
+ │ ├── Services/ # Business-Logik-Interfaces + Implementierungen
36
+ │ ├── Data/
37
+ │ │ └── AppDbContext.cs
38
+ │ └── Middleware/
39
+ └── tests/
40
+ └── MyApi.Tests/
41
+ ```
42
+
43
+ ### Program.cs — minimales API-Setup
44
+ ```csharp
45
+ // Program.cs — .NET 6+ Top-Level-Statements + minimale API
46
+ var builder = WebApplication.CreateBuilder(args);
47
+
48
+ // Services registrieren
49
+ builder.Services.AddDbContext<AppDbContext>(options =>
50
+ options.UseNpgsql(builder.Configuration.GetConnectionString("Default")));
51
+
52
+ builder.Services.AddScoped<IUserService, UserService>();
53
+ builder.Services.AddControllers();
54
+ builder.Services.AddEndpointsApiExplorer();
55
+ builder.Services.AddSwaggerGen();
56
+
57
+ var app = builder.Build();
58
+
59
+ if (app.Environment.IsDevelopment())
60
+ {
61
+ app.UseSwagger();
62
+ app.UseSwaggerUI();
63
+ }
64
+
65
+ app.UseHttpsRedirection();
66
+ app.UseAuthentication();
67
+ app.UseAuthorization();
68
+ app.MapControllers();
69
+
70
+ // Minimale API-Endpunkte
71
+ app.MapGroup("/api/v1").MapUserEndpoints();
72
+
73
+ app.Run();
74
+ ```
75
+
76
+ ### EF Core-Entity + DbContext
77
+ ```csharp
78
+ // Models/User.cs
79
+ public class User
80
+ {
81
+ public Guid Id { get; set; } = Guid.NewGuid();
82
+ public required string Email { get; set; }
83
+ public required string PasswordHash { get; set; }
84
+ public bool IsActive { get; set; } = true;
85
+ public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
86
+
87
+ public ICollection<Post> Posts { get; set; } = [];
88
+ }
89
+
90
+ // Data/AppDbContext.cs
91
+ public class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(options)
92
+ {
93
+ public DbSet<User> Users => Set<User>();
94
+ public DbSet<Post> Posts => Set<Post>();
95
+
96
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
97
+ {
98
+ modelBuilder.Entity<User>(e =>
99
+ {
100
+ e.HasIndex(u => u.Email).IsUnique();
101
+ e.Property(u => u.Email).HasMaxLength(320);
102
+ });
103
+ }
104
+ }
105
+ ```
106
+
107
+ ### Dependency Injection — Services
108
+ ```csharp
109
+ // Services/IUserService.cs
110
+ public interface IUserService
111
+ {
112
+ Task<UserDto> GetByIdAsync(Guid id, CancellationToken ct = default);
113
+ Task<UserDto> CreateAsync(CreateUserRequest request, CancellationToken ct = default);
114
+ }
115
+
116
+ // Services/UserService.cs
117
+ public class UserService(AppDbContext db) : IUserService
118
+ {
119
+ public async Task<UserDto> GetByIdAsync(Guid id, CancellationToken ct = default)
120
+ {
121
+ var user = await db.Users
122
+ .AsNoTracking()
123
+ .FirstOrDefaultAsync(u => u.Id == id, ct)
124
+ ?? throw new NotFoundException($"User {id} not found");
125
+
126
+ return new UserDto(user.Id, user.Email, user.CreatedAt);
127
+ }
128
+
129
+ public async Task<UserDto> CreateAsync(CreateUserRequest request, CancellationToken ct = default)
130
+ {
131
+ if (await db.Users.AnyAsync(u => u.Email == request.Email, ct))
132
+ throw new ConflictException("Email already in use");
133
+
134
+ var user = new User
135
+ {
136
+ Email = request.Email,
137
+ PasswordHash = BCrypt.Net.BCrypt.HashPassword(request.Password)
138
+ };
139
+ db.Users.Add(user);
140
+ await db.SaveChangesAsync(ct);
141
+ return new UserDto(user.Id, user.Email, user.CreatedAt);
142
+ }
143
+ }
144
+ ```
145
+
146
+ ### Controller-basierte API
147
+ ```csharp
148
+ [ApiController]
149
+ [Route("api/v1/[controller]")]
150
+ public class UsersController(IUserService userService) : ControllerBase
151
+ {
152
+ [HttpGet("{id:guid}")]
153
+ [ProducesResponseType<UserDto>(StatusCodes.Status200OK)]
154
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
155
+ public async Task<IActionResult> GetUser(Guid id, CancellationToken ct)
156
+ {
157
+ var user = await userService.GetByIdAsync(id, ct);
158
+ return Ok(user);
159
+ }
160
+
161
+ [HttpPost]
162
+ [ProducesResponseType<UserDto>(StatusCodes.Status201Created)]
163
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
164
+ [ProducesResponseType(StatusCodes.Status409Conflict)]
165
+ public async Task<IActionResult> CreateUser(
166
+ [FromBody] CreateUserRequest request,
167
+ CancellationToken ct)
168
+ {
169
+ var user = await userService.CreateAsync(request, ct);
170
+ return CreatedAtAction(nameof(GetUser), new { id = user.Id }, user);
171
+ }
172
+ }
173
+ ```
174
+
175
+ ### Minimale API-Endpunkte (Erweiterungsmethoden-Muster)
176
+ ```csharp
177
+ // Endpoints/UserEndpoints.cs
178
+ public static class UserEndpoints
179
+ {
180
+ public static RouteGroupBuilder MapUserEndpoints(this RouteGroupBuilder group)
181
+ {
182
+ var users = group.MapGroup("/users").WithTags("Users");
183
+
184
+ users.MapGet("/{id:guid}", async (Guid id, IUserService svc, CancellationToken ct) =>
185
+ {
186
+ var user = await svc.GetByIdAsync(id, ct);
187
+ return Results.Ok(user);
188
+ })
189
+ .WithName("GetUser")
190
+ .Produces<UserDto>();
191
+
192
+ return group;
193
+ }
194
+ }
195
+ ```
196
+
197
+ ### Middleware
198
+ ```csharp
199
+ // Middleware/RequestLoggingMiddleware.cs
200
+ public class RequestLoggingMiddleware(RequestDelegate next, ILogger<RequestLoggingMiddleware> logger)
201
+ {
202
+ public async Task InvokeAsync(HttpContext context)
203
+ {
204
+ var sw = Stopwatch.StartNew();
205
+ try
206
+ {
207
+ await next(context);
208
+ }
209
+ finally
210
+ {
211
+ sw.Stop();
212
+ logger.LogInformation(
213
+ "{Method} {Path} {StatusCode} in {Elapsed}ms",
214
+ context.Request.Method,
215
+ context.Request.Path,
216
+ context.Response.StatusCode,
217
+ sw.ElapsedMilliseconds);
218
+ }
219
+ }
220
+ }
221
+
222
+ // In Program.cs vor anderer Middleware registrieren:
223
+ app.UseMiddleware<RequestLoggingMiddleware>();
224
+ ```
225
+
226
+ ### Hintergrunddienste
227
+ ```csharp
228
+ // Services/CleanupService.cs
229
+ public class CleanupService(IServiceProvider services, ILogger<CleanupService> logger)
230
+ : BackgroundService
231
+ {
232
+ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
233
+ {
234
+ while (!stoppingToken.IsCancellationRequested)
235
+ {
236
+ await DoCleanupAsync(stoppingToken);
237
+ await Task.Delay(TimeSpan.FromHours(1), stoppingToken);
238
+ }
239
+ }
240
+
241
+ private async Task DoCleanupAsync(CancellationToken ct)
242
+ {
243
+ // Neuen Scope für jede Iteration verwenden — BackgroundService ist Singleton
244
+ using var scope = services.CreateScope();
245
+ var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
246
+ var cutoff = DateTimeOffset.UtcNow.AddDays(-30);
247
+ await db.Sessions.Where(s => s.ExpiresAt < cutoff).ExecuteDeleteAsync(ct);
248
+ }
249
+ }
250
+
251
+ // Registrieren: builder.Services.AddHostedService<CleanupService>();
252
+ ```
253
+
254
+ ### LINQ-Best-Practices
255
+ ```csharp
256
+ // AsNoTracking() immer für schreibgeschützte Abfragen verwenden
257
+ var users = await db.Users.AsNoTracking().Where(u => u.IsActive).ToListAsync(ct);
258
+
259
+ // Nur benötigte Spalten auswählen — vollständige Entitäten für Projektionen vermeiden
260
+ var emails = await db.Users
261
+ .Where(u => u.IsActive)
262
+ .Select(u => u.Email)
263
+ .ToListAsync(ct);
264
+
265
+ // ExecuteUpdateAsync/ExecuteDeleteAsync für Bulk-Ops verwenden — überspringt das Laden von Entitäten
266
+ await db.Users
267
+ .Where(u => !u.IsActive && u.CreatedAt < cutoff)
268
+ .ExecuteDeleteAsync(ct);
269
+
270
+ // N+1 vermeiden: Include() für verknüpfte Daten verwenden
271
+ var posts = await db.Posts
272
+ .Include(p => p.Author)
273
+ .Include(p => p.Tags)
274
+ .Where(p => p.Published)
275
+ .AsNoTracking()
276
+ .ToListAsync(ct);
277
+ ```
278
+
279
+ ### DTOs und Records
280
+ ```csharp
281
+ // Records für unveränderliche DTOs verwenden
282
+ public record UserDto(Guid Id, string Email, DateTimeOffset CreatedAt);
283
+ public record CreateUserRequest(
284
+ [property: Required, EmailAddress] string Email,
285
+ [property: Required, MinLength(8)] string Password
286
+ );
287
+
288
+ // Antworttypen mit Problem Details (eingebaut in .NET)
289
+ // Results.Problem() zurückgeben oder Ausnahmen werfen, die von Middleware abgefangen werden
290
+ ```
291
+
292
+ ## Beispiel
293
+
294
+ **Benutzer:** Eine `BlogPost`-Ressource zu einer .NET Web API hinzufügen: CRUD-Endpunkte, EF Core-Entity, Migrationen und ein Hintergrundjob, der geplante Posts veröffentlicht.
295
+
296
+ **Erwartete Ausgabe:**
297
+ - `Models/BlogPost.cs` — Entity mit `Id`, `Title`, `Body`, `AuthorId` (FK zu User), `PublishedAt` (nullable), `ScheduledFor` (nullable)
298
+ - `DTOs/BlogPostDtos.cs` — `BlogPostDto`-Record, `CreateBlogPostRequest`-Record mit `[Required]`-Validierung
299
+ - `Services/IBlogPostService.cs` + `BlogPostService.cs` — CRUD-Methoden, `GetPendingScheduledAsync` für Hintergrundjob
300
+ - `Controllers/BlogPostsController.cs` — alle CRUD mit korrekten Statuscodes
301
+ - `Services/PostPublisherService.cs` — `BackgroundService`, der jede Minute prüft und fällige Posts veröffentlicht
302
+ - EF Core-Migration: `dotnet ef migrations add AddBlogPosts`
303
+
304
+ ---
305
+
306
+ > **Mit uns arbeiten:** Claudient wird von [Uitbreiden](https://uitbreiden.com/) unterstützt — wir bauen KI-Produkte und B2B-Lösungen mit Entwickler-Communities. [uitbreiden.com](https://uitbreiden.com/)
@@ -0,0 +1,306 @@
1
+ > 🇪🇸 Esta es la traducción en español. [Versión en inglés](../csharp.md).
2
+
3
+ # Skill de C#/.NET
4
+
5
+ ## Cuándo activar
6
+ - Construir una Web API en .NET (minimal API o basada en controladores)
7
+ - Configurar Entity Framework Core con migraciones
8
+ - Configurar el contenedor de inyección de dependencias de .NET
9
+ - Escribir servicios en segundo plano con `IHostedService` o `BackgroundService`
10
+ - Implementar componentes del pipeline de middleware
11
+ - Escribir consultas LINQ y entender la ejecución diferida
12
+ - Configurar async/await correctamente en ASP.NET Core
13
+
14
+ ## Cuándo NO usar
15
+ - Servicios en Node.js o Python
16
+ - Codebases legacy de .NET Framework (pre-.NET 5) — los patrones difieren
17
+ - Blazor o MAUI frontend — preocupaciones diferentes
18
+ - Desarrollo de juegos con Unity — runtime diferente
19
+
20
+ ## Instrucciones
21
+
22
+ ### Estructura del proyecto
23
+ ```
24
+ MyApi/
25
+ ├── MyApi.sln
26
+ ├── src/
27
+ │ └── MyApi/
28
+ │ ├── Program.cs # Punto de entrada + contenedor DI
29
+ │ ├── appsettings.json
30
+ │ ├── appsettings.Development.json
31
+ │ ├── Controllers/ # API basada en controladores
32
+ │ ├── Endpoints/ # Extensiones de minimal API
33
+ │ ├── Models/ # Entidades de EF Core
34
+ │ ├── DTOs/ # Formas de solicitud/respuesta
35
+ │ ├── Services/ # Interfaces + implementaciones de lógica de negocio
36
+ │ ├── Data/
37
+ │ │ └── AppDbContext.cs
38
+ │ └── Middleware/
39
+ └── tests/
40
+ └── MyApi.Tests/
41
+ ```
42
+
43
+ ### Program.cs — configuración de minimal API
44
+ ```csharp
45
+ // Program.cs — sentencias de nivel superior de .NET 6+ + minimal API
46
+ var builder = WebApplication.CreateBuilder(args);
47
+
48
+ // Registrar servicios
49
+ builder.Services.AddDbContext<AppDbContext>(options =>
50
+ options.UseNpgsql(builder.Configuration.GetConnectionString("Default")));
51
+
52
+ builder.Services.AddScoped<IUserService, UserService>();
53
+ builder.Services.AddControllers();
54
+ builder.Services.AddEndpointsApiExplorer();
55
+ builder.Services.AddSwaggerGen();
56
+
57
+ var app = builder.Build();
58
+
59
+ if (app.Environment.IsDevelopment())
60
+ {
61
+ app.UseSwagger();
62
+ app.UseSwaggerUI();
63
+ }
64
+
65
+ app.UseHttpsRedirection();
66
+ app.UseAuthentication();
67
+ app.UseAuthorization();
68
+ app.MapControllers();
69
+
70
+ // Endpoints de minimal API
71
+ app.MapGroup("/api/v1").MapUserEndpoints();
72
+
73
+ app.Run();
74
+ ```
75
+
76
+ ### Entidad EF Core + DbContext
77
+ ```csharp
78
+ // Models/User.cs
79
+ public class User
80
+ {
81
+ public Guid Id { get; set; } = Guid.NewGuid();
82
+ public required string Email { get; set; }
83
+ public required string PasswordHash { get; set; }
84
+ public bool IsActive { get; set; } = true;
85
+ public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
86
+
87
+ public ICollection<Post> Posts { get; set; } = [];
88
+ }
89
+
90
+ // Data/AppDbContext.cs
91
+ public class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(options)
92
+ {
93
+ public DbSet<User> Users => Set<User>();
94
+ public DbSet<Post> Posts => Set<Post>();
95
+
96
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
97
+ {
98
+ modelBuilder.Entity<User>(e =>
99
+ {
100
+ e.HasIndex(u => u.Email).IsUnique();
101
+ e.Property(u => u.Email).HasMaxLength(320);
102
+ });
103
+ }
104
+ }
105
+ ```
106
+
107
+ ### Inyección de dependencias — servicios
108
+ ```csharp
109
+ // Services/IUserService.cs
110
+ public interface IUserService
111
+ {
112
+ Task<UserDto> GetByIdAsync(Guid id, CancellationToken ct = default);
113
+ Task<UserDto> CreateAsync(CreateUserRequest request, CancellationToken ct = default);
114
+ }
115
+
116
+ // Services/UserService.cs
117
+ public class UserService(AppDbContext db) : IUserService
118
+ {
119
+ public async Task<UserDto> GetByIdAsync(Guid id, CancellationToken ct = default)
120
+ {
121
+ var user = await db.Users
122
+ .AsNoTracking()
123
+ .FirstOrDefaultAsync(u => u.Id == id, ct)
124
+ ?? throw new NotFoundException($"User {id} not found");
125
+
126
+ return new UserDto(user.Id, user.Email, user.CreatedAt);
127
+ }
128
+
129
+ public async Task<UserDto> CreateAsync(CreateUserRequest request, CancellationToken ct = default)
130
+ {
131
+ if (await db.Users.AnyAsync(u => u.Email == request.Email, ct))
132
+ throw new ConflictException("Email already in use");
133
+
134
+ var user = new User
135
+ {
136
+ Email = request.Email,
137
+ PasswordHash = BCrypt.Net.BCrypt.HashPassword(request.Password)
138
+ };
139
+ db.Users.Add(user);
140
+ await db.SaveChangesAsync(ct);
141
+ return new UserDto(user.Id, user.Email, user.CreatedAt);
142
+ }
143
+ }
144
+ ```
145
+
146
+ ### API basada en controladores
147
+ ```csharp
148
+ [ApiController]
149
+ [Route("api/v1/[controller]")]
150
+ public class UsersController(IUserService userService) : ControllerBase
151
+ {
152
+ [HttpGet("{id:guid}")]
153
+ [ProducesResponseType<UserDto>(StatusCodes.Status200OK)]
154
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
155
+ public async Task<IActionResult> GetUser(Guid id, CancellationToken ct)
156
+ {
157
+ var user = await userService.GetByIdAsync(id, ct);
158
+ return Ok(user);
159
+ }
160
+
161
+ [HttpPost]
162
+ [ProducesResponseType<UserDto>(StatusCodes.Status201Created)]
163
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
164
+ [ProducesResponseType(StatusCodes.Status409Conflict)]
165
+ public async Task<IActionResult> CreateUser(
166
+ [FromBody] CreateUserRequest request,
167
+ CancellationToken ct)
168
+ {
169
+ var user = await userService.CreateAsync(request, ct);
170
+ return CreatedAtAction(nameof(GetUser), new { id = user.Id }, user);
171
+ }
172
+ }
173
+ ```
174
+
175
+ ### Endpoints de minimal API (patrón de método de extensión)
176
+ ```csharp
177
+ // Endpoints/UserEndpoints.cs
178
+ public static class UserEndpoints
179
+ {
180
+ public static RouteGroupBuilder MapUserEndpoints(this RouteGroupBuilder group)
181
+ {
182
+ var users = group.MapGroup("/users").WithTags("Users");
183
+
184
+ users.MapGet("/{id:guid}", async (Guid id, IUserService svc, CancellationToken ct) =>
185
+ {
186
+ var user = await svc.GetByIdAsync(id, ct);
187
+ return Results.Ok(user);
188
+ })
189
+ .WithName("GetUser")
190
+ .Produces<UserDto>();
191
+
192
+ return group;
193
+ }
194
+ }
195
+ ```
196
+
197
+ ### Middleware
198
+ ```csharp
199
+ // Middleware/RequestLoggingMiddleware.cs
200
+ public class RequestLoggingMiddleware(RequestDelegate next, ILogger<RequestLoggingMiddleware> logger)
201
+ {
202
+ public async Task InvokeAsync(HttpContext context)
203
+ {
204
+ var sw = Stopwatch.StartNew();
205
+ try
206
+ {
207
+ await next(context);
208
+ }
209
+ finally
210
+ {
211
+ sw.Stop();
212
+ logger.LogInformation(
213
+ "{Method} {Path} {StatusCode} in {Elapsed}ms",
214
+ context.Request.Method,
215
+ context.Request.Path,
216
+ context.Response.StatusCode,
217
+ sw.ElapsedMilliseconds);
218
+ }
219
+ }
220
+ }
221
+
222
+ // Registrar en Program.cs antes de otro middleware:
223
+ app.UseMiddleware<RequestLoggingMiddleware>();
224
+ ```
225
+
226
+ ### Servicios en segundo plano
227
+ ```csharp
228
+ // Services/CleanupService.cs
229
+ public class CleanupService(IServiceProvider services, ILogger<CleanupService> logger)
230
+ : BackgroundService
231
+ {
232
+ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
233
+ {
234
+ while (!stoppingToken.IsCancellationRequested)
235
+ {
236
+ await DoCleanupAsync(stoppingToken);
237
+ await Task.Delay(TimeSpan.FromHours(1), stoppingToken);
238
+ }
239
+ }
240
+
241
+ private async Task DoCleanupAsync(CancellationToken ct)
242
+ {
243
+ // Usar un nuevo scope para cada iteración — BackgroundService es singleton
244
+ using var scope = services.CreateScope();
245
+ var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
246
+ var cutoff = DateTimeOffset.UtcNow.AddDays(-30);
247
+ await db.Sessions.Where(s => s.ExpiresAt < cutoff).ExecuteDeleteAsync(ct);
248
+ }
249
+ }
250
+
251
+ // Registrar: builder.Services.AddHostedService<CleanupService>();
252
+ ```
253
+
254
+ ### Mejores prácticas de LINQ
255
+ ```csharp
256
+ // Siempre usar AsNoTracking() para consultas de solo lectura
257
+ var users = await db.Users.AsNoTracking().Where(u => u.IsActive).ToListAsync(ct);
258
+
259
+ // Seleccionar solo las columnas necesarias — evitar cargar entidades completas para proyecciones
260
+ var emails = await db.Users
261
+ .Where(u => u.IsActive)
262
+ .Select(u => u.Email)
263
+ .ToListAsync(ct);
264
+
265
+ // Usar ExecuteUpdateAsync/ExecuteDeleteAsync para operaciones masivas — evita cargar entidades
266
+ await db.Users
267
+ .Where(u => !u.IsActive && u.CreatedAt < cutoff)
268
+ .ExecuteDeleteAsync(ct);
269
+
270
+ // Evitar N+1: usar Include() para datos relacionados
271
+ var posts = await db.Posts
272
+ .Include(p => p.Author)
273
+ .Include(p => p.Tags)
274
+ .Where(p => p.Published)
275
+ .AsNoTracking()
276
+ .ToListAsync(ct);
277
+ ```
278
+
279
+ ### DTOs y records
280
+ ```csharp
281
+ // Usar records para DTOs inmutables
282
+ public record UserDto(Guid Id, string Email, DateTimeOffset CreatedAt);
283
+ public record CreateUserRequest(
284
+ [property: Required, EmailAddress] string Email,
285
+ [property: Required, MinLength(8)] string Password
286
+ );
287
+
288
+ // Tipos de respuesta con problem details (integrado en .NET)
289
+ // Devolver Results.Problem() o lanzar excepciones capturadas por el middleware
290
+ ```
291
+
292
+ ## Ejemplo
293
+
294
+ **Usuario:** Agregar un recurso `BlogPost` a una Web API de .NET: endpoints CRUD, entidad EF Core, migraciones y un trabajo en segundo plano que publica posts programados.
295
+
296
+ **Salida esperada:**
297
+ - `Models/BlogPost.cs` — entidad con `Id`, `Title`, `Body`, `AuthorId` (FK a User), `PublishedAt` (nullable), `ScheduledFor` (nullable)
298
+ - `DTOs/BlogPostDtos.cs` — record `BlogPostDto`, record `CreateBlogPostRequest` con validación `[Required]`
299
+ - `Services/IBlogPostService.cs` + `BlogPostService.cs` — métodos CRUD, `GetPendingScheduledAsync` para el trabajo en segundo plano
300
+ - `Controllers/BlogPostsController.cs` — todo CRUD con códigos de estado apropiados
301
+ - `Services/PostPublisherService.cs` — `BackgroundService` que verifica cada minuto y publica los posts pendientes
302
+ - Migración EF Core: `dotnet ef migrations add AddBlogPosts`
303
+
304
+ ---
305
+
306
+ > **Trabaja con nosotros:** Claudient está respaldado por [Uitbreiden](https://uitbreiden.com/) — construimos productos de IA y soluciones B2B con comunidades de desarrolladores. [uitbreiden.com](https://uitbreiden.com/)