148 lines
5.8 KiB
Markdown
148 lines
5.8 KiB
Markdown
# Condado Newsletter Bot
|
|
|
|
A newsletter bot built with **Kotlin** and **Spring Boot**. This file gives Claude persistent
|
|
instructions and context about the project so every session starts with the right knowledge.
|
|
|
|
---
|
|
|
|
## Project Overview
|
|
|
|
- **Language:** Kotlin (JVM)
|
|
- **Framework:** Spring Boot 3.x
|
|
- **Purpose:** Automate the creation, management, and delivery of newsletters
|
|
- **Architecture:** REST API backend with scheduled jobs for sending newsletters
|
|
|
|
---
|
|
|
|
## Tech Stack
|
|
|
|
| Layer | Technology |
|
|
|---------------|-----------------------------------|
|
|
| Language | Kotlin |
|
|
| Framework | Spring Boot 3.x |
|
|
| Build Tool | Gradle (Kotlin DSL - `build.gradle.kts`) |
|
|
| Database | PostgreSQL (via Spring Data JPA) |
|
|
| Email | Spring Mail (SMTP / JavaMailSender) |
|
|
| Scheduler | Spring `@Scheduled` tasks |
|
|
| Testing | JUnit 5 + MockK |
|
|
| Docs | Springdoc OpenAPI (Swagger UI) |
|
|
|
|
---
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
src/
|
|
├── main/
|
|
│ ├── kotlin/com/condado/newsletter/
|
|
│ │ ├── CondadoNewsletterApplication.kt # App entry point
|
|
│ │ ├── config/ # Spring configuration classes
|
|
│ │ ├── controller/ # REST controllers
|
|
│ │ ├── service/ # Business logic
|
|
│ │ ├── repository/ # Spring Data JPA repositories
|
|
│ │ ├── model/ # JPA entities
|
|
│ │ ├── dto/ # Data Transfer Objects
|
|
│ │ └── scheduler/ # Scheduled tasks
|
|
│ └── resources/
|
|
│ ├── application.yml # Main config
|
|
│ ├── application-dev.yml # Dev profile config
|
|
│ └── templates/ # Email HTML templates (Thymeleaf)
|
|
└── test/
|
|
└── kotlin/com/condado/newsletter/ # Tests mirror main structure
|
|
```
|
|
|
|
---
|
|
|
|
## Build & Run Commands
|
|
|
|
```bash
|
|
# Build the project
|
|
./gradlew build
|
|
|
|
# Run the application (dev profile)
|
|
./gradlew bootRun --args='--spring.profiles.active=dev'
|
|
|
|
# Run all tests
|
|
./gradlew test
|
|
|
|
# Run a specific test class
|
|
./gradlew test --tests "com.condado.newsletter.service.NewsletterServiceTest"
|
|
|
|
# Generate OpenAPI docs (served at /swagger-ui.html when running)
|
|
./gradlew bootRun
|
|
```
|
|
|
|
---
|
|
|
|
## Coding Standards
|
|
|
|
- Use **Kotlin idiomatic** style: data classes, extension functions, and null-safety operators.
|
|
- Prefer `val` over `var` wherever possible.
|
|
- Use **constructor injection** for dependencies (never field injection with `@Autowired`).
|
|
- All DTOs must be **data classes** with validation annotations (`javax.validation`).
|
|
- Controller methods must return `ResponseEntity<T>` with explicit HTTP status codes.
|
|
- Services must be annotated with `@Service` and **never** depend on controllers.
|
|
- Repositories must extend `JpaRepository<Entity, IdType>`.
|
|
- Use `@Transactional` on service methods that modify data.
|
|
- All public functions must have **KDoc** comments.
|
|
- Use **`snake_case`** for database columns and **`camelCase`** for Kotlin properties.
|
|
- Keep controllers thin — business logic belongs in services.
|
|
|
|
---
|
|
|
|
## Naming Conventions
|
|
|
|
| Artifact | Convention | Example |
|
|
|----------------|-----------------------------------|-----------------------------|
|
|
| Classes | PascalCase | `NewsletterService` |
|
|
| Functions | camelCase | `sendNewsletter()` |
|
|
| Variables | camelCase | `subscriberList` |
|
|
| Constants | SCREAMING_SNAKE_CASE | `MAX_RETRIES` |
|
|
| DB tables | snake_case (plural) | `newsletter_subscribers` |
|
|
| REST endpoints | kebab-case | `/api/v1/newsletter-issues` |
|
|
| Packages | lowercase | `com.condado.newsletter` |
|
|
|
|
---
|
|
|
|
## Testing Guidelines
|
|
|
|
- Every service class must have a corresponding unit test class.
|
|
- Use **MockK** for mocking (not Mockito).
|
|
- Integration tests use `@SpringBootTest` and an **H2 in-memory** database.
|
|
- Test method names follow the pattern: `should_[expectedBehavior]_when_[condition]`.
|
|
- Minimum 80% code coverage for service classes.
|
|
|
|
---
|
|
|
|
## Environment Variables
|
|
|
|
| Variable | Description |
|
|
|-----------------------|-----------------------------------|
|
|
| `SPRING_DATASOURCE_URL` | PostgreSQL connection URL |
|
|
| `SPRING_DATASOURCE_USERNAME` | DB username |
|
|
| `SPRING_DATASOURCE_PASSWORD` | DB password |
|
|
| `MAIL_HOST` | SMTP host |
|
|
| `MAIL_PORT` | SMTP port |
|
|
| `MAIL_USERNAME` | SMTP username |
|
|
| `MAIL_PASSWORD` | SMTP password |
|
|
|
|
> ⚠️ Never hardcode credentials. Always use environment variables or a `.env` file (gitignored).
|
|
|
|
---
|
|
|
|
## Key Domain Concepts
|
|
|
|
- **Subscriber:** A person who opted in to receive newsletters.
|
|
- **NewsletterIssue:** A single newsletter edition with a subject and HTML body.
|
|
- **Campaign:** A scheduled or triggered dispatch of a `NewsletterIssue` to a group of subscribers.
|
|
- **SendLog:** A record of each email send attempt (status: PENDING / SENT / FAILED).
|
|
|
|
---
|
|
|
|
## Git Workflow
|
|
|
|
- Branch naming: `feature/<short-description>`, `fix/<short-description>`, `chore/<short-description>`
|
|
- Commit messages follow [Conventional Commits](https://www.conventionalcommits.org/): `feat:`, `fix:`, `chore:`, `docs:`, `test:`
|
|
- PRs require at least one passing CI check before merging.
|
|
- Never commit directly to `main`.
|