red64-cli 0.5.0 → 0.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 (62) hide show
  1. package/README.md +64 -58
  2. package/dist/components/screens/StartScreen.d.ts.map +1 -1
  3. package/dist/components/screens/StartScreen.js +2 -2
  4. package/dist/components/screens/StartScreen.js.map +1 -1
  5. package/dist/services/AgentInvoker.js +4 -4
  6. package/dist/services/AgentInvoker.js.map +1 -1
  7. package/dist/services/ClaudeHealthCheck.d.ts +5 -0
  8. package/dist/services/ClaudeHealthCheck.d.ts.map +1 -1
  9. package/dist/services/ClaudeHealthCheck.js +43 -5
  10. package/dist/services/ClaudeHealthCheck.js.map +1 -1
  11. package/dist/services/index.d.ts +1 -1
  12. package/dist/services/index.d.ts.map +1 -1
  13. package/dist/services/index.js +1 -1
  14. package/dist/services/index.js.map +1 -1
  15. package/framework/stacks/c/code-quality.md +326 -0
  16. package/framework/stacks/c/coding-style.md +347 -0
  17. package/framework/stacks/c/conventions.md +513 -0
  18. package/framework/stacks/c/error-handling.md +350 -0
  19. package/framework/stacks/c/feedback.md +158 -0
  20. package/framework/stacks/c/memory-safety.md +408 -0
  21. package/framework/stacks/c/tech.md +122 -0
  22. package/framework/stacks/c/testing.md +472 -0
  23. package/framework/stacks/cpp/code-quality.md +282 -0
  24. package/framework/stacks/cpp/coding-style.md +363 -0
  25. package/framework/stacks/cpp/conventions.md +420 -0
  26. package/framework/stacks/cpp/error-handling.md +264 -0
  27. package/framework/stacks/cpp/feedback.md +104 -0
  28. package/framework/stacks/cpp/memory-safety.md +351 -0
  29. package/framework/stacks/cpp/tech.md +160 -0
  30. package/framework/stacks/cpp/testing.md +323 -0
  31. package/framework/stacks/java/code-quality.md +357 -0
  32. package/framework/stacks/java/coding-style.md +400 -0
  33. package/framework/stacks/java/conventions.md +437 -0
  34. package/framework/stacks/java/error-handling.md +408 -0
  35. package/framework/stacks/java/feedback.md +180 -0
  36. package/framework/stacks/java/tech.md +126 -0
  37. package/framework/stacks/java/testing.md +485 -0
  38. package/framework/stacks/javascript/async-patterns.md +216 -0
  39. package/framework/stacks/javascript/code-quality.md +182 -0
  40. package/framework/stacks/javascript/coding-style.md +293 -0
  41. package/framework/stacks/javascript/conventions.md +268 -0
  42. package/framework/stacks/javascript/error-handling.md +216 -0
  43. package/framework/stacks/javascript/feedback.md +80 -0
  44. package/framework/stacks/javascript/tech.md +114 -0
  45. package/framework/stacks/javascript/testing.md +209 -0
  46. package/framework/stacks/loco/code-quality.md +156 -0
  47. package/framework/stacks/loco/coding-style.md +247 -0
  48. package/framework/stacks/loco/error-handling.md +225 -0
  49. package/framework/stacks/loco/feedback.md +35 -0
  50. package/framework/stacks/loco/loco.md +342 -0
  51. package/framework/stacks/loco/structure.md +193 -0
  52. package/framework/stacks/loco/tech.md +129 -0
  53. package/framework/stacks/loco/testing.md +211 -0
  54. package/framework/stacks/rust/code-quality.md +370 -0
  55. package/framework/stacks/rust/coding-style.md +475 -0
  56. package/framework/stacks/rust/conventions.md +430 -0
  57. package/framework/stacks/rust/error-handling.md +399 -0
  58. package/framework/stacks/rust/feedback.md +152 -0
  59. package/framework/stacks/rust/memory-safety.md +398 -0
  60. package/framework/stacks/rust/tech.md +121 -0
  61. package/framework/stacks/rust/testing.md +528 -0
  62. package/package.json +14 -2
@@ -0,0 +1,323 @@
1
+ # Testing Patterns
2
+
3
+ Comprehensive testing patterns for modern C++ projects with Google Test, Google Mock, and Google Benchmark.
4
+
5
+ ---
6
+
7
+ ## Philosophy
8
+
9
+ - **Fast feedback**: Unit tests run in milliseconds, no I/O
10
+ - **Arrange-Act-Assert**: Every test follows the same three-step structure
11
+ - **Test behavior, not implementation**: Tests should survive refactoring
12
+ - **Sanitizers always on**: Run tests under ASan + UBSan in CI
13
+
14
+ ---
15
+
16
+ ## Test Organization
17
+
18
+ ```
19
+ tests/
20
+ CMakeLists.txt
21
+ unit/
22
+ test_user_service.cpp
23
+ test_payment_processor.cpp
24
+ test_json_parser.cpp
25
+ integration/
26
+ test_database.cpp
27
+ test_http_client.cpp
28
+ fuzz/
29
+ fuzz_json_parser.cpp
30
+ benchmark/
31
+ bench_serialization.cpp
32
+ fixtures/
33
+ test_data.json
34
+ ```
35
+
36
+ **Pattern**: Mirror `src/` structure. Prefix all test files with `test_`. Register all tests in CTest.
37
+
38
+ ---
39
+
40
+ ## Google Test Basics
41
+
42
+ ### TEST -- Simple Tests
43
+
44
+ ```cpp
45
+ #include <gtest/gtest.h>
46
+ #include "math_utils.hpp"
47
+
48
+ TEST(MathUtils, AddPositiveNumbers) {
49
+ EXPECT_EQ(add(2, 3), 5);
50
+ }
51
+
52
+ TEST(MathUtils, AddNegativeNumbers) {
53
+ EXPECT_EQ(add(-1, -2), -3);
54
+ }
55
+
56
+ TEST(MathUtils, AddOverflowReturnsError) {
57
+ auto result = safe_add(INT_MAX, 1);
58
+ ASSERT_FALSE(result.has_value());
59
+ EXPECT_EQ(result.error().code, ErrorCode::kOverflow);
60
+ }
61
+ ```
62
+
63
+ ### TEST_F -- Test Fixtures
64
+
65
+ ```cpp
66
+ class UserServiceTest : public ::testing::Test {
67
+ protected:
68
+ void SetUp() override {
69
+ repo_ = std::make_shared<MockUserRepo>();
70
+ service_ = std::make_unique<UserService>(repo_);
71
+ }
72
+
73
+ std::shared_ptr<MockUserRepo> repo_;
74
+ std::unique_ptr<UserService> service_;
75
+ };
76
+
77
+ TEST_F(UserServiceTest, CreateUserSuccess) {
78
+ // Arrange
79
+ EXPECT_CALL(*repo_, find_by_email("alice@example.com"))
80
+ .WillOnce(::testing::Return(std::nullopt));
81
+ EXPECT_CALL(*repo_, save(::testing::_))
82
+ .WillOnce(::testing::Return(User{.id = 1, .name = "Alice"}));
83
+
84
+ // Act
85
+ auto result = service_->create_user({"Alice", "alice@example.com"});
86
+
87
+ // Assert
88
+ ASSERT_TRUE(result.has_value());
89
+ EXPECT_EQ(result->name, "Alice");
90
+ }
91
+
92
+ TEST_F(UserServiceTest, CreateUserDuplicateEmailReturnsError) {
93
+ EXPECT_CALL(*repo_, find_by_email("taken@example.com"))
94
+ .WillOnce(::testing::Return(User{.id = 1, .email = "taken@example.com"}));
95
+
96
+ auto result = service_->create_user({"Bob", "taken@example.com"});
97
+
98
+ ASSERT_FALSE(result.has_value());
99
+ EXPECT_EQ(result.error().code, ErrorCode::kAlreadyExists);
100
+ }
101
+ ```
102
+
103
+ ### TEST_P -- Parameterized Tests
104
+
105
+ ```cpp
106
+ struct ValidationCase {
107
+ std::string input;
108
+ bool expected_valid;
109
+ std::string description;
110
+ };
111
+
112
+ class EmailValidationTest : public ::testing::TestWithParam<ValidationCase> {};
113
+
114
+ TEST_P(EmailValidationTest, ValidatesCorrectly) {
115
+ const auto& [input, expected_valid, description] = GetParam();
116
+ EXPECT_EQ(is_valid_email(input), expected_valid) << description;
117
+ }
118
+
119
+ INSTANTIATE_TEST_SUITE_P(
120
+ EmailCases,
121
+ EmailValidationTest,
122
+ ::testing::Values(
123
+ ValidationCase{"user@example.com", true, "standard email"},
124
+ ValidationCase{"user@sub.example.com", true, "subdomain"},
125
+ ValidationCase{"invalid", false, "no at sign"},
126
+ ValidationCase{"", false, "empty string"},
127
+ ValidationCase{"@example.com", false, "no local part"}
128
+ )
129
+ );
130
+ ```
131
+
132
+ ---
133
+
134
+ ## Google Mock
135
+
136
+ ### Defining Mocks
137
+
138
+ ```cpp
139
+ #include <gmock/gmock.h>
140
+
141
+ class UserRepo {
142
+ public:
143
+ virtual ~UserRepo() = default;
144
+ virtual std::optional<User> find_by_email(std::string_view email) = 0;
145
+ virtual Result<User> save(const User& user) = 0;
146
+ virtual std::vector<User> find_active() = 0;
147
+ };
148
+
149
+ class MockUserRepo : public UserRepo {
150
+ public:
151
+ MOCK_METHOD(std::optional<User>, find_by_email, (std::string_view), (override));
152
+ MOCK_METHOD(Result<User>, save, (const User&), (override));
153
+ MOCK_METHOD(std::vector<User>, find_active, (), (override));
154
+ };
155
+ ```
156
+
157
+ ### Matchers and Actions
158
+
159
+ ```cpp
160
+ using ::testing::_;
161
+ using ::testing::Return;
162
+ using ::testing::HasSubstr;
163
+ using ::testing::ElementsAre;
164
+ using ::testing::Field;
165
+
166
+ TEST_F(UserServiceTest, SavePassesCorrectData) {
167
+ EXPECT_CALL(*repo_, find_by_email(_)).WillOnce(Return(std::nullopt));
168
+
169
+ // Verify the saved user has the correct name
170
+ EXPECT_CALL(*repo_, save(Field(&User::name, "Alice")))
171
+ .WillOnce(Return(User{.id = 1, .name = "Alice"}));
172
+
173
+ service_->create_user({"Alice", "alice@example.com"});
174
+ }
175
+ ```
176
+
177
+ ---
178
+
179
+ ## Integration Testing
180
+
181
+ ```cpp
182
+ class DatabaseIntegrationTest : public ::testing::Test {
183
+ protected:
184
+ void SetUp() override {
185
+ db_ = std::make_unique<Database>(":memory:");
186
+ db_->migrate();
187
+ }
188
+
189
+ void TearDown() override {
190
+ db_.reset();
191
+ }
192
+
193
+ std::unique_ptr<Database> db_;
194
+ };
195
+
196
+ TEST_F(DatabaseIntegrationTest, InsertAndRetrieveUser) {
197
+ auto repo = UserRepo(*db_);
198
+
199
+ auto saved = repo.save(User{.name = "Alice", .email = "alice@example.com"});
200
+ ASSERT_TRUE(saved.has_value());
201
+
202
+ auto found = repo.find_by_email("alice@example.com");
203
+ ASSERT_TRUE(found.has_value());
204
+ EXPECT_EQ(found->name, "Alice");
205
+ }
206
+ ```
207
+
208
+ ---
209
+
210
+ ## Google Benchmark
211
+
212
+ ```cpp
213
+ #include <benchmark/benchmark.h>
214
+ #include "serializer.hpp"
215
+
216
+ static void BM_JsonSerialize(benchmark::State& state) {
217
+ auto user = User{.id = 1, .name = "Alice", .email = "alice@example.com"};
218
+ for (auto _ : state) {
219
+ auto json = serialize_to_json(user);
220
+ benchmark::DoNotOptimize(json);
221
+ }
222
+ }
223
+ BENCHMARK(BM_JsonSerialize);
224
+
225
+ static void BM_JsonDeserialize(benchmark::State& state) {
226
+ auto json = R"({"id":1,"name":"Alice","email":"alice@example.com"})";
227
+ for (auto _ : state) {
228
+ auto user = deserialize_from_json<User>(json);
229
+ benchmark::DoNotOptimize(user);
230
+ }
231
+ }
232
+ BENCHMARK(BM_JsonDeserialize);
233
+
234
+ BENCHMARK_MAIN();
235
+ ```
236
+
237
+ ---
238
+
239
+ ## Fuzz Testing with libFuzzer
240
+
241
+ ```cpp
242
+ // fuzz/fuzz_json_parser.cpp
243
+ #include "json_parser.hpp"
244
+ #include <cstdint>
245
+ #include <cstddef>
246
+
247
+ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
248
+ std::string_view input(reinterpret_cast<const char*>(data), size);
249
+ auto result = parse_json(input);
250
+ // If it does not crash or trigger sanitizers, the input is handled safely
251
+ return 0;
252
+ }
253
+ ```
254
+
255
+ ```cmake
256
+ # CMakeLists.txt for fuzz targets
257
+ add_executable(fuzz_json_parser fuzz/fuzz_json_parser.cpp)
258
+ target_compile_options(fuzz_json_parser PRIVATE -fsanitize=fuzzer,address,undefined)
259
+ target_link_options(fuzz_json_parser PRIVATE -fsanitize=fuzzer,address,undefined)
260
+ ```
261
+
262
+ ```bash
263
+ # Run fuzzer
264
+ ./build/fuzz_json_parser corpus/ -max_total_time=60
265
+ ```
266
+
267
+ ---
268
+
269
+ ## CMake Test Integration
270
+
271
+ ```cmake
272
+ # tests/CMakeLists.txt
273
+ include(GoogleTest)
274
+
275
+ add_executable(unit_tests
276
+ unit/test_user_service.cpp
277
+ unit/test_payment_processor.cpp
278
+ )
279
+ target_link_libraries(unit_tests PRIVATE
280
+ GTest::gtest_main
281
+ GTest::gmock
282
+ myapp_lib
283
+ )
284
+
285
+ gtest_discover_tests(unit_tests)
286
+ ```
287
+
288
+ ---
289
+
290
+ ## Test Commands
291
+
292
+ ```bash
293
+ # Fast feedback
294
+ ctest --test-dir build -R unit --output-on-failure # Unit tests only
295
+ ctest --test-dir build -R "UserService" -V # Single suite, verbose
296
+
297
+ # Full suite
298
+ ctest --test-dir build --output-on-failure
299
+
300
+ # With sanitizers
301
+ cmake --build build-asan && ctest --test-dir build-asan --output-on-failure
302
+
303
+ # Benchmarks (not in CTest by default)
304
+ ./build/bench/bench_serialization --benchmark_format=json
305
+ ```
306
+
307
+ ---
308
+
309
+ ## Test Markers (CTest Labels)
310
+
311
+ ```cmake
312
+ set_tests_properties(unit_tests PROPERTIES LABELS "unit")
313
+ set_tests_properties(integration_tests PROPERTIES LABELS "integration")
314
+ ```
315
+
316
+ ```bash
317
+ ctest --test-dir build -L unit # Run only unit tests
318
+ ctest --test-dir build -L integration # Run only integration tests
319
+ ```
320
+
321
+ ---
322
+
323
+ _Tests document behavior. Each test should read as a specification of what the code does._
@@ -0,0 +1,357 @@
1
+ # Code Quality Standards
2
+
3
+ Project memory for code quality conventions, static analysis, architecture testing, and null safety in Java 21+ with Gradle Kotlin DSL.
4
+
5
+ ---
6
+
7
+ ## Philosophy
8
+
9
+ - **Automate everything**: If a rule can be checked by a tool, it should be
10
+ - **Shift left**: Catch bugs at compile time, not in production
11
+ - **Architecture as code**: Enforce package dependencies and layering with ArchUnit
12
+ - **Zero warnings policy**: Treat warnings as errors in CI
13
+
14
+ ---
15
+
16
+ ## Checkstyle (Google Java Style)
17
+
18
+ ### Gradle Configuration
19
+
20
+ ```kotlin
21
+ // build.gradle.kts
22
+ plugins {
23
+ id("checkstyle")
24
+ }
25
+
26
+ checkstyle {
27
+ toolVersion = "10.20.1"
28
+ configFile = file("config/checkstyle/google_checks.xml")
29
+ isIgnoreFailures = false
30
+ maxWarnings = 0
31
+ }
32
+
33
+ tasks.withType<Checkstyle> {
34
+ reports {
35
+ xml.required.set(true)
36
+ html.required.set(true)
37
+ }
38
+ }
39
+ ```
40
+
41
+ ### Key Rules Enforced
42
+
43
+ | Rule | Description |
44
+ |---|---|
45
+ | `Indentation` | 2 spaces (Google style) or 4 spaces (project choice) |
46
+ | `LineLength` | Max 120 characters |
47
+ | `MethodLength` | Max 40 lines |
48
+ | `ParameterNumber` | Max 5 parameters |
49
+ | `AvoidStarImport` | No wildcard imports |
50
+ | `NeedBraces` | Braces required for all control structures |
51
+ | `MissingJavadocMethod` | Javadoc on public methods |
52
+
53
+ ```bash
54
+ ./gradlew checkstyleMain checkstyleTest
55
+ ```
56
+
57
+ ---
58
+
59
+ ## SpotBugs
60
+
61
+ ### Gradle Configuration
62
+
63
+ ```kotlin
64
+ // build.gradle.kts
65
+ plugins {
66
+ id("com.github.spotbugs") version "6.0.26"
67
+ }
68
+
69
+ spotbugs {
70
+ effort.set(com.github.spotbugs.snom.Effort.MAX)
71
+ reportLevel.set(com.github.spotbugs.snom.Confidence.MEDIUM)
72
+ excludeFilter.set(file("config/spotbugs/exclude.xml"))
73
+ }
74
+
75
+ tasks.withType<com.github.spotbugs.snom.SpotBugsTask> {
76
+ reports.create("html") { required.set(true) }
77
+ reports.create("xml") { required.set(true) }
78
+ }
79
+ ```
80
+
81
+ ### Exclusion Filter
82
+
83
+ ```xml
84
+ <!-- config/spotbugs/exclude.xml -->
85
+ <FindBugsFilter>
86
+ <Match>
87
+ <Class name="~.*\.dto\..*" />
88
+ <Bug pattern="EI_EXPOSE_REP,EI_EXPOSE_REP2" />
89
+ </Match>
90
+ <Match>
91
+ <Source name="~.*Test\.java" />
92
+ </Match>
93
+ </FindBugsFilter>
94
+ ```
95
+
96
+ ```bash
97
+ ./gradlew spotbugsMain
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Error Prone
103
+
104
+ Compile-time bug detection from Google:
105
+
106
+ ```kotlin
107
+ // build.gradle.kts
108
+ plugins {
109
+ id("net.ltgt.errorprone") version "4.1.0"
110
+ }
111
+
112
+ dependencies {
113
+ errorprone("com.google.errorprone:error_prone_core:2.36.0")
114
+ }
115
+
116
+ tasks.withType<JavaCompile> {
117
+ options.errorprone {
118
+ disableWarningsInGeneratedCode.set(true)
119
+ error(
120
+ "MissingOverride",
121
+ "EqualsHashCode",
122
+ "ReturnValueIgnored",
123
+ "UnnecessaryParentheses",
124
+ "FallThrough",
125
+ "MissingCasesInEnumSwitch",
126
+ "UnusedVariable"
127
+ )
128
+ }
129
+ }
130
+ ```
131
+
132
+ ### Common Error Prone Catches
133
+
134
+ ```java
135
+ // Error Prone catches: MissingOverride
136
+ public class UserService implements Service {
137
+ public void process() { ... } // ERROR: missing @Override
138
+ }
139
+
140
+ // Error Prone catches: ReturnValueIgnored
141
+ String trimmed = name.trim(); // GOOD
142
+ name.trim(); // ERROR: return value ignored (String is immutable)
143
+
144
+ // Error Prone catches: EqualsHashCode
145
+ public class User {
146
+ @Override
147
+ public boolean equals(Object o) { ... }
148
+ // ERROR: equals() without hashCode()
149
+ }
150
+ ```
151
+
152
+ ---
153
+
154
+ ## ArchUnit (Architecture Tests)
155
+
156
+ ### Dependency
157
+
158
+ ```kotlin
159
+ // build.gradle.kts
160
+ dependencies {
161
+ testImplementation("com.tngtech.archunit:archunit-junit5:1.3.0")
162
+ }
163
+ ```
164
+
165
+ ### Architecture Rules
166
+
167
+ ```java
168
+ @AnalyzeClasses(packages = "com.example")
169
+ class ArchitectureTest {
170
+
171
+ @ArchTest
172
+ static final ArchRule layerDependencies = layeredArchitecture()
173
+ .consideringAllDependencies()
174
+ .layer("Controller").definedBy("..controller..")
175
+ .layer("Service").definedBy("..service..")
176
+ .layer("Repository").definedBy("..repository..")
177
+ .layer("Domain").definedBy("..domain..")
178
+ .whereLayer("Controller").mayNotBeAccessedByAnyLayer()
179
+ .whereLayer("Service").mayOnlyBeAccessedByLayers("Controller", "Service")
180
+ .whereLayer("Repository").mayOnlyBeAccessedByLayers("Service")
181
+ .whereLayer("Domain").mayOnlyBeAccessedByLayers("Service", "Repository", "Controller");
182
+
183
+ @ArchTest
184
+ static final ArchRule servicesShouldNotDependOnControllers =
185
+ noClasses().that().resideInAPackage("..service..")
186
+ .should().dependOnClassesThat().resideInAPackage("..controller..");
187
+
188
+ @ArchTest
189
+ static final ArchRule controllersShouldBeAnnotated =
190
+ classes().that().resideInAPackage("..controller..")
191
+ .should().beAnnotatedWith(RestController.class);
192
+
193
+ @ArchTest
194
+ static final ArchRule noFieldInjection =
195
+ noFields().should().beAnnotatedWith(Autowired.class)
196
+ .because("Use constructor injection instead of field injection");
197
+
198
+ @ArchTest
199
+ static final ArchRule recordsShouldBeInDtoPackage =
200
+ classes().that().areRecords()
201
+ .and().haveSimpleNameEndingWith("Request")
202
+ .should().resideInAPackage("..dto..");
203
+ }
204
+ ```
205
+
206
+ ---
207
+
208
+ ## SonarQube Integration
209
+
210
+ ### Gradle Plugin
211
+
212
+ ```kotlin
213
+ // build.gradle.kts
214
+ plugins {
215
+ id("org.sonarqube") version "5.1.0.4882"
216
+ }
217
+
218
+ sonar {
219
+ properties {
220
+ property("sonar.projectKey", "my-project")
221
+ property("sonar.host.url", "http://localhost:9000")
222
+ property("sonar.java.source", "21")
223
+ property("sonar.coverage.jacoco.xmlReportPaths", "build/reports/jacoco/test/jacocoTestReport.xml")
224
+ property("sonar.exclusions", "**/dto/**,**/config/**")
225
+ }
226
+ }
227
+ ```
228
+
229
+ ```bash
230
+ ./gradlew sonar -Dsonar.token=your-token
231
+ ```
232
+
233
+ ### Quality Gate Metrics
234
+
235
+ | Metric | Threshold |
236
+ |---|---|
237
+ | Coverage | >= 80% |
238
+ | Duplicated lines | <= 3% |
239
+ | Maintainability rating | A |
240
+ | Reliability rating | A |
241
+ | Security rating | A |
242
+ | Technical debt ratio | <= 5% |
243
+
244
+ ---
245
+
246
+ ## Null Safety
247
+
248
+ ### @Nullable / @NonNull Annotations
249
+
250
+ ```java
251
+ // Use Spring's or JSpecify annotations project-wide
252
+ import org.springframework.lang.NonNull;
253
+ import org.springframework.lang.Nullable;
254
+
255
+ // GOOD: Annotate boundaries
256
+ public class UserService {
257
+
258
+ @NonNull
259
+ public User getUser(@NonNull Long id) {
260
+ return userRepository.findById(id)
261
+ .orElseThrow(() -> new NotFoundException("User", id));
262
+ }
263
+
264
+ @Nullable
265
+ public User findByEmail(@NonNull String email) {
266
+ return userRepository.findByEmail(email).orElse(null);
267
+ }
268
+ }
269
+
270
+ // GOOD: Package-level default with @NonNullApi
271
+ // package-info.java
272
+ @NonNullApi
273
+ package com.example.user.service;
274
+
275
+ import org.springframework.lang.NonNullApi;
276
+ ```
277
+
278
+ ### Optional vs @Nullable
279
+
280
+ | Return Type | When to Use |
281
+ |---|---|
282
+ | `Optional<T>` | Public API where absence is a normal outcome |
283
+ | `@Nullable T` | Internal methods, performance-sensitive code |
284
+ | `T` (non-null) | When null is never valid -- throw if missing |
285
+
286
+ ```java
287
+ // GOOD: Clear null contract
288
+ public Optional<User> findByEmail(String email) { ... } // public API
289
+ @Nullable User lookupCache(Long id) { ... } // internal
290
+
291
+ // BAD: Ambiguous null contract
292
+ public User findByEmail(String email) { ... } // returns null? throws? who knows
293
+ ```
294
+
295
+ ---
296
+
297
+ ## Spotless (Auto-Formatting)
298
+
299
+ ```kotlin
300
+ // build.gradle.kts
301
+ plugins {
302
+ id("com.diffplug.spotless") version "7.0.0"
303
+ }
304
+
305
+ spotless {
306
+ java {
307
+ googleJavaFormat("1.24.0")
308
+ removeUnusedImports()
309
+ trimTrailingWhitespace()
310
+ endWithNewline()
311
+ }
312
+ kotlinGradle {
313
+ ktlint()
314
+ }
315
+ }
316
+ ```
317
+
318
+ ```bash
319
+ ./gradlew spotlessCheck # Verify formatting
320
+ ./gradlew spotlessApply # Auto-format
321
+ ```
322
+
323
+ ---
324
+
325
+ ## CI Pipeline Quality Commands
326
+
327
+ ```bash
328
+ # Full quality pipeline (run in CI)
329
+ ./gradlew clean build # Compile + tests
330
+ ./gradlew checkstyleMain # Style enforcement
331
+ ./gradlew spotbugsMain # Bug detection
332
+ ./gradlew spotlessCheck # Format verification
333
+ ./gradlew jacocoTestReport # Coverage report
334
+ ./gradlew sonar # SonarQube analysis
335
+
336
+ # Quick local check
337
+ ./gradlew check # Runs all verification tasks
338
+ ./gradlew spotlessApply && ./gradlew check # Format + verify
339
+ ```
340
+
341
+ ---
342
+
343
+ ## Anti-Patterns
344
+
345
+ | Anti-Pattern | Problem | Correct Approach |
346
+ |---|---|---|
347
+ | No static analysis in CI | Bugs slip through to production | Run checkstyle + spotbugs + errorprone in CI |
348
+ | Suppressing all warnings | Hides real issues | Suppress only with documented justification |
349
+ | No architecture tests | Layering violations accumulate | ArchUnit tests enforce boundaries |
350
+ | Field injection (`@Autowired`) | Hides dependencies, untestable | Constructor injection |
351
+ | Missing null annotations | NPE surprises at runtime | `@NonNullApi` package default + `@Nullable` opt-in |
352
+ | Manual formatting debates | Wastes time in code review | Spotless auto-format, no discussion |
353
+ | Ignoring SonarQube debt | Technical debt grows silently | Quality gate blocks merges |
354
+
355
+ ---
356
+
357
+ _Quality is not an afterthought. Automate checks, enforce architecture, and treat every warning as a bug waiting to happen._