🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
12 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
Ballistic Builder is a PCPartPicker-style platform for firearms, starting with the AR-15 ecosystem. It's a Spring Boot 3.4.3 application that:
- Ingests merchant feeds (AvantLink) and normalizes product data
- Manages complex category mappings and part role classification
- Provides REST APIs for a consumer-facing Builder application
- Enables users to browse parts, compare prices, and assemble builds
Critical: This is NOT:
- An e-commerce platform (does not sell products)
- A marketplace (does not process payments)
- A forum-first community
- An inventory management system
It IS:
- An affiliate-driven aggregation platform
- A data normalization engine disguised as a UI
- Focused on accuracy, clarity, and trust
Think: "Build smarter rifles, not spreadsheets."
Core Principles
When working on this codebase, always prioritize:
- Accuracy > Completeness - Correct data is more important than comprehensive data
- Idempotency > Speed - Operations must be safely repeatable
- Explicit data > Heuristics - Prefer manual mappings over inference when accuracy matters
- Long-term maintainability > Cleverness - Code readability 6-12 months out matters more than clever abstractions
- Incremental delivery - Small team, phased solutions, clear migration paths
Avoid introducing:
- Real-time inventory guarantees (merchant feeds are authoritative)
- Payment processing or checkout flows
- Legal/compliance risk (this is an aggregator, not a retailer)
- Over-engineered abstractions or premature optimization
- "Rewrite everything" solutions
Common Commands
Build & Run
# Clean build
mvn clean install
# Run development server (port 8080)
mvn spring-boot:run
# Run with Spring Boot DevTools hot reload
mvn spring-boot:run -Dspring-boot.run.jvmArguments="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005"
Testing
# Run all tests
mvn test
# Run specific test class
mvn test -Dtest=PlatformResolverTest
# Run with coverage
mvn clean test jacoco:report
Database
# PostgreSQL connection details in application.properties
# Default: jdbc:postgresql://r710.gofwd.group:5433/ss_builder
# User: postgres
API Documentation
- Swagger UI: http://localhost:8080/swagger-ui.html
- OpenAPI spec: http://localhost:8080/v3/api-docs
Architecture Overview
Layered Architecture Pattern
Controllers (REST API endpoints)
↓
Services (Business logic + validation)
↓
Repositories (Spring Data JPA)
↓
Models (JPA Entities)
↓
PostgreSQL Database
Package Structure
Core Packages:
catalog/classification/- Platform resolution and product classification enginecontrollers/- REST API endpoints (v1 convention, admin panel)enrichment/ai/- AI-powered product data enhancement (OpenAI integration)imports/- CSV/TSV feed import functionality for merchant datamodel/- JPA entities (Product, User, Build, Brand, Merchant, etc.)repos/- Spring Data JPA repositoriessecurity/- JWT authentication, token validation, user detailsservices/- Business logic layer (interface + impl pattern)web/dto/- Data Transfer Objects for API contractsweb/mapper/- Entity to DTO conversion utilities
Key Technologies
- Java 21
- Spring Boot 3.4.3 (Spring Data JPA, Spring Security, Spring Mail)
- PostgreSQL 42.7.7 with HikariCP connection pooling
- JWT authentication (JJWT 0.11.5)
- MinIO 8.4.3 (S3-compatible object storage for images)
- Apache Commons CSV 1.11.0 (feed processing)
- SpringDoc OpenAPI 2.8.5 (API documentation)
Critical Domain Concepts
Product Classification System
Platform Resolution: Products are automatically classified to gun platforms (AR-15, AK-47, etc.) using rule-based logic in catalog/classification/PlatformResolver. Rules are stored in the platform_rule table and evaluated against product attributes (name, brand, MPN, UPC).
Part Role Mapping: Products are assigned part roles (Upper Receiver, Barrel, etc.) through:
- Automatic classification via
PartRoleRuleentities - Manual merchant category mappings in
MerchantCategoryMap - Manual overrides with
platform_lockedflag
Category Normalization: Raw merchant categories are mapped to CanonicalCategory through CategoryMapping entities. Unmapped categories are exposed in the admin UI for manual assignment.
Merchant Feed Ingestion (Critical)
The import system is the heart of the platform. The imports/ package handles CSV/TSV feed imports from AvantLink merchants with these critical characteristics:
Idempotency by Design:
- Safe to re-run repeatedly without side effects
- Never duplicates products or offers
- Handles dirty, malformed, or incomplete feeds gracefully
Import Modes:
- Full Import - Products + offers (initial or full sync)
- Offer-Only Sync - Price/stock refresh for existing products
Deduplication Rules:
- Products deduped by Brand + MPN (primary key combination)
- UPC fallback for future enhancement
- Offers are merchant-specific (same product can have multiple offers)
- Offers track
firstSeenAtandlastSeenAttimestamps
Process Flow:
- Auto-detects delimiters (CSV/TSV)
- Creates or updates
Productentities - Upserts
ProductOfferentities (price, stock, merchant URL) - Tracks
FeedImportstatus and history - Logs errors without breaking entire import
Never Break Idempotency - Any change to the import system must maintain the property that running imports multiple times produces the same result.
Build System
Users create gun builds (Build entity) composed of BuildItem entities. Each build can be:
- Public (visible in community)
- Private (user-only)
- Linked to specific platforms
- Priced via aggregated
ProductOfferdata
Authentication & Authorization
JWT Flow:
- User logs in via
/api/auth/login JwtServicegenerates access token (48-hour expiry)- Token stored in
AuthTokentable JwtAuthenticationFiltervalidates token on each request- Principal stored as UUID string in SecurityContext
Roles: USER, ADMIN (role-based access control via Spring Security)
Magic Links: Users can request passwordless login links (30-day token expiry)
Performance Considerations
Recent Optimizations
- API batch sizes reduced: Catalog endpoints previously returned 2000 products per call, now paginated to ~48 items
- DTO optimization:
ProductDTOstreamlined for faster serialization - N+1 query prevention: Use
@EntityGraphannotations to eagerly fetch relations
Caching Strategy
- Spring Caching enabled globally (
@EnableCaching) - Product details cached in
ProductV1Controller - Clear cache after imports or admin updates
Database Query Patterns
- Use
JpaSpecificationExecutorfor dynamic filtering - Complex aggregations use native PostgreSQL queries
- HikariCP max connection lifetime: 10 minutes
API Design Patterns
Endpoint Conventions
- Public API:
/api/v1/{resource} - Admin API:
/api/v1/admin/{resource} - Auth endpoints:
/api/auth/{action} - Legacy endpoints return 410 Gone (intentionally deprecated)
Request/Response Flow
- Controller receives request with DTOs
- Validates input (Spring Validation)
- Maps DTO to entity via mapper
- Calls service layer (business logic)
- Service interacts with repositories
- Maps entity back to DTO
- Returns JSON response
Authorization Patterns
- JWT token in
Authorization: Bearer <token>header - Role checks via
@PreAuthorize("hasRole('ADMIN')")or SecurityConfig rules - User identity extracted from SecurityContext via
JwtAuthenticationFilter
Common Development Patterns
Adding a New API Endpoint
- Create DTO classes in
web/dto/(request + response) - Create/update service interface in
services/ - Implement service in
services/impl/ - Create controller in
controllers/(follow naming:{Resource}V1Controller) - Inject service via constructor
- Add authorization rules in
SecurityConfigor@PreAuthorize - Document with SpringDoc annotations (
@Operation,@ApiResponse)
Entity Relationships
- Use
@EntityGraphto prevent N+1 queries - Soft delete pattern:
deletedAtfield (filterWHERE deleted_at IS NULL) - Temporal tracking:
createdAt,updatedAtvia@PrePersist/@PreUpdate - Avoid bidirectional relationships unless necessary
Service Layer Pattern
- Define interface:
public interface BrandService { ... } - Implement:
@Service public class BrandServiceImpl implements BrandService - Use constructor injection for dependencies
- Handle business logic, validation, and transactions
Configuration
Environment-Specific Settings
Key properties in src/main/resources/application.properties:
# Database
spring.datasource.url=jdbc:postgresql://r710.gofwd.group:5433/ss_builder
# JWT
security.jwt.secret=ballistic-test-secret-key-...
security.jwt.access-token-minutes=2880 # 48 hours
# MinIO (image storage)
minio.endpoint=https://minioapi.dev.gofwd.group
minio.bucket=battlbuilders
minio.public-base-url=https://minio.dev.gofwd.group
# Email (SMTP)
spring.mail.host=mail.goforwardmail.com
spring.mail.username=info@battl.builders
# AI/OpenAI
ai.openai.apiKey=sk-proj-...
ai.openai.model=gpt-4.1-mini
ai.minConfidence=0.75
# Feature Flags
app.api.legacy.enabled=false
app.beta.captureOnly=true
app.email.outbound-enabled=true
CORS Configuration
Allowed origins configured in CorsConfig:
http://localhost:3000(React dev)http://localhost:8080,8070,4200,4201
Important Notes
Legacy Code
ProductControllerintentionally returns 410 Gone (deprecated API v0)- Old
Accountmodel coexists with newerUsermodel - JSP support included but not actively used
Security Warnings
- Credentials in
application.propertiesshould use environment variables in production - Rotate OpenAI API key regularly
- Use secrets manager for email passwords
- Ensure magic link tokens have short expiration
Multi-Tenancy
- System supports multiple merchants via
Merchantentity - Category mappings are merchant-specific (
MerchantCategoryMap) - Platform rules engine allows per-merchant classification overrides
Testing Strategy
- TestNG framework included
- Minimal test coverage currently
- Key test:
PlatformResolverTestfor classification logic - Integration tests should cover feed import flows
Development Constraints & Guidelines
Team Context
This is a small team building for longevity and credibility. Code decisions should account for:
- Code readability 6-12 months from now
- Incremental delivery over big-bang rewrites
- Clear migration paths when refactoring
- Minimal external dependencies unless truly necessary
When Proposing Changes
- Feature requests: Propose phased, minimal solutions
- Refactors: Explain tradeoffs and provide migration steps
- Debugging: Reason from architecture first (check layers: controller → service → repo → entity)
- Design questions: Follow the PCPartPicker mental model
- Scaling concerns: Assume success but move incrementally
What NOT to Suggest
- Rewriting large portions of the codebase
- Adding frameworks for problems that don't exist yet
- Magical inference engines or hidden behavior
- Solutions that introduce legal/compliance risk
- Features that assume this is an e-commerce checkout platform
Frontend Assumptions
The Next.js/React frontend depends on this backend for:
- Normalized APIs (backend owns business logic)
- Part role authoritative data
- Backend-driven compatibility rules
- No duplication of backend logic in frontend
How to Work with This Codebase
To Understand a Feature
- Find the REST endpoint in
controllers/ - Trace the service call in
services/(interface → impl) - Check repository queries in
repos/ - Review model relationships in
model/ - Check DTOs in
web/dto/for request/response contracts
To Debug an Issue
- Check controller layer for request validation
- Verify service layer business logic
- Inspect repository queries (check for N+1)
- Review entity relationships and fetch strategies
- Check application.properties for configuration issues
- Review logs for SQL queries (Hibernate logging)
Red Flags to Watch For
- Breaking idempotency in import system
- Introducing N+1 query problems
- Adding credentials to application.properties
- Creating bidirectional JPA relationships without careful consideration
- Bypassing the service layer from controllers
- Duplicating business logic in DTOs or controllers