Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.DS_Store
.vscode/
.env
log.txt
out/
*.swp
Expand All @@ -11,4 +12,11 @@ debug/

# Composer gitignore
composer.phar
/vendor/
/vendor/

# PHPUnit
.phpunit.result.cache
.phpunit.cache/

# omc
.omc/
113 changes: 113 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# SOLAPI PHP SDK

**Generated:** 2026-01-21
**Commit:** b68825d
**Branch:** master

## OVERVIEW

PHP SDK for SOLAPI messaging API (SMS, LMS, MMS, Kakao Alimtalk, Voice, Fax) targeting Korean telecom. Zero external dependencies, PHP 7.1+.

## STRUCTURE

```
solapi-php/
├── src/
│ ├── Services/ # Entry point (SolapiMessageService)
│ ├── Libraries/ # HTTP client, auth, utilities
│ ├── Models/
│ │ ├── Request/ # API request DTOs (7 files)
│ │ ├── Response/ # API response DTOs (17 files)
│ │ ├── Kakao/ # Kakao message options
│ │ ├── Voice/ # Voice message options
│ │ └── Fax/ # Fax message options
│ └── Exceptions/ # Custom exceptions (4 files)
├── composer.json # PSR-4: Nurigo\Solapi\ → src/
└── README.md
```

## WHERE TO LOOK

| Task | Location | Notes |
|------|----------|-------|
| Send messages | `Services/SolapiMessageService.php` | Main entry point, all public methods |
| Build message | `Models/Message.php` | Fluent builder, extends BaseMessage |
| HTTP requests | `Libraries/Fetcher.php` | Singleton, CURL-based |
| Auth header | `Libraries/Authenticator.php` | HMAC-SHA256, static method |
| Kakao options | `Models/Kakao/KakaoOption.php` | pfId, templateId, buttons, bms |
| Voice options | `Models/Voice/VoiceOption.php` | voiceType, headerMessage, tailMessage |
| Error handling | `Exceptions/` | BaseException, CurlException, MessageNotReceivedException |
| Request params | `Models/Request/` | SendRequest, GetMessagesRequest, etc. |
| Response parsing | `Models/Response/` | SendResponse, GroupMessageResponse, etc. |

## CODE MAP

**Entry Point:**
```php
$service = new SolapiMessageService($apiKey, $apiSecret);
$response = $service->send($message);
```

**Call Flow:**
```
SolapiMessageService → Fetcher (singleton) → Authenticator (static)
→ CURL → api.solapi.com
→ Response DTOs
```

**Key Classes:**
| Class | Type | Role |
|-------|------|------|
| `SolapiMessageService` | Service | Primary API (send, uploadFile, getMessages, getGroups, getBalance) |
| `Message` | Model | Message builder with fluent setters |
| `Fetcher` | Library | HTTP client singleton, handles all API requests |
| `Authenticator` | Library | Generates HMAC-SHA256 auth headers |
| `NullEliminator` | Library | Removes null values before JSON serialization |

## CONVENTIONS

**Namespace:** `Nurigo\Solapi\*` (PSR-4 from `src/`)

**Patterns:**
- Fluent builder: `$msg->setTo("...")->setFrom("...")->setText("...")`
- Singleton: `Fetcher::getInstance($key, $secret)`
- Public properties with getters/setters on models
- Korean PHPDoc comments (domain-specific)

**Type Safety:**
- Full type hints on method params/returns
- PHPDoc `@var`, `@param`, `@return`, `@throws` annotations

**Tidy First (Kent Beck):**
- Separate structural and behavioral changes into distinct commits
- Tidy related code before making feature changes
- Guard clauses, helper variables/functions, code proximity, symmetry normalization, delete unused code

## ANTI-PATTERNS

- **Avoid catch-all nulls:** Many get* methods return `null` on any exception — check response validity
- **Singleton state:** Fetcher singleton retains credentials — don't mix different API keys in same process
- **No interfaces:** Service/Fetcher have no contracts — mocking requires concrete class extension
- **SSL verification disabled:** `CURLOPT_SSL_VERIFYPEER = false` in Fetcher

## UNIQUE STYLES

- **Korean comments:** PHPDoc descriptions in Korean (수신번호, 발신번호, 메시지 내용)
- **Default country:** `"82"` (Korea) hardcoded in BaseMessage
- **Timezone:** `Asia/Seoul` set in Authenticator

## COMMANDS

```bash
# Install
composer require solapi/sdk

# No local tests — see solapi-php-examples repo
```

## NOTES

- **Examples:** External repo at `github.com/solapi/solapi-php-examples`
- **API docs:** `developers.solapi.com`
- **PHP requirement:** 7.1+ (ext-curl, ext-json required)
- **TODO in README:** Missing documentation link (line 19)
86 changes: 86 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

SOLAPI PHP SDK - A zero-dependency messaging SDK for Korean telecommunications (SMS, LMS, MMS, Kakao Alimtalk, Voice, Fax). Version 5.0.6, requires PHP 7.1+ with curl and json extensions.

## Commands

```bash
# Install dependencies (none required, autoloader only)
composer install

# There are no local tests - see https://github.com/solapi/solapi-php-examples for usage examples
```

## Architecture

**Entry Point:** `SolapiMessageService` in `src/Services/` - all public API methods

**Call Flow:**
```
SolapiMessageService → Fetcher (singleton) → Authenticator (static) → CURL → api.solapi.com
```

**Key Classes:**
- `SolapiMessageService` - Primary API: send(), uploadFile(), getMessages(), getGroups(), getBalance()
- `Message` (`Models/Message.php`) - Fluent builder for message construction
- `Fetcher` (`Libraries/Fetcher.php`) - Singleton HTTP client
- `Authenticator` (`Libraries/Authenticator.php`) - HMAC-SHA256 auth header generation

**Models Structure:**
- `Models/Request/` - 7 request DTOs (SendRequest, GetMessagesRequest, etc.)
- `Models/Response/` - 17 response DTOs (SendResponse, GroupMessageResponse, etc.)
- `Models/Kakao/` - Kakao message options (pfId, templateId, buttons)
- `Models/Voice/` - Voice message options
- `Models/Fax/` - Fax message options

## Code Conventions

**Namespace:** `Nurigo\Solapi\*` (PSR-4 autoload from `src/`)

**Patterns:**
- Fluent builder: `$msg->setTo("...")->setFrom("...")->setText("...")`
- Singleton: `Fetcher::getInstance($apiKey, $apiSecret)`
- Public properties with getters/setters on all model classes
- Full type hints on method params/returns with PHPDoc annotations

**Language Notes:**
- PHPDoc comments are in Korean (수신번호, 발신번호, 메시지 내용)
- Default country code is "82" (Korea) in BaseMessage
- Timezone hardcoded to Asia/Seoul in Authenticator

## Tidy First Principles

Follow Kent Beck's "Tidy First" principles when making code changes:

**Core Principles:**
- **Separate Structure from Behavior**: Separate structural changes (tidying) and behavioral changes (features) into distinct commits
- **Tidy First**: Tidy related code before making feature changes to improve changeability
- **Small Steps**: Keep tidying work completable within minutes to hours

**Practical Techniques:**
- Use guard clauses for early returns to eliminate nested if statements
- Use helper variables/functions to clarify complex expressions
- Keep related code physically close together
- Express identical logic in identical ways (normalize symmetry)
- Delete unused code immediately

**When to Apply:**
- Before adding new features, tidy the affected area
- Before fixing bugs, clarify related code
- During code review, identify tidying opportunities

## Important Behaviors

- **Singleton State:** Fetcher singleton retains credentials - don't mix different API keys in the same process
- **Null Returns:** Many get* methods return `null` on any exception instead of throwing - always check response validity
- **No Interfaces:** Service/Fetcher lack contracts - mocking requires concrete class extension
- **SSL Verification:** Disabled in Fetcher (`CURLOPT_SSL_VERIFYPEER = false`)

## External Resources

- API Documentation: https://developers.solapi.com
- Examples Repository: https://github.com/solapi/solapi-php-examples
22 changes: 19 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
{
"name": "solapi/sdk",
"description": "SOLAPI SDK for PHP",
"version": "5.0.6",
"version": "5.1.0",
"type": "library",
"license": "MIT",
"autoload": {
"psr-4": {
"Nurigo\\Solapi\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Nurigo\\Solapi\\Tests\\": "tests/"
}
},
"repositories": [
{
"type": "vcs",
Expand Down Expand Up @@ -41,7 +46,18 @@
"homepage": "https://solapi.com",
"require": {
"php": ">=7.1",
"ext-curl": "*",
"ext-json": "*"
"ext-json": "*",
"psr/http-client": "^1.0",
"psr/http-message": "^1.0 || ^2.0",
"nyholm/psr7": "^1.5"
},
Comment on lines 47 to +53

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This update changes the underlying HTTP transport from cURL to a file_get_contents-based stream wrapper. This introduces a new runtime requirement: allow_url_fopen must be enabled in php.ini. This is a significant change, as this setting is often disabled on production or shared hosting environments for security reasons. If allow_url_fopen is disabled, the SDK will fail. This should be clearly documented as a requirement or potential breaking change in the README or migration guide.

"require-dev": {
"phpunit/phpunit": "^9.5"
},
"scripts": {
"test": "phpunit",
"test:unit": "phpunit --testsuite=Unit",
"test:e2e": "phpunit --testsuite=E2E",
"test:coverage": "phpunit --coverage-text"
}
}
Loading