{"filename":"scala-kafka-cursorrules-prompt-file.mdc","content":"---\ndescription: \"Cursor rules for Scala Kafka.\"\nglobs: **/*\nalwaysApply: false\n---\n# general-scala-clean-code.mdc\n\n- Declare vals/vars as close as possible to first use.\n- Name length should be proportional to scope: 1-2 chars allowed only inside small lambdas.\n- Avoid nested for-comprehensions deeper than two levels; factor out steps into helpers.\n- Split a single source file by responsibility.\n- Use *tail-rec* optimisation (`@tailrec`) where appropriate.\n- Prefer *immutable* collections and avoid mutation during iteration.\n- When interop with Java forces mutability, wrap it in a pure facade with the use of .asScala, to retain functional API.\n- When something is nullable, wrap it into an Option, to retain functional API.\n- Keep cyclomatic complexity below 10 for any method; IDE inspections should warn.\n\n# general-scala-development-practices.mdc\n\n# ========== GENERAL PRINCIPLES ==========\n- You are an experienced Senior Scala Developer.\n- You always adhere to SOLID, DRY, KISS and YAGNI principles.\n- Prefer *pure* functions; minimise side-effects. Where effects are required, make them explicit (e.g. using scala.util.Try, Either, or cats-effect IO/Task if adopted).\n- Use *val* over *var*; collections must be immutable unless mutability is proven cheaper & safe.\n- Replace *null* with Option, Either or a domain-specific ADT.\n- Use pattern matching exhaustively and handle the *default* case only when truly open-ended.\n- Prefer for-comprehensions, map/flatMap/fold, and higher-order functions over imperative loops.\n- Prefer *case classes* and *sealed traits* for algebraic data types.\n- Extract common logic into private or package-private helpers; avoid long methods (> 30 LOC).\n- Prefer extension methods or type classes over inheritance when adding behaviour.\n- Keep public APIs small, surface only what the module owns.\n- Break every task into the smallest composable pure functions before wiring them together.\n\n# ========== NAMING & SYNTAX ==========\n- Class / object / trait names are UpperCamelCase nouns (e.g. *NotificationStreamApp*).\n- Methods & vals are lowerCamelCase verbs or nouns (e.g. *process*, *serde*, *productKey*).\n- Constants use `SCREAMING_SNAKE_CASE`.\n- Similar to Java’s static final members, if the member is final, immutable and it belongs to a package object or an object, it may be considered a constant.\n- Symbolic names (`|>`) are allowed *only* when they align with widespread FP idioms.\n- Match expressions use `match`/`case` over nested if/else chains; for simple two-branch logic prefer `if … then … else …` expressions.\n\n# ========== ERROR HANDLING & LOGGING ==========\n- Catch the most specific Exception first; convert checked Java exceptions to an ADT or `Try`.\n- No empty `catch` blocks; log at *debug* or *error* level with a meaningful message.\n- Leverage `scala.util.Using` (or cats-effect `Resource`) for auto-closing resources.\n- Avoid “defensive” logging or `println`; use SLF4J (Logback) with the *scala-logging* wrapper.\n\n# ========== TESTING ==========\n- Use ScalaTest in a **Given-When-Then** layout with the use of AnyFlatSpec.\n- Focus on critical paths and business invariants; do not over-test boilerplate.\n- Property-based tests (ScalaCheck) for pure functions with non-trivial invariants.\n- Set up integration tests as a subproject named “integration” and treat integration tests as standard tests\n\n# ========== PERFORMANCE & SAFETY ==========\n- Avoid blocking calls inside Kafka stream processing; if unavoidable, off-load to a dedicated thread-pool.\n- Convert Java collections to Scala equivalents once at the boundary; never bounce back and forth.\n- Use underscore-separated digits for large numeric literals (e.g. `val timeoutMs = 30_000`).\n\n# ========== MODERN SCALA 3 FEATURES ==========\n- Use *Enums* for finite alternatives instead of Java-style enums.\n- Embrace *opaque types* to avoid accidental misuse of primitive wrappers.\n- Use *context parameters* (`using`) for type-class evidence instead of classic implicit lists when convenient.\n- Prefer `given`/`using` syntax over `implicit` where supported.\n\n# ========== CLEAN BUILD ==========\n- The sbt build uses **scalafmt** for formatting; treat any scalafmt violation as a build error.\n\n# kafka-development-practices.mdc\n\n- All topic names config values (Typesafe Config or pure-config).\n- Use Format or Codec from the JSON or AVRO or another library that is being used in the project.\n- Streams logic must be tested with `TopologyTestDriver` (unit-test) plus an integration test against local Kafka.\n\n# linting-formatting.mdc\n\n- **scalafmt:** Enforce Google-inspired scalafmt configuration with `maxColumn = 100`.\n"}