| description | Java Chat - AI-powered Java learning with streaming responses, citations, and knowledge augmentation |
|---|---|
| alwaysApply | true |
- [ORG1] Purpose: keep every critical rule within the first ~250 lines; move long examples/notes to Appendix.
- [ORG2] Structure: Rule Summary first, then detailed sections keyed by short hashes (e.g.,
[GT1a]). - [ORG3] Usage: cite hashes when giving guidance or checking compliance; add new rules without renumbering older ones.
- [ORG4] Directive language: rules use imperative/prohibitive phrasing ("do X", "no Y", "never Z"); no discretionary hedges ("prefer", "consider", "try to", "ideally", "when possible") that give agents interpretive latitude.
- [ZA1a-c] Zero Tolerance Policy (zero assumptions, validation workflow, forbidden practices)
- [GT1a-l] Git, history safety, hooks/signing, lock files, and clean commits
- [CC1a-d] Clean Code & DDD (Mandatory)
- [ID1a-d] Idiomatic Patterns & Defaults
- [EV1a-f] Secrets and Env Vars (no secrets in properties; OpenAI/Qdrant via .env/env)
- [RC1a-f] Root Cause Resolution (single implementation, no fallbacks, no shims/workarounds)
- [FS1a-k] File Creation & Clean Architecture (search first, strict types, single responsibility)
- [TY1a-d] Type Safety (strict generics, no raw types, no unchecked casts)
- [FV1a-h] Frontend Validation (Zod schemas, discriminated unions, never swallow errors)
- [AB1a-d] Abstraction Discipline (reuse-first, no anemic wrappers)
- [NO1a-e] Null/Optional Discipline (no null returns, use Optional/empty collections)
- [AR1a-f] Architecture & Boundaries (canonical roots, layer rules, framework-free domain)
- [CS1a-h] Code Smells (primitive obsession, data clumps, magic literals)
- [VR1a-c] Verification Loops (build/test/run)
- [JD1a-h] Javadoc Standards (mandatory, why > what)
- [ND1a-h] Naming Discipline (intent-revealing, banned generics, constant naming, type names)
- [ZA1a] Assume Blindness: Your training data for APIs/versions is FALSE until verified.
- [ZA1b] Scout Phase: Before coding, use tools (
context7,perplexity) and check local sources (~/.m2,~/.gradle,node_modules) to verify existence/signatures of APIs. - [ZA1c] Source Verification: For dependency code questions, inspect
~/.m2JARs or~/.gradle/caches/(for Java) orfrontend/node_modules(for frontend) first; fallback to upstream GitHub; never answer without referencing code. - [ZA1d] Forbidden Practices:
- No
Map<String, Object>, raw types, unchecked casts,@SuppressWarnings, oreslint-disablein production. - No trusting memory—verify every import/API/config against current docs.
- No
- [ZA1e] Mandatory Research: You MUST research dependency questions and correct usage. Never use legacy or
@deprecatedusage from dependencies. Ensure correct usage by reviewing related code directly innode_modulesor Gradle caches and using online tool calls. - [ZA1f] Dependency Search: To search
node_modulesefficiently withast-grep, target specific packages:ast-grep run --pattern '...' frontend/node_modules/<package>. Do NOT scan the entirenode_modulesfolder.
- [GT1a] Never bypass pre-commit hooks or commit signing.
- [GT1b] If hooks fail, fix the environment; do not force the commit.
- [GT1c] Read-only git commands (e.g.,
git status,git diff,git log,git show) never require permission. Any git command that writes to the working tree, index, or history requires explicit permission. - [GT1d] Commit message standards: one logical change per commit; describe the change and purpose; no tooling/AI references; no
Co-authored-byor AI attribution. - [GT1e] Do not amend or rewrite history (no
--amend, no force pushes) without explicit user permission. - [GT1f] Do not change branches (checkout/merge/rebase/pull) unless the user explicitly instructs it.
- [GT1g] Destructive git commands are prohibited unless explicitly ordered by the user (e.g.,
git restore,git reset, force checkout). - [GT1h] Never delete lock files automatically (including
.git/index.lock). Stop and ask for instruction. - [GT1i] Treat existing staged/unstaged changes as intentional unless the user says otherwise; never “clean up” someone else’s work unprompted.
- [GT1j] Git commands that write to the working tree, index, or history require elevated permissions; never run without escalation.
- [GT1k] Do Not Block On Baseline Diffs: If
git statusalready shows modified files when you start, assume those changes are intentional and continue the requested task without stopping to ask about them. Avoid touching unrelated files. - [GT1l] Stop Only On Concurrent Drift: Only stop and ask for direction if a file changes unexpectedly during your work in a way that conflicts with edits you are actively making (e.g., a file you are editing changes on disk between reads/writes). Otherwise, proceed and keep changes scoped.
- [CC1a] Mandatory Principles: Clean Code principles (Robert C. Martin) and Domain-Driven Design (DDD) are mandatory and required in this repository.
- [CC1b] DRY (Don't Repeat Yourself): Avoid redundant code. Reuse code where appropriate and consistent with clean code principles.
- [CC1c] YAGNI (You Aren't Gonna Need It): Do not build features or abstractions "just in case". Implement only what is required for the current task.
- [CC1d] Clean Architecture: Dependencies point inward. Domain logic has zero framework imports.
- [ID1a] Defaults First: Always prefer the idiomatic, expected, and default patterns provided by the framework, library, or SDK (Spring Boot, Java 21+, etc.).
- [ID1b] Custom Justification: Custom implementations require a compelling reason. If you can't justify it, use the standard way.
- [ID1c] No Reinventing: Do not build custom utilities for things the platform already does (e.g., use standard
Optional,Stream, SpringRestTemplate/WebClient). - [ID1d] Dependencies: Make careful use of dependencies. Do not make assumptions—use the correct idiomatic behavior to avoid boilerplate.
- [EV1a] No Secrets In Properties/YAML: Secrets are PROHIBITED in
.propertiesand.yml/.yaml(including examples). Do not add secret-looking keys with blank defaults to property files. - [EV1b] Secrets Source Of Truth: Secrets MUST be provided via
.env(local) and environment variables (deployment). Deployment uses Coolify containers with BuildKit secrets; keep secrets out of tracked config. - [EV1c] Non-Secret Defaults In Properties: All non-secret defaults and environment-specific overrides MUST live in Spring property files (
src/main/resources/application*.properties) and Spring profiles. - [EV1d] Allowed
.env/Env Vars For External Services: OpenAI/GitHub Models and Qdrant connectivity MUST come from.env/environment variables:- LLM (model/base-url/api-key):
OPENAI_API_KEY,OPENAI_BASE_URL,OPENAI_MODEL,GITHUB_TOKEN,GITHUB_MODELS_BASE_URL,GITHUB_MODELS_CHAT_MODEL - Qdrant (host/ports/tls/api-key):
QDRANT_HOST,QDRANT_PORT,QDRANT_REST_PORT,QDRANT_SSL,QDRANT_API_KEY
- LLM (model/base-url/api-key):
- [EV1e] No New Env Var Settings: Do not introduce any additional env-var-driven settings without explicit written approval.
- [EV1f] Dotenv Handling:
.envloading MUST remain supported for local development and scripts. Do not add dotenv libraries into the Java runtime; load env vars at the process level (Makefile/scripts/Coolify).
- [RC1a] One Way: Ship one proven implementation—no fallback paths, no "try X then Y", no silent degradation.
- [RC1b] No Shims: NO compatibility layers, shims, adapters, or wrappers that hide defects.
- [RC1c] Fix Roots: Investigate → understand → fix root causes. Do not add band-aids to silence errors.
- [RC1d] Dev Logging: Dev-only logging is allowed to learn (must not change behavior, remove before shipping).
- [RC1e] Exceptions: Use typed exception handling patterns; propagate meaningful errors, never swallow silently.
- [RC1f] Explicit Violations: Any of the following is a violation that must be removed, not justified:
- Returning "best effort" results after a dependency failure (LLM, embeddings, vector store, database, filesystem).
- Catching and logging an exception while continuing as if the operation succeeded.
- Adding a secondary retrieval/indexing path that runs only when the primary path fails.
- [FS1a] Search First: Search exhaustively for existing logic → reuse or extend → only then create new files.
- [FS1b] Single Responsibility: New features belong in NEW files named for their single responsibility. Do not cram code into existing files.
- [FS1c] Canonical Roots:
boot/,application/,domain/,adapters/,support/. - [FS1d] Convention over Configuration: Prefer Spring Boot defaults and existing utilities.
- [FS1e] No Generic Utilities: Reject
*Utils/*Helper/*Common. Banned:BaseMapper<T>,GenericRepository<T,ID>,SharedUtils. - [FS1f] Large Files: >500 LOC is a monolith. Extract pieces you touch into clean-architecture roots.
- [FS1g] Domain Value Types: Identifiers, amounts, slugs wrap in records with constructor validation; never raw primitives across API boundaries.
- [FS1h] Single Responsibility Methods: No dead code; no empty try/catch that swallows exceptions.
- [FS1i] Dependency Injection: Never manually instantiate
ObjectMapper,RestTemplate, orHttpClient; always inject the Spring-managed bean. - [FS1j] Custom Properties: Custom
app.*properties require@ConfigurationPropertiesbinding inAppProperties. - [FS1l] Contract:
docs/contracts/code-change.md
- [TY1a] Strict Generics: No raw types (e.g.,
Listwithout<T>). - [TY1b] No Unchecked Casts: If a cast is unavoidable, guard with explicit conversions (e.g.,
Number::intValue) instead of suppressing. - [TY1c] No Suppressions: Never use
@SuppressWarningsto resolve lint issues; fix the code. - [TY1d] No
Map<String, Object>: Use typed records or classes.
- [FV1a] Mandatory Validation: All external data (API responses, SSE events, localStorage) MUST be validated through Zod schemas before use. External data is
unknownuntil validated. - [FV1b] No
asCasts: Never useas Typeassertions for external data. Use ZodsafeParse()with proper error handling. - [FV1c] Discriminated Unions: Return
{ success: true, data }or{ success: false, error }, nevernull. No silent fallbacks. - [FV1d] Never Swallow Errors: Every validation failure MUST be logged with full context via
logZodFailure(). No empty catch blocks. - [FV1e] Record Identification: Every error log MUST identify WHICH record failed (slug, ID, URL, endpoint name).
- [FV1f] Single Source of Truth: All schemas live in
frontend/src/lib/validation/schemas.ts. Types are inferred viaz.infer<>, never duplicated. - [FV1g] No
parse(): UsesafeParse()exclusively.parse()throws and can crash rendering. - [FV1h] Schema Matches API: Schema
optional()/nullable()/nullish()MUST match the actual API contract. Verify against real responses.
@see docs/type-safety-zod-validation.md for full patterns and examples.
- [AB1a] No Anemic Wrappers: Do not add classes that only forward calls without domain value.
- [AB1b] Earn Reuse: New abstractions must earn reuse—extend existing code first; only add new type/helper when it removes real duplication.
- [AB1c] Behavior Locality: Keep behavior close to objects: invariants live in domain model/services, not mappers or helpers.
- [AB1d] Delete Unused: Delete unused code instead of keeping it "just in case."
- [NO1a] No Null Returns: Public methods never return null; singletons use
Optional<T>; collections return empty, never null. - [NO1b] Domain Invariants: Domain models enforce invariants; avoid nullable fields unless business-optional and documented.
- [NO1c] Empty Collections: Return
List.of(),Set.of(),Map.of()instead of null. - [NO1d] No Optional Params: Optional parameters prohibited in business logic: accept nullable
T, check internally; call sites unwrap with.orElse(null). - [NO1e] Usage: Use
Optional.map/flatMap/orElseThrow; avoidisPresent()/get()chains.
- [AR1a] Controllers (adapters/in/web): Translate HTTP to domain, delegate to one use case, return
ResponseEntity; no repo calls, no business logic. - [AR1b] Use Cases (application/): Transactional boundary, single command, orchestrate domain/ports.
- [AR1c] Domain (domain/): Invariants/transformations, framework-free, no Spring imports.
- [AR1d] Adapters (adapters/out/): Implement ports, persist validated models, no HTTP/web concerns.
- [AR1e] Composition: Favor composition over inheritance; constructor injection only; services stateless.
- [AR1f] Monoliths: Monolith = >500 LOC or multi-concern catch-all. Shrink on touch.
- [CS1a] Primitive Obsession: Wrap IDs/amounts/business values in domain types when they carry invariants.
- [CS1b] Data Clumps: When 3+ parameters travel together, extract into a record (
DateRange,PageSpec,SearchCriteria). - [CS1c] Long Params: >4 parameters use parameter object or builder; never add 5th positional argument.
- [CS1d] Feature Envy: If method uses another object's data more than its own, move it there.
- [CS1e] Switch on Type: Replace with polymorphism when branches >3 or recur.
- [CS1f] Temporal Coupling: Enforce call order via state machine, builder, or combined API.
- [CS1g] Magic Literals: No inline numbers (except 0, 1, -1) or strings; define named constants.
- [CS1h] Comment Deodorant: If comment explains what, refactor until self-documenting; comments explain why only.
- [VR1a] Build:
make buildor./gradlew build; expect success. - [VR1b] Tests:
make testor./gradlew test; targeted runs use--tests ClassName. - [VR1c] Runtime:
make run &, hit/actuator/healthand changed endpoints; then stop.
- [JD1a] Mandatory: Javadocs mandatory on public/protected classes, methods, and enums.
- [JD1b] Why > What: Focus on "why" (purpose, rationale, constraints) over "what".
- [JD1c] Summary: First sentence is the summary: complete sentence, present tense, third person.
- [JD1d] Tags: Use
@paramonly when name isn't self-documenting; use@returnonly for non-obvious values. - [JD1e] Throws: Include
@throwsfor checked exceptions and runtime exceptions callers should handle. - [JD1f] Evidence: Cite sources inline (e.g., "Per RFC 7231").
- [JD1g] Deprecation:
@Deprecatedannotation AND@deprecatedtag with migration path. - [JD1h] No Filler: Ban "This method...", "Gets the...". Start with verb or noun directly.
- [DS1a] Locate: Find source JARs in Gradle cache:
find ~/.gradle/caches/modules-2/files-2.1 -name "*-sources.jar" | grep <artifact>. - [DS1b] List: View JAR contents without extraction:
unzip -l <jar_path> | grep <ClassName>. - [DS1c] Read: Pipe specific file content to stdout:
unzip -p <jar_path> <internal/path/to/Class.java>. - [DS1d] Search: To use
ast-grepon dependencies, pipe content directly:unzip -p <jar> <file> | ast-grep run --pattern '...' --lang java --stdin. No temp files required. - [DS1e] Efficiency: Do not extract full JARs. Use CLI piping for instant access.
- [DS1f] Ensure Sources: If sources are missing, assume standard dev environment has them or instruct user to run
./gradlew downloadSources(if alias exists).
- [TL1a] Commands:
make run,make dev,make test,make build,make compose-up,make compose-down. - [TL1b] Docker:
docker compose up -dfor Qdrant vector store. - [TL1c] Ingest:
curl -X POST http://localhost:8080/api/ingest .... - [TL1d] Stream:
curl -N http://localhost:8080/api/chat/stream .... - [TL1e] Secrets: Never commit secrets. Secrets MUST live in
.env(local) and environment variables (deployment). Secrets are PROHIBITED in.properties/.ymlfiles.
- [LM1a] Settings: Do not change any LLM settings without explicit written approval.
- [LM1b] No Fallback: Do not auto-fallback or regress models across providers; surface error to user.
- [LM1c] Config: OpenAI/GitHub Models model/base-url/api-key MUST come from
.env/environment variables (see [EV1d]). All other LLM settings MUST come from Spring property files and@ConfigurationProperties. - [LM1d] Behavior: Allowed: logging diagnostics. Not allowed: silently changing LLM behavior.
- [LM1e] Streaming: TTFB < 200ms, streaming start < 500ms.
- [LM1f] Events:
text,citation,code,enrichment,suggestion,status. - [LM1g] Errors:
onErrorContinuefor partial failures; never drop entire response on single failure. - [LM1h] Heartbeats: Maintain connection with periodic events during long operations.
- [MD1a] No Regex: No regex for HTML/Markdown processing; use proper parsers (Flexmark, DOM APIs).
- [MD1b] Structured Data: Parse to objects, transform, serialize.
- [MD1c] Idiomatic: Use Java Streams, Optional, proper HTML APIs.
- [MD1d] Separation: Backend handles structure, frontend handles presentation.
- [MD1e] Fail-safe: Graceful degradation when parsing fails; never crash on malformed input.
- [ND1a] Intent-Revealing: Every identifier (variable, parameter, method, class, constant) must be domain-specific and intent-revealing; a reader must understand purpose without context from surrounding code.
- [ND1b] Banned Single-Letter Variables:
a,b,c,d,n,o,p,s,t,v,x,y,zare prohibited as variable/parameter names. Exceptions:i,j,kin trivial indexedforloops; single-char lambda params only when the type is unambiguous in a one-expression pipeline (e.g.,list.stream().map(e -> e.name()));eincatchblocks. - [ND1c] Banned Generic Nouns: These names (and close variants) are prohibited as variable, parameter, or field names:
data,info,value,val,item,items,obj,object,result,results,response,payload,content,stuff,thing,entry,element,record,temp,tmp,misc,foo,bar,baz,dummy,sample. Use domain-specific names that describe what the variable holds (e.g.,embeddingVectornotdata;chatMessagenotitem;rankedDocumentsnotresults). - [ND1d] Banned Abbreviations: No abbreviated variable names:
val,res,req,resp,msg,str,num,cnt,idx,len,buf,ctx,cfg,mgr,impl,proc,ref,desc,doc,col,cb. Use full words:message,request,response,count,index,length,buffer,context,configuration,manager,description,document,column,callback. - [ND1e] Constants:
UPPER_SNAKE_CASEwith domain-qualifying prefix; no bare generic constant names likeVALUE,DATA,DEFAULT,THRESHOLD,LIMIT,SIZE,TIMEOUT,COUNT,MAX,MINwithout a qualifying domain noun (e.g.,EMBEDDING_DIMENSIONnotSIZE;RERANKER_TIMEOUT_MSnotTIMEOUT;MAX_RETRIEVAL_RESULTSnotMAX). - [ND1f] Type Names: No generic suffixes
*Data,*Info,*Object,*Item,*Wrapper,*Holder,*Container,*Manager(unless the class genuinely manages a lifecycle); class and record names declare their domain role. - [ND1g] Alias Consistency: The same concept uses the same name across method signatures, variable assignments, log messages, and documentation; do not alias the same thing with different names in the same scope or call chain.
- [ND1h] Legacy Fix-on-Touch: When editing code that uses banned or generic names, rename them in the same edit; never introduce new generic names into existing code.