autoworkflow 3.1.5 → 3.6.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 (124) hide show
  1. package/.claude/commands/analyze.md +19 -0
  2. package/.claude/commands/audit.md +26 -0
  3. package/.claude/commands/build.md +39 -0
  4. package/.claude/commands/commit.md +25 -0
  5. package/.claude/commands/fix.md +23 -0
  6. package/.claude/commands/plan.md +18 -0
  7. package/.claude/commands/suggest.md +23 -0
  8. package/.claude/commands/verify.md +18 -0
  9. package/.claude/hooks/post-bash-router.sh +20 -0
  10. package/.claude/hooks/post-commit.sh +140 -0
  11. package/.claude/hooks/post-edit.sh +190 -17
  12. package/.claude/hooks/pre-edit.sh +221 -0
  13. package/.claude/hooks/session-check.sh +90 -0
  14. package/.claude/settings.json +56 -6
  15. package/.claude/settings.local.json +5 -1
  16. package/.claude/skills/actix.md +337 -0
  17. package/.claude/skills/alembic.md +504 -0
  18. package/.claude/skills/angular.md +237 -0
  19. package/.claude/skills/api-design.md +187 -0
  20. package/.claude/skills/aspnet-core.md +377 -0
  21. package/.claude/skills/astro.md +245 -0
  22. package/.claude/skills/auth-clerk.md +327 -0
  23. package/.claude/skills/auth-firebase.md +367 -0
  24. package/.claude/skills/auth-nextauth.md +359 -0
  25. package/.claude/skills/auth-supabase.md +368 -0
  26. package/.claude/skills/axum.md +386 -0
  27. package/.claude/skills/blazor.md +456 -0
  28. package/.claude/skills/chi.md +348 -0
  29. package/.claude/skills/code-review.md +133 -0
  30. package/.claude/skills/csharp.md +296 -0
  31. package/.claude/skills/css-modules.md +325 -0
  32. package/.claude/skills/cypress.md +343 -0
  33. package/.claude/skills/debugging.md +133 -0
  34. package/.claude/skills/diesel.md +392 -0
  35. package/.claude/skills/django.md +301 -0
  36. package/.claude/skills/docker.md +319 -0
  37. package/.claude/skills/doctrine.md +473 -0
  38. package/.claude/skills/documentation.md +182 -0
  39. package/.claude/skills/dotnet.md +409 -0
  40. package/.claude/skills/drizzle.md +293 -0
  41. package/.claude/skills/echo.md +321 -0
  42. package/.claude/skills/eloquent.md +256 -0
  43. package/.claude/skills/emotion.md +426 -0
  44. package/.claude/skills/entity-framework.md +370 -0
  45. package/.claude/skills/express.md +316 -0
  46. package/.claude/skills/fastapi.md +329 -0
  47. package/.claude/skills/fastify.md +299 -0
  48. package/.claude/skills/fiber.md +315 -0
  49. package/.claude/skills/flask.md +322 -0
  50. package/.claude/skills/gin.md +342 -0
  51. package/.claude/skills/git.md +116 -0
  52. package/.claude/skills/github-actions.md +353 -0
  53. package/.claude/skills/go.md +377 -0
  54. package/.claude/skills/gorm.md +409 -0
  55. package/.claude/skills/graphql.md +478 -0
  56. package/.claude/skills/hibernate.md +379 -0
  57. package/.claude/skills/hono.md +306 -0
  58. package/.claude/skills/java.md +400 -0
  59. package/.claude/skills/jest.md +313 -0
  60. package/.claude/skills/jpa.md +282 -0
  61. package/.claude/skills/kotlin.md +347 -0
  62. package/.claude/skills/kubernetes.md +363 -0
  63. package/.claude/skills/laravel.md +414 -0
  64. package/.claude/skills/mcp-browser.md +320 -0
  65. package/.claude/skills/mcp-database.md +219 -0
  66. package/.claude/skills/mcp-fetch.md +241 -0
  67. package/.claude/skills/mcp-filesystem.md +204 -0
  68. package/.claude/skills/mcp-github.md +217 -0
  69. package/.claude/skills/mcp-memory.md +240 -0
  70. package/.claude/skills/mcp-search.md +218 -0
  71. package/.claude/skills/mcp-slack.md +262 -0
  72. package/.claude/skills/micronaut.md +388 -0
  73. package/.claude/skills/mongodb.md +319 -0
  74. package/.claude/skills/mongoose.md +355 -0
  75. package/.claude/skills/mysql.md +281 -0
  76. package/.claude/skills/nestjs.md +335 -0
  77. package/.claude/skills/nextjs-app-router.md +260 -0
  78. package/.claude/skills/nextjs-pages.md +172 -0
  79. package/.claude/skills/nuxt.md +202 -0
  80. package/.claude/skills/openapi.md +489 -0
  81. package/.claude/skills/performance.md +199 -0
  82. package/.claude/skills/php.md +398 -0
  83. package/.claude/skills/playwright.md +371 -0
  84. package/.claude/skills/postgresql.md +257 -0
  85. package/.claude/skills/prisma.md +293 -0
  86. package/.claude/skills/pydantic.md +304 -0
  87. package/.claude/skills/pytest.md +313 -0
  88. package/.claude/skills/python.md +272 -0
  89. package/.claude/skills/quarkus.md +377 -0
  90. package/.claude/skills/react.md +230 -0
  91. package/.claude/skills/redis.md +391 -0
  92. package/.claude/skills/refactoring.md +143 -0
  93. package/.claude/skills/remix.md +246 -0
  94. package/.claude/skills/rest-api.md +490 -0
  95. package/.claude/skills/rocket.md +366 -0
  96. package/.claude/skills/rust.md +341 -0
  97. package/.claude/skills/sass.md +380 -0
  98. package/.claude/skills/sea-orm.md +382 -0
  99. package/.claude/skills/security.md +167 -0
  100. package/.claude/skills/sequelize.md +395 -0
  101. package/.claude/skills/spring-boot.md +416 -0
  102. package/.claude/skills/sqlalchemy.md +269 -0
  103. package/.claude/skills/sqlx-rust.md +408 -0
  104. package/.claude/skills/state-jotai.md +346 -0
  105. package/.claude/skills/state-mobx.md +353 -0
  106. package/.claude/skills/state-pinia.md +431 -0
  107. package/.claude/skills/state-redux.md +337 -0
  108. package/.claude/skills/state-tanstack-query.md +434 -0
  109. package/.claude/skills/state-zustand.md +340 -0
  110. package/.claude/skills/styled-components.md +403 -0
  111. package/.claude/skills/svelte.md +238 -0
  112. package/.claude/skills/sveltekit.md +207 -0
  113. package/.claude/skills/symfony.md +437 -0
  114. package/.claude/skills/tailwind.md +279 -0
  115. package/.claude/skills/terraform.md +394 -0
  116. package/.claude/skills/testing-library.md +371 -0
  117. package/.claude/skills/trpc.md +426 -0
  118. package/.claude/skills/typeorm.md +368 -0
  119. package/.claude/skills/vitest.md +330 -0
  120. package/.claude/skills/vue.md +202 -0
  121. package/.claude/skills/warp.md +365 -0
  122. package/README.md +163 -52
  123. package/package.json +1 -1
  124. package/system/triggers.md +256 -17
@@ -0,0 +1,366 @@
1
+ # Rocket Framework Skill
2
+
3
+ ## Application Setup
4
+ \`\`\`rust
5
+ #[macro_use] extern crate rocket;
6
+
7
+ use rocket::{Build, Rocket, fairing::AdHoc};
8
+
9
+ #[launch]
10
+ fn rocket() -> Rocket<Build> {
11
+ rocket::build()
12
+ .attach(DbPool::init())
13
+ .attach(AdHoc::config::<AppConfig>())
14
+ .mount("/", routes![health])
15
+ .mount("/api/v1/auth", routes![login, register])
16
+ .mount("/api/v1/users", routes![
17
+ list_users,
18
+ create_user,
19
+ get_user,
20
+ update_user,
21
+ delete_user
22
+ ])
23
+ .register("/", catchers![
24
+ not_found,
25
+ internal_error,
26
+ unauthorized
27
+ ])
28
+ }
29
+
30
+ #[get("/health")]
31
+ fn health() -> &'static str {
32
+ "OK"
33
+ }
34
+ \`\`\`
35
+
36
+ ## Database with rocket_db_pools
37
+ \`\`\`rust
38
+ use rocket_db_pools::{Database, Connection};
39
+ use rocket_db_pools::sqlx::{self, PgPool};
40
+
41
+ #[derive(Database)]
42
+ #[database("postgres")]
43
+ pub struct DbPool(PgPool);
44
+
45
+ // Access in handlers
46
+ #[get("/<id>")]
47
+ async fn get_user(
48
+ mut db: Connection<DbPool>,
49
+ id: &str,
50
+ ) -> Result<Json<User>, AppError> {
51
+ let user = sqlx::query_as!(User, "SELECT * FROM users WHERE id = $1", id)
52
+ .fetch_optional(&mut **db)
53
+ .await?
54
+ .ok_or(AppError::NotFound)?;
55
+
56
+ Ok(Json(user))
57
+ }
58
+ \`\`\`
59
+
60
+ ## Request Guards
61
+ \`\`\`rust
62
+ use rocket::{
63
+ request::{self, Request, FromRequest, Outcome},
64
+ http::Status,
65
+ };
66
+
67
+ pub struct AuthUser {
68
+ pub user_id: String,
69
+ pub role: String,
70
+ }
71
+
72
+ #[rocket::async_trait]
73
+ impl<'r> FromRequest<'r> for AuthUser {
74
+ type Error = AppError;
75
+
76
+ async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
77
+ let auth_header = request.headers().get_one("Authorization");
78
+
79
+ let token = match auth_header {
80
+ Some(h) if h.starts_with("Bearer ") => &h[7..],
81
+ _ => return Outcome::Error((Status::Unauthorized, AppError::Unauthorized)),
82
+ };
83
+
84
+ match validate_token(token) {
85
+ Ok(claims) => Outcome::Success(AuthUser {
86
+ user_id: claims.sub,
87
+ role: claims.role,
88
+ }),
89
+ Err(_) => Outcome::Error((Status::Unauthorized, AppError::Unauthorized)),
90
+ }
91
+ }
92
+ }
93
+
94
+ // Use in protected routes
95
+ #[get("/profile")]
96
+ async fn get_profile(
97
+ auth: AuthUser,
98
+ mut db: Connection<DbPool>,
99
+ ) -> Result<Json<User>, AppError> {
100
+ let user = find_user(&mut db, &auth.user_id).await?;
101
+ Ok(Json(user))
102
+ }
103
+
104
+ // Optional auth
105
+ #[get("/posts")]
106
+ async fn list_posts(
107
+ auth: Option<AuthUser>,
108
+ mut db: Connection<DbPool>,
109
+ ) -> Result<Json<Vec<Post>>, AppError> {
110
+ let posts = if let Some(user) = auth {
111
+ // Return user's posts
112
+ get_user_posts(&mut db, &user.user_id).await?
113
+ } else {
114
+ // Return public posts
115
+ get_public_posts(&mut db).await?
116
+ };
117
+ Ok(Json(posts))
118
+ }
119
+ \`\`\`
120
+
121
+ ## Request Data and Forms
122
+ \`\`\`rust
123
+ use rocket::serde::{Deserialize, json::Json};
124
+ use rocket::form::Form;
125
+
126
+ // JSON body
127
+ #[derive(Deserialize)]
128
+ #[serde(crate = "rocket::serde")]
129
+ pub struct CreateUserRequest {
130
+ pub email: String,
131
+ pub name: String,
132
+ pub password: String,
133
+ }
134
+
135
+ #[post("/", data = "<body>")]
136
+ async fn create_user(
137
+ mut db: Connection<DbPool>,
138
+ body: Json<CreateUserRequest>,
139
+ ) -> Result<(Status, Json<User>), AppError> {
140
+ // Validate
141
+ if body.email.is_empty() {
142
+ return Err(AppError::Validation("Email is required".into()));
143
+ }
144
+
145
+ let user = User::new(&body.email, &body.name, &body.password)?;
146
+ save_user(&mut db, &user).await?;
147
+
148
+ Ok((Status::Created, Json(user)))
149
+ }
150
+
151
+ // Form data
152
+ #[derive(FromForm)]
153
+ pub struct LoginForm {
154
+ email: String,
155
+ password: String,
156
+ }
157
+
158
+ #[post("/login", data = "<form>")]
159
+ async fn login_form(form: Form<LoginForm>) -> Result<Json<TokenResponse>, AppError> {
160
+ // Process form...
161
+ }
162
+
163
+ // Query parameters
164
+ #[get("/?<page>&<per_page>")]
165
+ async fn list_users(
166
+ mut db: Connection<DbPool>,
167
+ page: Option<u32>,
168
+ per_page: Option<u32>,
169
+ ) -> Result<Json<Vec<User>>, AppError> {
170
+ let page = page.unwrap_or(1);
171
+ let per_page = per_page.unwrap_or(20).min(100);
172
+ let offset = (page - 1) * per_page;
173
+
174
+ let users = sqlx::query_as!(User,
175
+ "SELECT * FROM users LIMIT $1 OFFSET $2",
176
+ per_page as i64,
177
+ offset as i64
178
+ )
179
+ .fetch_all(&mut **db)
180
+ .await?;
181
+
182
+ Ok(Json(users))
183
+ }
184
+ \`\`\`
185
+
186
+ ## Error Handling
187
+ \`\`\`rust
188
+ use rocket::{
189
+ response::{self, Responder, Response},
190
+ http::{Status, ContentType},
191
+ Request,
192
+ };
193
+ use thiserror::Error;
194
+
195
+ #[derive(Error, Debug)]
196
+ pub enum AppError {
197
+ #[error("Resource not found")]
198
+ NotFound,
199
+
200
+ #[error("Unauthorized")]
201
+ Unauthorized,
202
+
203
+ #[error("Validation error: {0}")]
204
+ Validation(String),
205
+
206
+ #[error("Database error")]
207
+ Database(#[from] sqlx::Error),
208
+ }
209
+
210
+ impl<'r> Responder<'r, 'static> for AppError {
211
+ fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> {
212
+ let (status, message) = match &self {
213
+ AppError::NotFound => (Status::NotFound, self.to_string()),
214
+ AppError::Unauthorized => (Status::Unauthorized, self.to_string()),
215
+ AppError::Validation(_) => (Status::BadRequest, self.to_string()),
216
+ AppError::Database(e) => {
217
+ eprintln!("Database error: {:?}", e);
218
+ (Status::InternalServerError, "Internal server error".into())
219
+ }
220
+ };
221
+
222
+ let body = format!(r#"{{"error":"{}"}}"#, message);
223
+
224
+ Response::build()
225
+ .status(status)
226
+ .header(ContentType::JSON)
227
+ .sized_body(body.len(), std::io::Cursor::new(body))
228
+ .ok()
229
+ }
230
+ }
231
+
232
+ // Error catchers
233
+ #[catch(404)]
234
+ fn not_found() -> Json<serde_json::Value> {
235
+ Json(serde_json::json!({
236
+ "error": "Resource not found"
237
+ }))
238
+ }
239
+
240
+ #[catch(500)]
241
+ fn internal_error() -> Json<serde_json::Value> {
242
+ Json(serde_json::json!({
243
+ "error": "Internal server error"
244
+ }))
245
+ }
246
+
247
+ #[catch(401)]
248
+ fn unauthorized() -> Json<serde_json::Value> {
249
+ Json(serde_json::json!({
250
+ "error": "Unauthorized"
251
+ }))
252
+ }
253
+ \`\`\`
254
+
255
+ ## Fairings (Middleware)
256
+ \`\`\`rust
257
+ use rocket::{
258
+ fairing::{self, Fairing, Info, Kind},
259
+ Data, Request, Response,
260
+ };
261
+
262
+ pub struct RequestTimer;
263
+
264
+ #[rocket::async_trait]
265
+ impl Fairing for RequestTimer {
266
+ fn info(&self) -> Info {
267
+ Info {
268
+ name: "Request Timer",
269
+ kind: Kind::Request | Kind::Response,
270
+ }
271
+ }
272
+
273
+ async fn on_request(&self, request: &mut Request<'_>, _: &mut Data<'_>) {
274
+ request.local_cache(|| std::time::Instant::now());
275
+ }
276
+
277
+ async fn on_response<'r>(&self, request: &'r Request<'_>, _: &mut Response<'r>) {
278
+ let start = request.local_cache(|| std::time::Instant::now());
279
+ let duration = start.elapsed();
280
+ println!("{} {} - {:?}", request.method(), request.uri(), duration);
281
+ }
282
+ }
283
+
284
+ // CORS fairing
285
+ use rocket::fairing::AdHoc;
286
+
287
+ pub fn cors_fairing() -> AdHoc {
288
+ AdHoc::on_response("CORS", |_, response| Box::pin(async move {
289
+ response.set_header(rocket::http::Header::new("Access-Control-Allow-Origin", "*"));
290
+ response.set_header(rocket::http::Header::new("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE"));
291
+ response.set_header(rocket::http::Header::new("Access-Control-Allow-Headers", "Authorization, Content-Type"));
292
+ }))
293
+ }
294
+
295
+ // Attach fairings
296
+ #[launch]
297
+ fn rocket() -> Rocket<Build> {
298
+ rocket::build()
299
+ .attach(RequestTimer)
300
+ .attach(cors_fairing())
301
+ // ...
302
+ }
303
+ \`\`\`
304
+
305
+ ## Testing
306
+ \`\`\`rust
307
+ #[cfg(test)]
308
+ mod tests {
309
+ use super::*;
310
+ use rocket::local::asynchronous::Client;
311
+ use rocket::http::{Status, ContentType};
312
+
313
+ async fn create_client() -> Client {
314
+ Client::tracked(rocket())
315
+ .await
316
+ .expect("valid rocket instance")
317
+ }
318
+
319
+ #[rocket::async_test]
320
+ async fn test_health() {
321
+ let client = create_client().await;
322
+ let response = client.get("/health").dispatch().await;
323
+ assert_eq!(response.status(), Status::Ok);
324
+ }
325
+
326
+ #[rocket::async_test]
327
+ async fn test_create_user() {
328
+ let client = create_client().await;
329
+ let response = client
330
+ .post("/api/v1/users")
331
+ .header(ContentType::JSON)
332
+ .body(r#"{"email":"test@example.com","name":"Test","password":"password123"}"#)
333
+ .dispatch()
334
+ .await;
335
+
336
+ assert_eq!(response.status(), Status::Created);
337
+ }
338
+
339
+ #[rocket::async_test]
340
+ async fn test_get_user_not_found() {
341
+ let client = create_client().await;
342
+ let response = client.get("/api/v1/users/nonexistent").dispatch().await;
343
+ assert_eq!(response.status(), Status::NotFound);
344
+ }
345
+
346
+ #[rocket::async_test]
347
+ async fn test_protected_route_without_auth() {
348
+ let client = create_client().await;
349
+ let response = client.get("/api/v1/users/profile").dispatch().await;
350
+ assert_eq!(response.status(), Status::Unauthorized);
351
+ }
352
+ }
353
+ \`\`\`
354
+
355
+ ## ✅ DO
356
+ - Use request guards for auth and validation
357
+ - Implement \`Responder\` for custom error types
358
+ - Register error catchers with \`register\`
359
+ - Use fairings for cross-cutting concerns
360
+ - Use \`rocket_db_pools\` for database connections
361
+
362
+ ## ❌ DON'T
363
+ - Don't use \`.unwrap()\` in handlers - return \`Result\`
364
+ - Don't forget to mount routes with \`mount\`
365
+ - Don't block async handlers with sync code
366
+ - Don't expose internal errors to clients
@@ -0,0 +1,341 @@
1
+ # Rust Skill
2
+
3
+ ## Ownership & Borrowing
4
+ \`\`\`rust
5
+ // Ownership - values have a single owner
6
+ let s1 = String::from("hello");
7
+ let s2 = s1; // s1 is MOVED, can no longer be used
8
+
9
+ // Clone for explicit copy
10
+ let s1 = String::from("hello");
11
+ let s2 = s1.clone(); // Both valid
12
+
13
+ // Borrowing - references without ownership
14
+ fn print_length(s: &String) -> usize {
15
+ s.len() // Can read but not modify
16
+ }
17
+
18
+ // Mutable borrow - only ONE at a time
19
+ fn append(s: &mut String) {
20
+ s.push_str(" world");
21
+ }
22
+
23
+ let mut s = String::from("hello");
24
+ append(&mut s); // s is now "hello world"
25
+
26
+ // Lifetimes - ensure references are valid
27
+ fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
28
+ if x.len() > y.len() { x } else { y }
29
+ }
30
+ \`\`\`
31
+
32
+ ## Error Handling with Result and Option
33
+ \`\`\`rust
34
+ use std::fs::File;
35
+ use std::io::{self, Read};
36
+
37
+ // Result<T, E> for operations that can fail
38
+ fn read_file(path: &str) -> Result<String, io::Error> {
39
+ let mut file = File::open(path)?; // ? propagates error
40
+ let mut contents = String::new();
41
+ file.read_to_string(&mut contents)?;
42
+ Ok(contents)
43
+ }
44
+
45
+ // Option<T> for values that may not exist
46
+ fn find_user(id: u32) -> Option<User> {
47
+ users.iter().find(|u| u.id == id).cloned()
48
+ }
49
+
50
+ // Pattern matching on Result/Option
51
+ fn process_user(id: u32) -> Result<(), AppError> {
52
+ match find_user(id) {
53
+ Some(user) => {
54
+ println!("Found: {}", user.name);
55
+ Ok(())
56
+ }
57
+ None => Err(AppError::NotFound),
58
+ }
59
+ }
60
+
61
+ // Combinators for cleaner code
62
+ fn get_user_email(id: u32) -> Option<String> {
63
+ find_user(id)
64
+ .filter(|u| u.is_active)
65
+ .map(|u| u.email.clone())
66
+ }
67
+
68
+ // Converting between Option and Result
69
+ fn require_user(id: u32) -> Result<User, AppError> {
70
+ find_user(id).ok_or(AppError::NotFound)
71
+ }
72
+
73
+ // unwrap_or for defaults
74
+ let name = user.nickname.unwrap_or_else(|| user.name.clone());
75
+ \`\`\`
76
+
77
+ ## Custom Error Types with thiserror
78
+ \`\`\`rust
79
+ use thiserror::Error;
80
+
81
+ #[derive(Error, Debug)]
82
+ pub enum AppError {
83
+ #[error("User not found: {0}")]
84
+ NotFound(String),
85
+
86
+ #[error("Unauthorized access")]
87
+ Unauthorized,
88
+
89
+ #[error("Validation failed: {0}")]
90
+ Validation(String),
91
+
92
+ #[error("Database error")]
93
+ Database(#[from] sqlx::Error),
94
+
95
+ #[error("IO error")]
96
+ Io(#[from] std::io::Error),
97
+
98
+ #[error("External service error: {0}")]
99
+ External(String),
100
+ }
101
+
102
+ // Using the error
103
+ fn get_user(id: &str) -> Result<User, AppError> {
104
+ let user = db.find_user(id)
105
+ .map_err(AppError::Database)?
106
+ .ok_or_else(|| AppError::NotFound(id.to_string()))?;
107
+
108
+ if !user.is_active {
109
+ return Err(AppError::Validation("User is inactive".into()));
110
+ }
111
+
112
+ Ok(user)
113
+ }
114
+ \`\`\`
115
+
116
+ ## Structs and Implementations
117
+ \`\`\`rust
118
+ use serde::{Deserialize, Serialize};
119
+
120
+ #[derive(Debug, Clone, Serialize, Deserialize)]
121
+ pub struct User {
122
+ pub id: String,
123
+ pub email: String,
124
+ pub name: String,
125
+ #[serde(skip_serializing)]
126
+ password_hash: String,
127
+ pub is_active: bool,
128
+ }
129
+
130
+ impl User {
131
+ // Constructor
132
+ pub fn new(email: String, name: String, password: &str) -> Result<Self, AppError> {
133
+ let password_hash = hash_password(password)?;
134
+ Ok(Self {
135
+ id: Uuid::new_v4().to_string(),
136
+ email,
137
+ name,
138
+ password_hash,
139
+ is_active: true,
140
+ })
141
+ }
142
+
143
+ // Method
144
+ pub fn verify_password(&self, password: &str) -> bool {
145
+ verify_password(password, &self.password_hash)
146
+ }
147
+
148
+ // Builder pattern
149
+ pub fn with_id(mut self, id: String) -> Self {
150
+ self.id = id;
151
+ self
152
+ }
153
+ }
154
+
155
+ // Default trait implementation
156
+ impl Default for User {
157
+ fn default() -> Self {
158
+ Self {
159
+ id: String::new(),
160
+ email: String::new(),
161
+ name: String::from("Anonymous"),
162
+ password_hash: String::new(),
163
+ is_active: false,
164
+ }
165
+ }
166
+ }
167
+ \`\`\`
168
+
169
+ ## Traits
170
+ \`\`\`rust
171
+ // Define a trait
172
+ pub trait Repository<T> {
173
+ fn find_by_id(&self, id: &str) -> Result<Option<T>, AppError>;
174
+ fn create(&self, entity: &T) -> Result<(), AppError>;
175
+ fn update(&self, entity: &T) -> Result<(), AppError>;
176
+ fn delete(&self, id: &str) -> Result<(), AppError>;
177
+ }
178
+
179
+ // Implement for a specific type
180
+ pub struct PostgresUserRepository {
181
+ pool: PgPool,
182
+ }
183
+
184
+ impl Repository<User> for PostgresUserRepository {
185
+ fn find_by_id(&self, id: &str) -> Result<Option<User>, AppError> {
186
+ sqlx::query_as!(User, "SELECT * FROM users WHERE id = $1", id)
187
+ .fetch_optional(&self.pool)
188
+ .await
189
+ .map_err(AppError::Database)
190
+ }
191
+
192
+ // ... other implementations
193
+ }
194
+
195
+ // Trait bounds in functions
196
+ fn process<T: Repository<User> + Send + Sync>(repo: &T) -> Result<(), AppError> {
197
+ let user = repo.find_by_id("123")?;
198
+ // ...
199
+ Ok(())
200
+ }
201
+
202
+ // Using impl Trait for return types
203
+ fn create_repository() -> impl Repository<User> {
204
+ PostgresUserRepository::new()
205
+ }
206
+ \`\`\`
207
+
208
+ ## Async/Await
209
+ \`\`\`rust
210
+ use tokio;
211
+
212
+ #[tokio::main]
213
+ async fn main() -> Result<(), Box<dyn std::error::Error>> {
214
+ let result = fetch_data().await?;
215
+ println!("Got: {:?}", result);
216
+ Ok(())
217
+ }
218
+
219
+ async fn fetch_data() -> Result<Data, AppError> {
220
+ let client = reqwest::Client::new();
221
+ let response = client
222
+ .get("https://api.example.com/data")
223
+ .send()
224
+ .await?
225
+ .json::<Data>()
226
+ .await?;
227
+ Ok(response)
228
+ }
229
+
230
+ // Concurrent execution
231
+ async fn fetch_all(urls: Vec<String>) -> Vec<Result<Response, Error>> {
232
+ let futures: Vec<_> = urls.into_iter()
233
+ .map(|url| fetch_url(url))
234
+ .collect();
235
+
236
+ futures::future::join_all(futures).await
237
+ }
238
+
239
+ // With timeout
240
+ use tokio::time::{timeout, Duration};
241
+
242
+ async fn fetch_with_timeout(url: &str) -> Result<Response, AppError> {
243
+ timeout(Duration::from_secs(5), fetch_url(url))
244
+ .await
245
+ .map_err(|_| AppError::External("Request timed out".into()))?
246
+ }
247
+ \`\`\`
248
+
249
+ ## Collections and Iterators
250
+ \`\`\`rust
251
+ // Vector operations
252
+ let numbers: Vec<i32> = vec![1, 2, 3, 4, 5];
253
+
254
+ // Map, filter, collect
255
+ let doubled: Vec<i32> = numbers.iter()
256
+ .filter(|&n| n % 2 == 0)
257
+ .map(|n| n * 2)
258
+ .collect();
259
+
260
+ // HashMap
261
+ use std::collections::HashMap;
262
+
263
+ let mut scores: HashMap<String, i32> = HashMap::new();
264
+ scores.insert("Alice".to_string(), 100);
265
+ scores.entry("Bob".to_string()).or_insert(0);
266
+
267
+ // Iterate with enumerate
268
+ for (index, value) in numbers.iter().enumerate() {
269
+ println!("{}: {}", index, value);
270
+ }
271
+
272
+ // Fold/reduce
273
+ let sum: i32 = numbers.iter().fold(0, |acc, x| acc + x);
274
+
275
+ // Find and position
276
+ let first_even = numbers.iter().find(|&n| n % 2 == 0);
277
+ let position = numbers.iter().position(|&n| n > 3);
278
+ \`\`\`
279
+
280
+ ## Testing
281
+ \`\`\`rust
282
+ #[cfg(test)]
283
+ mod tests {
284
+ use super::*;
285
+
286
+ #[test]
287
+ fn test_user_creation() {
288
+ let user = User::new(
289
+ "test@example.com".to_string(),
290
+ "Test User".to_string(),
291
+ "password123"
292
+ ).unwrap();
293
+
294
+ assert_eq!(user.email, "test@example.com");
295
+ assert!(user.is_active);
296
+ }
297
+
298
+ #[test]
299
+ fn test_password_verification() {
300
+ let user = User::new(
301
+ "test@example.com".to_string(),
302
+ "Test".to_string(),
303
+ "password123"
304
+ ).unwrap();
305
+
306
+ assert!(user.verify_password("password123"));
307
+ assert!(!user.verify_password("wrong"));
308
+ }
309
+
310
+ #[test]
311
+ #[should_panic(expected = "invalid email")]
312
+ fn test_invalid_email_panics() {
313
+ User::new("invalid".to_string(), "Test".to_string(), "pass").unwrap();
314
+ }
315
+
316
+ // Async tests with tokio
317
+ #[tokio::test]
318
+ async fn test_fetch_user() {
319
+ let repo = MockUserRepository::new();
320
+ let user = repo.find_by_id("123").await.unwrap();
321
+ assert!(user.is_some());
322
+ }
323
+ }
324
+ \`\`\`
325
+
326
+ ## ✅ DO
327
+ - Handle all \`Result\` and \`Option\` cases explicitly
328
+ - Use \`?\` operator for error propagation
329
+ - Use \`thiserror\` for library errors, \`anyhow\` for applications
330
+ - Prefer iterators over manual loops
331
+ - Use \`clippy\` and \`rustfmt\`
332
+ - Derive common traits: \`Debug\`, \`Clone\`, \`Serialize\`, \`Deserialize\`
333
+ - Use \`Arc<T>\` for shared ownership across threads
334
+
335
+ ## ❌ DON'T
336
+ - Don't use \`.unwrap()\` in production code (use \`?\` or handle errors)
337
+ - Don't ignore compiler warnings
338
+ - Don't fight the borrow checker - redesign if needed
339
+ - Don't use \`unsafe\` without good reason
340
+ - Don't clone everything to avoid borrowing (refactor instead)
341
+ - Don't use \`String\` when \`&str\` suffices