home / skills / jpicklyk / task-orchestrator / backend-implementation

This skill helps you design and implement Kotlin Spring Boot REST APIs with robust validation, testing, and clean architecture.

npx playbooks add skill jpicklyk/task-orchestrator --skill backend-implementation

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
10.4 KB
---
name: Backend Implementation
description: Backend development with Kotlin, Spring Boot, REST APIs. Use for backend, api, service, kotlin, rest tags. Provides validation commands, testing patterns, and blocker scenarios.
allowed-tools: Read, Write, Edit, Bash, Grep, Glob
---

# Backend Implementation Skill

Domain-specific guidance for backend API development, service implementation, and business logic.

## When To Use This Skill

Load this Skill when task has tags:
- `backend`, `api`, `service`, `kotlin`, `rest`
- `spring`, `spring-boot`, `controller`, `repository`

## Validation Commands

### Run Tests
```bash
# Full test suite
./gradlew test

# Specific test class
./gradlew test --tests "UserServiceTest"

# Single test method
./gradlew test --tests "UserServiceTest.shouldCreateUser"

# With build
./gradlew clean test
```

### Build Project
```bash
# Build JAR
./gradlew build

# Build without tests (for quick syntax check)
./gradlew build -x test
```

### Run Application
```bash
# Local development
./gradlew bootRun

# With specific profile
./gradlew bootRun --args='--spring.profiles.active=dev'
```

## Success Criteria (Before Completing Task)

✅ **ALL tests MUST pass** (0 failures, 0 errors)
✅ **Build MUST succeed** without compilation errors
✅ **Code follows project conventions** (existing patterns)
✅ **API endpoints tested** (integration tests)
✅ **Error handling implemented** (try-catch, validation)

## Common Backend Tasks

### REST API Endpoints
- Controller with request mapping
- Request/response DTOs
- Service layer business logic
- Repository integration
- Error handling (400, 401, 404, 500)
- Validation (@Valid annotations)

### Service Implementation
- Business logic in service classes
- Transaction management (@Transactional)
- Error handling and exceptions
- Dependency injection (@Autowired, constructor injection)

### Database Integration
- Repository interfaces (JPA, Exposed ORM)
- Entity mapping
- Query methods
- Transaction boundaries

## Testing Principles for Backend

### Use Real Infrastructure for Integration Tests

❌ **AVOID mocking repositories in integration tests:**
```kotlin
// BAD - Mocking repositories misses SQL errors, constraints
@Mock private lateinit var userRepository: UserRepository
when(userRepository.findById(any())).thenReturn(mockUser)
```

✅ **USE real in-memory database:**
```kotlin
// GOOD - Tests actual integration
@SpringBootTest
@Transactional  // Auto-rollback after each test
class UserApiTest {
    @Autowired private lateinit var userRepository: UserRepository
    @Autowired private lateinit var userService: UserService
    // Tests real database, serialization, constraints
}
```

### Test Incrementally, Not in Batches

❌ **Avoid:** Write 200 lines code + 15 tests → run all → 12 failures → no idea which code caused which failure

✅ **Do:**
1. Write basic implementation
2. Write ONE happy path test
3. Run ONLY that test: `./gradlew test --tests "ToolTest.shouldHandleBasicCase"`
4. Fix until passes
5. Add ONE edge case test
6. Run ONLY that test
7. Repeat

**Benefits:** Feedback in seconds, isolates root cause immediately.

### Debug with Actual Output

When test fails:
1. **Read error message carefully** - tells you what's wrong
2. **Print actual output:**
   ```kotlin
   println("Full response: $result")
   println("Response keys: ${result.jsonObject.keys}")
   ```
3. **Verify assumptions about test data** - count manually
4. **Fix root cause, not symptoms**

### Create Complete Test Entities

❌ **BAD - Missing required fields:**
```kotlin
val task = Task(
    id = UUID.randomUUID(),
    title = "Test Task",
    status = TaskStatus.PENDING
    // Missing: summary, priority, complexity, timestamps
)
taskRepository.create(task)  // FAILS: NOT NULL constraint
```

✅ **GOOD - Complete entity:**
```kotlin
val task = Task(
    id = UUID.randomUUID(),
    title = "Test Task",
    summary = "Test summary",               // Required
    status = TaskStatus.PENDING,            // Required
    priority = Priority.HIGH,               // Required
    complexity = 5,                         // Required
    tags = listOf("test"),
    projectId = testProjectId,
    createdAt = Instant.now(),              // Required
    modifiedAt = Instant.now()              // Required
)
```

**How to find required fields:** Check migration SQL or ORM model definition.

## Common Blocker Scenarios

### Blocker 1: Missing Database Schema

**Issue:** Tests expect column that doesn't exist
```
SQLSyntaxErrorException: Unknown column 'users.password_hash'
```

**What to try:**
- Check migration files - is column defined?
- Review prerequisite database tasks - marked complete but incomplete?
- Check if column was renamed

**If blocked:** Report to orchestrator - database task may need reopening

### Blocker 2: NullPointerException in Service

**Issue:** NPE at runtime in service class
```
NullPointerException: Cannot invoke method on null object
```

**What to try:**
- Check dependency injection - is @Autowired present?
- Check constructor injection - all parameters provided?
- Check @Configuration on config class
- Check @Service or @Component on service class
- Add null safety (Kotlin: use `?` operator, nullable types)

**Common causes:**
- Missing @Configuration annotation
- Spring not scanning package
- Circular dependency

### Blocker 3: Integration Test Failures

**Issue:** Integration tests pass locally but fail in CI or for others

**What to try:**
- Check test isolation - are tests cleaning up state?
- Check @Transactional with rollback
- Check test order dependencies (tests should be independent)
- Check H2/in-memory DB configuration matches production DB type
- Check test data initialization

### Blocker 4: Architectural Conflict

**Issue:** Task requirements conflict with existing architecture
```
Task requires middleware auth but project uses annotation-based security
```

**What to try:**
- Review existing patterns in codebase
- Check architecture documentation
- Look for similar implementations

**If blocked:** Report to orchestrator - may need architectural decision or task revision

### Blocker 5: External Dependency Bug

**Issue:** Third-party library has known bug
```
JWT library v3.2.1 has refresh token bug - expires immediately
```

**What to try:**
- Check library changelog - is fix available in newer version?
- Search for known issues in library's issue tracker
- Try workaround if documented

**If blocked:** Report to orchestrator - may need to wait for library update or use alternative

## Blocker Report Format

```
⚠️ BLOCKED - Requires Senior Engineer

Issue: [Specific problem - NPE at UserService.kt:42, missing column, etc.]

Attempted Fixes:
- [What you tried #1]
- [What you tried #2]
- [Why attempts didn't work]

Root Cause (if known): [Your analysis]

Partial Progress: [What work you DID complete]

Context for Senior Engineer:
- Error output: [Paste error]
- Test results: [Test failures]
- Related files: [Files involved]

Requires: [What needs to happen - Senior Engineer investigation, etc.]
```

## Quick Reference

### Spring Boot Patterns

**Controller:**
```kotlin
@RestController
@RequestMapping("/api/users")
class UserController(private val userService: UserService) {

    @PostMapping
    fun createUser(@Valid @RequestBody request: CreateUserRequest): User {
        return userService.createUser(request)
    }

    @GetMapping("/{id}")
    fun getUser(@PathVariable id: UUID): User {
        return userService.findById(id)
            ?: throw NotFoundException("User not found")
    }
}
```

**Service:**
```kotlin
@Service
@Transactional
class UserService(
    private val userRepository: UserRepository,
    private val passwordEncoder: PasswordEncoder
) {
    fun createUser(request: CreateUserRequest): User {
        val user = User(
            email = request.email,
            passwordHash = passwordEncoder.encode(request.password)
        )
        return userRepository.save(user)
    }
}
```

**Repository:**
```kotlin
@Repository
interface UserRepository : JpaRepository<User, UUID> {
    fun findByEmail(email: String): User?
}
```

### Error Handling

```kotlin
@RestControllerAdvice
class GlobalExceptionHandler {

    @ExceptionHandler(NotFoundException::class)
    fun handleNotFound(ex: NotFoundException): ResponseEntity<ErrorResponse> {
        return ResponseEntity
            .status(HttpStatus.NOT_FOUND)
            .body(ErrorResponse(ex.message))
    }

    @ExceptionHandler(ValidationException::class)
    fun handleValidation(ex: ValidationException): ResponseEntity<ErrorResponse> {
        return ResponseEntity
            .status(HttpStatus.BAD_REQUEST)
            .body(ErrorResponse(ex.message))
    }
}
```

## Common Patterns to Follow

1. **Controller → Service → Repository** layering
2. **Constructor injection** over field injection
3. **@Transactional on service layer** for database operations
4. **DTO pattern** for request/response (don't expose entities)
5. **Exception handling** with @RestControllerAdvice
6. **Validation** with @Valid and constraint annotations
7. **Testing with real database** for integration tests

## What NOT to Do

❌ Don't mock repositories in integration tests
❌ Don't skip tests and mark task complete
❌ Don't expose entities directly in API responses
❌ Don't put business logic in controllers
❌ Don't forget @Transactional for database operations
❌ Don't hardcode configuration (use application.yml)

## Focus Areas

When reading task sections, prioritize:
- `requirements` - What API endpoints need to be built
- `technical-approach` - How to implement (patterns, libraries)
- `implementation` - Specific implementation details
- `testing-strategy` - How to test the implementation

## Remember

- **Run tests incrementally** - one test at a time for fast feedback
- **Use real infrastructure** - in-memory database for integration tests
- **Debug with actual output** - print what you got, don't assume
- **Report blockers promptly** - don't wait, communicate to orchestrator
- **Follow existing patterns** - check codebase for similar implementations
- **Complete test entities** - all required fields must be populated
- **Validation is mandatory** - ALL tests must pass before completion

## Additional Resources

For deeper patterns and examples, see:
- **PATTERNS.md** - Spring Security, REST API design patterns (load if needed)
- **BLOCKERS.md** - Detailed blocker scenarios with solutions (load if stuck)
- **examples.md** - Complete working examples (load if uncertain)

Overview

This skill provides practical, domain-specific guidance for implementing backend services in Kotlin with Spring Boot. It focuses on REST API design, service and repository layering, validation, testing patterns, and common blocker resolutions. Use it to deliver reliable endpoints, robust business logic, and repeatable integration tests.

How this skill works

The skill inspects task tags and implementation context to recommend patterns: Controller → Service → Repository layering, DTOs for requests/responses, and @Transactional service boundaries. It supplies validation and run commands, testing principles (favoring real in-memory DB for integration tests), and structured blocker reports to escalate issues quickly. It also outlines success criteria required before marking work complete.

When to use it

  • Implementing or updating REST endpoints (controllers, DTOs, request/response flow)
  • Writing service layer business logic and transaction boundaries
  • Integrating JPA/ORM repositories and database entities
  • Creating integration tests and CI build checks for backend code
  • Debugging runtime errors like NPEs, schema mismatches, or CI-only failures

Best practices

  • Follow Controller → Service → Repository layering and use constructor injection
  • Keep business logic out of controllers; expose DTOs, not entities
  • Mark service methods @Transactional for DB operations
  • Run tests incrementally: implement one happy path, run only that test, then add edge cases
  • Use an in-memory database for integration tests instead of mocking repositories
  • Provide clear blocker reports with attempted fixes, error output, and required next steps

Example use cases

  • Add POST /api/users endpoint with DTO validation, password hashing, and repository save
  • Write integration tests using H2 and @SpringBootTest for user creation and retrieval
  • Fix NullPointerException caused by missing Spring bean or package scanning
  • Resolve CI-only test failures by ensuring transactional rollback and independent test data
  • Document a blocker when database migration is missing a required column

FAQ

What commands should I run to validate changes locally?

Run ./gradlew test for tests, ./gradlew build to build the artifact, and ./gradlew bootRun for local runs. Use --tests to run a specific test class or method.

Should I mock repositories in integration tests?

No. Use a real in-memory database so tests exercise SQL constraints, migrations, and serialization.

What must be true before marking a task complete?

All tests must pass, build must succeed, endpoints covered by integration tests, error handling implemented, and code should follow existing project conventions.