@kodrunhq/opencode-autopilot 1.10.0 → 1.12.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 (35) hide show
  1. package/assets/commands/oc-brainstorm.md +2 -0
  2. package/assets/commands/oc-review-agents.md +103 -0
  3. package/assets/commands/oc-review-pr.md +2 -0
  4. package/assets/commands/oc-tdd.md +2 -0
  5. package/assets/commands/oc-write-plan.md +2 -0
  6. package/assets/skills/coding-standards/SKILL.md +313 -0
  7. package/assets/skills/csharp-patterns/SKILL.md +327 -0
  8. package/assets/skills/frontend-design/SKILL.md +433 -0
  9. package/assets/skills/java-patterns/SKILL.md +258 -0
  10. package/assets/templates/cli-tool.md +49 -0
  11. package/assets/templates/fullstack.md +71 -0
  12. package/assets/templates/library.md +49 -0
  13. package/assets/templates/web-api.md +60 -0
  14. package/bin/cli.ts +1 -1
  15. package/bin/configure-tui.ts +1 -1
  16. package/package.json +1 -1
  17. package/src/agents/debugger.ts +329 -0
  18. package/src/agents/index.ts +16 -5
  19. package/src/agents/planner.ts +563 -0
  20. package/src/agents/reviewer.ts +270 -0
  21. package/src/config.ts +76 -18
  22. package/src/health/checks.ts +182 -1
  23. package/src/health/runner.ts +20 -2
  24. package/src/hooks/anti-slop.ts +132 -0
  25. package/src/hooks/slop-patterns.ts +71 -0
  26. package/src/index.ts +11 -0
  27. package/src/installer.ts +11 -3
  28. package/src/orchestrator/fallback/fallback-config.ts +21 -0
  29. package/src/orchestrator/fallback/mock-interceptor.ts +51 -0
  30. package/src/registry/model-groups.ts +4 -1
  31. package/src/review/stack-gate.ts +2 -0
  32. package/src/skills/adaptive-injector.ts +47 -2
  33. package/src/tools/configure.ts +1 -1
  34. package/src/tools/doctor.ts +6 -0
  35. package/src/utils/language-resolver.ts +34 -0
@@ -0,0 +1,433 @@
1
+ ---
2
+ name: frontend-design
3
+ description: State-of-the-art frontend UX/UI design patterns covering component architecture, responsive design, accessibility, and design system integration
4
+ stacks:
5
+ - react
6
+ - vue
7
+ - svelte
8
+ - angular
9
+ requires: []
10
+ ---
11
+
12
+ # Frontend Design Patterns
13
+
14
+ Practical frontend design patterns for building polished, accessible, and performant user interfaces. Covers component architecture, responsive design, accessibility, state management, animation, visual design principles, and design system integration. Apply these when building, reviewing, or refactoring frontend code.
15
+
16
+ ## 1. Component Architecture
17
+
18
+ **DO:** Structure components using atomic design principles and clear composition patterns.
19
+
20
+ - Organize components as atoms, molecules, and organisms:
21
+ ```
22
+ atoms/ Button, Input, Label, Icon, Badge
23
+ molecules/ SearchBar (Input + Button), FormField (Label + Input + Error)
24
+ organisms/ Header (Logo + Nav + SearchBar), OrderForm (FormFields + Submit)
25
+ ```
26
+ - Use compound components for related elements that share state:
27
+ ```jsx
28
+ // DO: Compound component -- parent manages shared state
29
+ <Select value={selected} onChange={setSelected}>
30
+ <Select.Trigger>{selected}</Select.Trigger>
31
+ <Select.Options>
32
+ <Select.Option value="a">Option A</Select.Option>
33
+ <Select.Option value="b">Option B</Select.Option>
34
+ </Select.Options>
35
+ </Select>
36
+ ```
37
+ - Separate container (data fetching, state) from presentational (rendering) components:
38
+ ```jsx
39
+ // Container: handles data
40
+ function OrderListContainer() {
41
+ const { data, isLoading } = useOrders();
42
+ return <OrderList orders={data} loading={isLoading} />;
43
+ }
44
+
45
+ // Presentational: pure rendering
46
+ function OrderList({ orders, loading }) {
47
+ if (loading) return <Skeleton count={3} />;
48
+ return orders.map(o => <OrderCard key={o.id} order={o} />);
49
+ }
50
+ ```
51
+ - Use composition (children, slots) instead of prop drilling:
52
+ ```jsx
53
+ // DO: Composition via children
54
+ <Card>
55
+ <Card.Header>Title</Card.Header>
56
+ <Card.Body>{content}</Card.Body>
57
+ <Card.Footer><Button>Save</Button></Card.Footer>
58
+ </Card>
59
+
60
+ // DON'T: Prop drilling through many levels
61
+ <Card title="Title" content={content} buttonText="Save" onButtonClick={...} />
62
+ ```
63
+
64
+ **DON'T:**
65
+
66
+ - Pass data through more than 2 intermediate components (prop drilling) -- use context, composition, or state management
67
+ - Create components with more than 10 props -- split into smaller components or use composition
68
+ - Mix data fetching with rendering in the same component
69
+ - Use `index` as `key` for lists that can be reordered, filtered, or mutated
70
+
71
+ ## 2. Responsive Design
72
+
73
+ **DO:** Design mobile-first and use modern CSS features for fluid layouts.
74
+
75
+ - Use `min-width` breakpoints (mobile-first):
76
+ ```css
77
+ /* Base: mobile */
78
+ .grid { display: flex; flex-direction: column; }
79
+
80
+ /* Tablet and up */
81
+ @media (min-width: 768px) {
82
+ .grid { flex-direction: row; flex-wrap: wrap; }
83
+ }
84
+
85
+ /* Desktop and up */
86
+ @media (min-width: 1024px) {
87
+ .grid { max-width: 1200px; margin: 0 auto; }
88
+ }
89
+ ```
90
+ - Use `clamp()` for fluid typography:
91
+ ```css
92
+ /* Fluid font size: 1rem at 320px, 1.5rem at 1200px */
93
+ h1 { font-size: clamp(1rem, 0.5rem + 2.5vw, 1.5rem); }
94
+ ```
95
+ - Use container queries for component-level responsiveness:
96
+ ```css
97
+ .card-container { container-type: inline-size; }
98
+
99
+ @container (min-width: 400px) {
100
+ .card { display: flex; flex-direction: row; }
101
+ }
102
+ ```
103
+ - Use `aspect-ratio` for media containers:
104
+ ```css
105
+ .video-wrapper { aspect-ratio: 16 / 9; width: 100%; }
106
+ .avatar { aspect-ratio: 1; border-radius: 50%; }
107
+ ```
108
+ - Use logical properties for internationalization:
109
+ ```css
110
+ /* DO: Works for LTR and RTL */
111
+ .sidebar { margin-inline-start: 1rem; padding-block: 0.5rem; }
112
+
113
+ /* DON'T: Only works for LTR */
114
+ .sidebar { margin-left: 1rem; padding-top: 0.5rem; padding-bottom: 0.5rem; }
115
+ ```
116
+ - Use responsive images:
117
+ ```html
118
+ <picture>
119
+ <source srcset="hero-wide.webp" media="(min-width: 1024px)" />
120
+ <source srcset="hero-medium.webp" media="(min-width: 640px)" />
121
+ <img src="hero-small.webp" alt="Hero image" loading="lazy" />
122
+ </picture>
123
+ ```
124
+
125
+ **DON'T:**
126
+
127
+ - Use `max-width` breakpoints (desktop-first) -- mobile-first produces smaller CSS and better progressive enhancement
128
+ - Use fixed pixel widths for layouts -- use relative units (`rem`, `%`, `fr`, `vw`)
129
+ - Hide content with `display: none` on mobile instead of designing a mobile-appropriate layout
130
+ - Use `@media` for component-level responsiveness when container queries are available
131
+
132
+ ## 3. Accessibility (a11y)
133
+
134
+ **DO:** Build accessible interfaces from the start, not as an afterthought.
135
+
136
+ - Use semantic HTML elements:
137
+ ```html
138
+ <!-- DO: Semantic -->
139
+ <nav aria-label="Main navigation">
140
+ <ul>
141
+ <li><a href="/home">Home</a></li>
142
+ <li><a href="/about">About</a></li>
143
+ </ul>
144
+ </nav>
145
+
146
+ <!-- DON'T: Div soup -->
147
+ <div class="nav">
148
+ <div class="nav-item" onclick="goto('/home')">Home</div>
149
+ <div class="nav-item" onclick="goto('/about')">About</div>
150
+ </div>
151
+ ```
152
+ - Use ARIA only when native HTML semantics are insufficient:
153
+ ```html
154
+ <!-- DO: ARIA for custom widgets -->
155
+ <div role="tablist">
156
+ <button role="tab" aria-selected="true" aria-controls="panel-1">Tab 1</button>
157
+ <div role="tabpanel" id="panel-1">Content 1</div>
158
+ </div>
159
+
160
+ <!-- DON'T: ARIA on native elements that already have semantics -->
161
+ <button role="button">Submit</button> <!-- Redundant -->
162
+ ```
163
+ - Manage focus for keyboard navigation:
164
+ ```jsx
165
+ // Skip link for keyboard users
166
+ <a href="#main-content" className="skip-link">Skip to main content</a>
167
+
168
+ // Focus management in modals
169
+ function Modal({ isOpen, onClose }) {
170
+ const closeRef = useRef(null);
171
+ useEffect(() => {
172
+ if (isOpen) closeRef.current?.focus();
173
+ }, [isOpen]);
174
+ // Trap focus inside modal while open
175
+ }
176
+ ```
177
+ - Meet WCAG AA color contrast minimums:
178
+ ```css
179
+ /* AA minimums: 4.5:1 for normal text, 3:1 for large text */
180
+ .text { color: #333; background: #fff; } /* 12.6:1 -- PASS */
181
+ .text { color: #999; background: #fff; } /* 2.8:1 -- FAIL */
182
+ ```
183
+ - Use `focus-visible` for keyboard-only focus indicators:
184
+ ```css
185
+ button:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
186
+ button:focus:not(:focus-visible) { outline: none; }
187
+ ```
188
+ - Use live regions for dynamic content updates:
189
+ ```html
190
+ <div aria-live="polite" aria-atomic="true">
191
+ {statusMessage} <!-- Screen readers announce changes -->
192
+ </div>
193
+ ```
194
+
195
+ **DON'T:**
196
+
197
+ - Use `div` or `span` for interactive elements -- use `button`, `a`, `input`, `select`
198
+ - Remove focus outlines without providing an alternative visual indicator
199
+ - Use color alone to convey information (add icons, text, or patterns)
200
+ - Use `tabindex` values greater than 0 -- it disrupts natural tab order
201
+ - Auto-play video or audio without user consent
202
+
203
+ ## 4. State Management
204
+
205
+ **DO:** Start with the simplest state solution and scale up only when needed.
206
+
207
+ - Use local state first -- most state belongs to a single component:
208
+ ```jsx
209
+ function Counter() {
210
+ const [count, setCount] = useState(0);
211
+ return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
212
+ }
213
+ ```
214
+ - Separate server state from client state:
215
+ ```jsx
216
+ // Server state: fetched, cached, synced with backend (use React Query/SWR)
217
+ const { data: orders } = useQuery({ queryKey: ['orders'], queryFn: fetchOrders });
218
+
219
+ // Client state: UI-only (use useState/useReducer)
220
+ const [isFilterOpen, setFilterOpen] = useState(false);
221
+ ```
222
+ - Use URL as state for shareable, bookmarkable views:
223
+ ```jsx
224
+ // Search params as state
225
+ const [searchParams, setSearchParams] = useSearchParams();
226
+ const page = Number(searchParams.get("page") ?? "1");
227
+ const filter = searchParams.get("status") ?? "all";
228
+ ```
229
+ - Use optimistic updates for perceived performance:
230
+ ```jsx
231
+ const mutation = useMutation({
232
+ mutationFn: updateOrder,
233
+ onMutate: async (newOrder) => {
234
+ await queryClient.cancelQueries({ queryKey: ['orders'] });
235
+ const previous = queryClient.getQueryData(['orders']);
236
+ queryClient.setQueryData(['orders'], old => optimisticUpdate(old, newOrder));
237
+ return { previous };
238
+ },
239
+ onError: (err, newOrder, context) => {
240
+ queryClient.setQueryData(['orders'], context.previous); // Rollback
241
+ },
242
+ });
243
+ ```
244
+
245
+ **DON'T:**
246
+
247
+ - Put everything in global state -- only share state that multiple components need simultaneously
248
+ - Use global state for server data -- use a data fetching library with caching (React Query, SWR, RTK Query)
249
+ - Store derived values in state -- compute them during render:
250
+ ```jsx
251
+ // DON'T: Derived state
252
+ const [total, setTotal] = useState(0);
253
+ useEffect(() => setTotal(items.reduce(...)), [items]);
254
+
255
+ // DO: Computed value
256
+ const total = items.reduce((sum, item) => sum + item.price, 0);
257
+ ```
258
+
259
+ ## 5. Animation and Interaction
260
+
261
+ **DO:** Use animations purposefully to provide feedback and guide attention.
262
+
263
+ - Use CSS transitions for simple state changes:
264
+ ```css
265
+ .button {
266
+ transition: background-color 150ms ease, transform 100ms ease;
267
+ }
268
+ .button:hover { background-color: var(--color-hover); }
269
+ .button:active { transform: scale(0.97); }
270
+ ```
271
+ - Respect reduced motion preferences:
272
+ ```css
273
+ @media (prefers-reduced-motion: reduce) {
274
+ *, *::before, *::after {
275
+ animation-duration: 0.01ms !important;
276
+ transition-duration: 0.01ms !important;
277
+ }
278
+ }
279
+ ```
280
+ - Use `will-change` sparingly for GPU acceleration hints:
281
+ ```css
282
+ /* Only on elements that WILL animate, not everything */
283
+ .sliding-panel { will-change: transform; }
284
+ .sliding-panel.idle { will-change: auto; } /* Remove when done */
285
+ ```
286
+ - Use Intersection Observer for scroll-triggered animations:
287
+ ```jsx
288
+ function FadeIn({ children }) {
289
+ const ref = useRef(null);
290
+ const isVisible = useIntersectionObserver(ref, { threshold: 0.1 });
291
+ return (
292
+ <div ref={ref} className={isVisible ? "fade-in visible" : "fade-in"}>
293
+ {children}
294
+ </div>
295
+ );
296
+ }
297
+ ```
298
+ - Prefer skeleton screens over spinners:
299
+ ```jsx
300
+ // DO: Skeleton preserves layout, reduces perceived wait time
301
+ function OrderSkeleton() {
302
+ return <div className="skeleton-card"><div className="skeleton-line" />...</div>;
303
+ }
304
+
305
+ // DON'T: Spinner gives no information about what's loading
306
+ function Loading() { return <Spinner />; }
307
+ ```
308
+
309
+ **DON'T:**
310
+
311
+ - Animate `width`, `height`, `top`, `left` -- animate `transform` and `opacity` (GPU-composited, no layout recalculation)
312
+ - Use animations that last longer than 300ms for UI transitions (feels sluggish)
313
+ - Add `will-change` to everything -- it consumes GPU memory. Apply only to animating elements
314
+ - Ignore `prefers-reduced-motion` -- some users experience motion sickness
315
+
316
+ ## 6. Visual Design Principles
317
+
318
+ **DO:** Apply systematic design decisions for consistent, professional interfaces.
319
+
320
+ - Use a typographic scale (e.g., major third 1.25):
321
+ ```css
322
+ :root {
323
+ --font-xs: 0.64rem; /* 10.24px */
324
+ --font-sm: 0.8rem; /* 12.8px */
325
+ --font-base: 1rem; /* 16px */
326
+ --font-lg: 1.25rem; /* 20px */
327
+ --font-xl: 1.563rem; /* 25px */
328
+ --font-2xl: 1.953rem; /* 31.25px */
329
+ }
330
+ ```
331
+ - Use a 4px/8px spacing grid:
332
+ ```css
333
+ :root {
334
+ --space-1: 0.25rem; /* 4px */
335
+ --space-2: 0.5rem; /* 8px */
336
+ --space-3: 0.75rem; /* 12px */
337
+ --space-4: 1rem; /* 16px */
338
+ --space-6: 1.5rem; /* 24px */
339
+ --space-8: 2rem; /* 32px */
340
+ }
341
+ ```
342
+ - Use HSL-based color systems with semantic tokens:
343
+ ```css
344
+ :root {
345
+ /* Primitives */
346
+ --blue-500: hsl(220 90% 56%);
347
+ --red-500: hsl(0 84% 60%);
348
+
349
+ /* Semantic tokens */
350
+ --color-primary: var(--blue-500);
351
+ --color-danger: var(--red-500);
352
+ --color-text: hsl(220 20% 15%);
353
+ --color-text-muted: hsl(220 15% 50%);
354
+ --color-surface: hsl(0 0% 100%);
355
+ --color-border: hsl(220 15% 88%);
356
+ }
357
+ ```
358
+ - Use a consistent elevation/shadow system:
359
+ ```css
360
+ :root {
361
+ --shadow-sm: 0 1px 2px hsl(0 0% 0% / 0.05);
362
+ --shadow-md: 0 4px 6px hsl(0 0% 0% / 0.07);
363
+ --shadow-lg: 0 10px 15px hsl(0 0% 0% / 0.1);
364
+ --shadow-xl: 0 20px 25px hsl(0 0% 0% / 0.15);
365
+ }
366
+ ```
367
+ - Establish visual hierarchy through size, weight, and color -- not decoration:
368
+ ```css
369
+ .heading { font-size: var(--font-xl); font-weight: 700; color: var(--color-text); }
370
+ .subheading { font-size: var(--font-lg); font-weight: 500; color: var(--color-text); }
371
+ .body { font-size: var(--font-base); font-weight: 400; color: var(--color-text); }
372
+ .caption { font-size: var(--font-sm); font-weight: 400; color: var(--color-text-muted); }
373
+ ```
374
+
375
+ **DON'T:**
376
+
377
+ - Use arbitrary pixel values for spacing -- stick to the grid
378
+ - Use more than 3 font sizes on a single screen (headings + body + caption)
379
+ - Mix color definition methods (hex, rgb, hsl) -- pick one system
380
+ - Use shadows for decoration -- shadows indicate elevation (interactive, floating, overlay)
381
+
382
+ ## 7. Design System Integration
383
+
384
+ **DO:** Build a token-based system that scales across themes and components.
385
+
386
+ - Use CSS custom properties for theming:
387
+ ```css
388
+ :root {
389
+ --color-bg: hsl(0 0% 100%);
390
+ --color-text: hsl(220 20% 15%);
391
+ --radius-md: 0.375rem;
392
+ --font-body: system-ui, -apple-system, sans-serif;
393
+ }
394
+ ```
395
+ - Support dark mode via custom properties and media query:
396
+ ```css
397
+ @media (prefers-color-scheme: dark) {
398
+ :root {
399
+ --color-bg: hsl(220 20% 10%);
400
+ --color-text: hsl(220 15% 85%);
401
+ --color-surface: hsl(220 20% 14%);
402
+ --color-border: hsl(220 15% 25%);
403
+ }
404
+ }
405
+
406
+ /* Manual toggle via data attribute */
407
+ [data-theme="dark"] {
408
+ --color-bg: hsl(220 20% 10%);
409
+ --color-text: hsl(220 15% 85%);
410
+ }
411
+ ```
412
+ - Use component variants via data attributes or props:
413
+ ```css
414
+ /* Data attribute variants */
415
+ .button { padding: var(--space-2) var(--space-4); border-radius: var(--radius-md); }
416
+ .button[data-variant="primary"] { background: var(--color-primary); color: white; }
417
+ .button[data-variant="secondary"] { background: transparent; border: 1px solid var(--color-border); }
418
+ .button[data-size="sm"] { padding: var(--space-1) var(--space-2); font-size: var(--font-sm); }
419
+ ```
420
+ - Use consistent naming across tokens and components:
421
+ ```
422
+ Tokens: --color-primary, --space-4, --radius-md, --shadow-lg
423
+ Components: Button, Card, Input (PascalCase)
424
+ Variants: data-variant="primary", data-size="sm" (kebab-case values)
425
+ ```
426
+ - Document component APIs -- props, variants, and usage examples should be clear from the component definition
427
+
428
+ **DON'T:**
429
+
430
+ - Hardcode colors or spacing values in components -- always reference tokens
431
+ - Create one-off styles that don't fit the system -- either extend the system or use an existing token
432
+ - Switch themes by overriding individual properties in JS -- toggle a class or data attribute on `<html>`
433
+ - Mix multiple theming approaches (CSS-in-JS, CSS Modules, global CSS) in the same project without clear boundaries
@@ -0,0 +1,258 @@
1
+ ---
2
+ name: java-patterns
3
+ description: Idiomatic Java patterns including records, Spring Boot conventions, JPA/Hibernate, and common pitfalls
4
+ stacks:
5
+ - java
6
+ requires:
7
+ - coding-standards
8
+ ---
9
+
10
+ # Java Patterns
11
+
12
+ Idiomatic Java patterns for modern (17+) projects. Covers language features, Spring Boot conventions, JPA/Hibernate best practices, testing idioms, and common pitfalls. Apply these when writing, reviewing, or refactoring Java code.
13
+
14
+ ## 1. Modern Java Idioms
15
+
16
+ **DO:** Use modern Java features to write concise, safe, and expressive code.
17
+
18
+ - Use records for immutable data carriers:
19
+ ```java
20
+ // Record: immutable, equals/hashCode/toString auto-generated
21
+ public record UserDto(String name, String email, Instant createdAt) {}
22
+
23
+ // Use in APIs, DTOs, value objects -- not JPA entities
24
+ var user = new UserDto("Alice", "alice@example.com", Instant.now());
25
+ ```
26
+ - Use sealed classes for restricted type hierarchies:
27
+ ```java
28
+ public sealed interface Shape permits Circle, Rectangle, Triangle {
29
+ double area();
30
+ }
31
+
32
+ public record Circle(double radius) implements Shape {
33
+ public double area() { return Math.PI * radius * radius; }
34
+ }
35
+ ```
36
+ - Use Optional for nullable returns -- never for fields or parameters:
37
+ ```java
38
+ // DO: Chain operations safely
39
+ Optional<User> user = repository.findById(id);
40
+ String name = user.map(User::name).orElse("Anonymous");
41
+
42
+ // DO: Handle absence explicitly
43
+ return repository.findById(id)
44
+ .orElseThrow(() -> new UserNotFoundException(id));
45
+ ```
46
+ - Use pattern matching with `instanceof`:
47
+ ```java
48
+ // DO: Pattern matching eliminates manual cast
49
+ if (shape instanceof Circle c) {
50
+ return Math.PI * c.radius() * c.radius();
51
+ }
52
+ ```
53
+ - Use text blocks for multi-line strings:
54
+ ```java
55
+ String query = """
56
+ SELECT u.name, u.email
57
+ FROM users u
58
+ WHERE u.active = true
59
+ ORDER BY u.name
60
+ """;
61
+ ```
62
+
63
+ **DON'T:**
64
+
65
+ - Use `Optional.get()` without checking `isPresent()` -- use `orElse()`, `orElseThrow()`, or `map()`
66
+ - Use Optional as a method parameter or field type -- it's for return values only
67
+ - Return `null` from public methods when Optional is appropriate
68
+ - Use raw types: `List` instead of `List<String>`
69
+ - Use `instanceof` followed by a manual cast when pattern matching is available
70
+
71
+ ## 2. Spring Boot Patterns
72
+
73
+ **DO:** Follow Spring Boot conventions for maintainable, testable applications.
74
+
75
+ - Use constructor-based dependency injection -- never field injection:
76
+ ```java
77
+ // DO: Constructor injection (immutable, testable)
78
+ @Service
79
+ public class OrderService {
80
+ private final OrderRepository orderRepo;
81
+ private final PaymentGateway paymentGateway;
82
+
83
+ public OrderService(OrderRepository orderRepo, PaymentGateway paymentGateway) {
84
+ this.orderRepo = orderRepo;
85
+ this.paymentGateway = paymentGateway;
86
+ }
87
+ }
88
+ ```
89
+ - Layer architecture: Controller -> Service -> Repository:
90
+ ```java
91
+ @RestController // Thin: HTTP concerns only
92
+ @Service // Business logic and orchestration
93
+ @Repository // Data access only
94
+ ```
95
+ - Place `@Transactional` on the service layer, not on repositories:
96
+ ```java
97
+ @Service
98
+ public class TransferService {
99
+ @Transactional
100
+ public void transfer(AccountId from, AccountId to, Money amount) {
101
+ accountRepo.debit(from, amount);
102
+ accountRepo.credit(to, amount);
103
+ }
104
+ }
105
+ ```
106
+ - Use `@ConfigurationProperties` for type-safe configuration:
107
+ ```java
108
+ @ConfigurationProperties(prefix = "app.email")
109
+ public record EmailConfig(String host, int port, boolean useTls) {}
110
+ ```
111
+ - Handle exceptions with `@ControllerAdvice`:
112
+ ```java
113
+ @ControllerAdvice
114
+ public class GlobalExceptionHandler {
115
+ @ExceptionHandler(UserNotFoundException.class)
116
+ public ResponseEntity<ErrorResponse> handleNotFound(UserNotFoundException ex) {
117
+ return ResponseEntity.status(404)
118
+ .body(new ErrorResponse(ex.getMessage()));
119
+ }
120
+ }
121
+ ```
122
+
123
+ **DON'T:**
124
+
125
+ - Use `@Autowired` on fields -- constructor injection is immutable and explicit
126
+ - Put business logic in controllers -- controllers parse HTTP, services execute logic
127
+ - Use `@Transactional` on repository methods -- Spring Data already wraps queries
128
+ - Catch exceptions in controllers individually -- use `@ControllerAdvice` for centralized handling
129
+ - Use Spring profiles for feature flags -- profiles are for environments (dev, staging, prod)
130
+
131
+ ## 3. JPA/Hibernate Conventions
132
+
133
+ **DO:** Design entities carefully and be explicit about fetching behavior.
134
+
135
+ - Mark IDs as immutable and use `@Version` for optimistic locking:
136
+ ```java
137
+ @Entity
138
+ public class Order {
139
+ @Id @GeneratedValue(strategy = GenerationType.UUID)
140
+ private UUID id;
141
+
142
+ @Version
143
+ private Long version; // Optimistic locking -- prevents lost updates
144
+ }
145
+ ```
146
+ - Default to lazy fetching, use explicit join fetch for read paths:
147
+ ```java
148
+ // DO: Lazy by default
149
+ @ManyToOne(fetch = FetchType.LAZY)
150
+ private Customer customer;
151
+
152
+ // DO: Explicit fetch when needed
153
+ @EntityGraph(attributePaths = {"customer", "items"})
154
+ Optional<Order> findWithDetailsById(UUID id);
155
+ ```
156
+ - Prevent N+1 queries with `@EntityGraph` or `JOIN FETCH`:
157
+ ```java
158
+ // Repository method with join fetch
159
+ @Query("SELECT o FROM Order o JOIN FETCH o.items WHERE o.status = :status")
160
+ List<Order> findByStatusWithItems(@Param("status") OrderStatus status);
161
+ ```
162
+ - Use DTOs for API responses, never expose entities directly:
163
+ ```java
164
+ // DO: Project to DTO
165
+ public record OrderSummary(UUID id, String customerName, BigDecimal total) {
166
+ public static OrderSummary from(Order order) {
167
+ return new OrderSummary(order.getId(), order.getCustomer().getName(), order.getTotal());
168
+ }
169
+ }
170
+ ```
171
+
172
+ **DON'T:**
173
+
174
+ - Use `FetchType.EAGER` on `@ManyToOne` or `@OneToMany` -- it causes unexpected extra queries
175
+ - Return JPA entities from REST endpoints -- entities carry lazy proxies and hibernate state
176
+ - Use `CascadeType.ALL` without thinking -- cascade delete can wipe related data unexpectedly
177
+ - Call `entity.getCollection().size()` to check emptiness -- use a count query instead
178
+ - Mutate entity state outside a `@Transactional` context -- changes won't persist or may throw
179
+
180
+ ## 4. Testing
181
+
182
+ **DO:** Write focused tests that verify behavior, using the right test slice.
183
+
184
+ - Use JUnit 5 `@Nested` for grouping related test scenarios:
185
+ ```java
186
+ class OrderServiceTest {
187
+ @Nested
188
+ class WhenOrderIsValid {
189
+ @Test
190
+ void shouldCalculateTotal() { ... }
191
+
192
+ @Test
193
+ void shouldApplyDiscount() { ... }
194
+ }
195
+
196
+ @Nested
197
+ class WhenOrderIsEmpty {
198
+ @Test
199
+ void shouldThrowValidationException() { ... }
200
+ }
201
+ }
202
+ ```
203
+ - Use Mockito for isolating dependencies:
204
+ ```java
205
+ @ExtendWith(MockitoExtension.class)
206
+ class OrderServiceTest {
207
+ @Mock OrderRepository orderRepo;
208
+ @Mock PaymentGateway paymentGateway;
209
+ @InjectMocks OrderService service;
210
+
211
+ @Test
212
+ void shouldProcessPayment() {
213
+ when(paymentGateway.charge(any())).thenReturn(PaymentResult.success());
214
+ service.placeOrder(order);
215
+ verify(paymentGateway).charge(any());
216
+ }
217
+ }
218
+ ```
219
+ - Use test slices instead of `@SpringBootTest` for faster tests:
220
+ ```java
221
+ @WebMvcTest(OrderController.class) // Controller tests only
222
+ @DataJpaTest // Repository tests only
223
+ @JsonTest // JSON serialization tests only
224
+ ```
225
+ - Use AssertJ for fluent, readable assertions:
226
+ ```java
227
+ assertThat(orders)
228
+ .hasSize(3)
229
+ .extracting(Order::status)
230
+ .containsExactly(PENDING, SHIPPED, DELIVERED);
231
+ ```
232
+
233
+ **DON'T:**
234
+
235
+ - Use `@SpringBootTest` for every test -- it loads the full application context (slow)
236
+ - Mock everything -- test real behavior where possible, mock only external boundaries
237
+ - Write tests that depend on database state from other tests -- each test should set up its own state
238
+ - Use `assertEquals(expected, actual)` when AssertJ provides a more readable alternative
239
+
240
+ ## 5. Common Pitfalls
241
+
242
+ **Pitfall: Mutable Date/Time**
243
+ Use `java.time.*` exclusively. Never use `java.util.Date` or `java.util.Calendar` -- they are mutable and error-prone. Use `Instant` for timestamps, `LocalDate` for dates without time, `ZonedDateTime` for timezone-aware dates.
244
+
245
+ **Pitfall: Checked Exceptions Overuse**
246
+ Reserve checked exceptions for truly recoverable conditions that the caller MUST handle (e.g., `IOException` when writing to disk). Use unchecked exceptions (`RuntimeException` subclasses) for programming errors and business rule violations.
247
+
248
+ **Pitfall: Null Returns**
249
+ Return `Optional<T>` from methods that may not produce a value. For collections, return empty collections instead of `null`. Use `@Nullable` annotations from `jakarta.annotation` when Optional is not appropriate (e.g., record fields).
250
+
251
+ **Pitfall: `==` vs `.equals()` for Objects**
252
+ `==` compares references, `.equals()` compares values. Always use `.equals()` for `String`, `Integer`, `BigDecimal`, and all objects. Exception: enum values can use `==` because enums are singletons.
253
+
254
+ **Pitfall: Raw Types**
255
+ Always specify generic type parameters. `List` instead of `List<String>` bypasses compile-time type safety and can cause `ClassCastException` at runtime.
256
+
257
+ **Pitfall: Synchronized Blocks in Spring Beans**
258
+ Spring beans are singletons by default. Using `synchronized` on a bean method serializes all requests through that method. Use `@Async`, message queues, or database-level locking instead of in-process synchronization for concurrent request handling.