Services Documentation
This document provides comprehensive documentation for all services in the Yappa Knowledge Hub backend.
Overview
Services contain the core business logic and external API integrations. The backend has two main service categories:
- Notion Services - Integration with Notion API
- Application Services - Core business logic
Notion Services
Located in src/Service/Notion/
NotionClient
File: src/Service/Notion/NotionClient.php
Description: Low-level HTTP client for Notion API. Handles authentication, request/response formatting, and error handling.
Constructor Parameters:
HttpClientInterface $httpClient- Symfony HTTP clientstring $apiKey- Notion API keystring $version- Notion API version (default: '2022-06-28')
Key Methods:
createPage(string $databaseId, array $properties): array
Creates a new page in a Notion database.
$properties = [
'Title' => ['title' => [['text' => ['content' => 'My Page']]]],
'Status' => ['status' => ['name' => 'In progress']]
];
$page = $notionClient->createPage($databaseId, $properties);updatePage(string $pageId, array $properties): array
Updates an existing Notion page.
$properties = [
'Status' => ['status' => ['name' => 'Done']]
];
$page = $notionClient->updatePage($pageId, $properties);getPage(string $pageId): array
Retrieves a single page by ID.
$page = $notionClient->getPage($pageId);queryDatabase(string $databaseId, array $filter, array $sorts): array
Queries a database with filters and sorting.
$filter = [
'property' => 'Status',
'status' => ['equals' => 'Done']
];
$sorts = [
['property' => 'Created', 'direction' => 'descending']
];
$results = $notionClient->queryDatabase($databaseId, $filter, $sorts);queryDatabaseWithPagination(string $databaseId, array $filter, array $sorts): array
Queries a database and automatically handles pagination to fetch all results.
$results = $notionClient->queryDatabaseWithPagination($databaseId, [], []);
// Returns all pages, not just first 100searchPages(string $query, array $filter): array
Searches across all accessible pages.
$results = $notionClient->searchPages('symfony', [
'property' => 'object',
'value' => 'page'
]);createPageWithIcon(string $databaseId, array $properties, ?array $icon): array
Creates a page with an icon.
$icon = ['type' => 'emoji', 'emoji' => ''];
$page = $notionClient->createPageWithIcon($databaseId, $properties, $icon);updatePageWithIcon(string $pageId, array $properties, ?array $icon): array
Updates a page including its icon.
NotionKnowledgeService
File: src/Service/Notion/NotionKnowledgeService.php
Description: High-level service for knowledge item operations in Notion. Handles property mapping and business logic.
Constructor Parameters:
NotionClient $client- Notion API clientstring $knowledgeDatabaseId- Knowledge database ID
Key Methods:
create(array $data): array
Creates a knowledge item in Notion.
$data = [
'title' => 'My Knowledge Item',
'content' => 'Detailed content...',
'tags' => ['php', 'symfony'],
'categoryId' => 'notion-category-id',
'status' => 'Not started',
'sourceUrl' => 'https://example.com',
'slackUserId' => 'U12345',
'slackMessageTs' => '1234567890.123456',
'slackChannelId' => 'C12345',
'aiSummary' => 'AI-generated summary...'
];
$page = $knowledgeService->create($data);Supported Properties:
title(string, required) - Page titlecontent(string) - Rich text contenttags(array) - Multi-select tagscategoryId(string) - Relation to categorystatus(string) - Status propertysourceUrl(string) - URL propertyslackUserId(string) - Slack user IDslackMessageTs(string) - Slack message timestampslackChannelId(string) - Slack channel IDaiSummary(string) - AI-generated summary
update(string $pageId, array $data): array
Updates a knowledge item.
$data = [
'title' => 'Updated Title',
'status' => 'Done',
'tags' => ['updated', 'tags']
];
$page = $knowledgeService->update($pageId, $data);get(string $pageId): array
Retrieves a knowledge item.
$page = $knowledgeService->get($pageId);listAll(): array
Lists all knowledge items (with pagination).
$pages = $knowledgeService->listAll();
// Returns all pages, not just first 100queryByCategory(string $categoryId, array $additionalFilters = []): array
Queries knowledge items by category.
$pages = $knowledgeService->queryByCategory($categoryId);search(string $query): array
Searches knowledge items.
$pages = $knowledgeService->search('symfony deployment');mapToArray(array $page): array
Maps a Notion page to a PHP array.
$page = $notionClient->getPage($pageId);
$knowledge = $knowledgeService->mapToArray($page);
// Returns:
// [
// 'id' => 'notion-page-id',
// 'notionId' => 'notion-page-id',
// 'notionUrl' => 'https://notion.so/...',
// 'title' => 'Page Title',
// 'content' => 'Content...',
// 'tags' => ['tag1', 'tag2'],
// 'targetGroups' => ['group1'],
// 'status' => 'Done',
// 'sourceUrl' => 'https://...',
// 'aiSummary' => 'Summary...',
// 'created' => '2026-02-19T10:30:00.000Z',
// 'lastEdited' => '2026-02-19T11:00:00.000Z',
// 'categoryId' => ['category-id']
// ]NotionCategoryService
File: src/Service/Notion/NotionCategoryService.php
Description: Manages categories in Notion with icon support and emoji conversion.
Constructor Parameters:
NotionClient $client- Notion API clientstring $categoryDatabaseId- Category database ID
Key Methods:
create(array $data): array
Creates a category in Notion.
$data = [
'name' => 'Development',
'description' => 'Development resources',
'icon' => ':rocket:', // Slack emoji or Unicode
'defaultTargetGroups' => ['developers', 'devops'],
'color' => 'blue',
'isActive' => true,
'sortOrder' => 1,
'digestFrequency' => 'weekly'
];
$page = $categoryService->create($data);Supported Properties:
name(string, required) - Category namedescription(string) - Category descriptionicon(string) - Emoji icon (Slack format or Unicode)defaultTargetGroups(array) - Default target groupscolor(string) - Category colorisActive(boolean) - Active statussortOrder(integer) - Sort orderdigestFrequency(string) - Digest frequency
update(string $pageId, array $data): array
Updates a category.
$data = [
'name' => 'Updated Name',
'icon' => '',
'defaultTargetGroups' => ['developers', 'designers']
];
$page = $categoryService->update($pageId, $data);get(string $pageId): array
Retrieves a category.
listAll(): array
Lists all categories (with pagination).
$categories = $categoryService->listAll();mapToArray(array $page): array
Maps a Notion category page to a PHP array.
$category = $categoryService->mapToArray($page);
// Returns:
// [
// 'id' => 'notion-page-id',
// 'name' => 'Development',
// 'description' => 'Description...',
// 'icon' => '',
// 'defaultTargetGroups' => ['developers'],
// 'color' => 'blue',
// 'isActive' => true,
// 'sortOrder' => 1,
// 'digestFrequency' => 'weekly',
// 'lastDigestAt' => '2026-02-15T10:00:00.000Z',
// 'created' => '2026-01-01T00:00:00.000Z',
// 'updated' => '2026-02-19T10:30:00.000Z'
// ]Emoji Conversion: The service automatically converts Slack emoji format (:rocket:) to Unicode emoji () for Notion. Supports 60+ common emojis.
NotionSyncService
File: src/Service/Notion/NotionSyncService.php
Description: Bidirectional synchronization between SQLite and Notion. Implements the dual-storage pattern.
Constructor Parameters:
NotionClient $notionClient- Notion API clientEntityManagerInterface $entityManager- Doctrine entity managerLoggerInterface $logger- Loggerstring $knowledgeDatabaseId- Knowledge database IDstring $categoriesDatabaseId- Categories database ID
Key Methods:
createKnowledge(array $data): array
Creates knowledge in both SQLite and Notion.
$data = [
'title' => 'My Knowledge',
'content' => 'Content...',
'tags' => ['tag1', 'tag2'],
'categoryId' => 'notion-category-id',
'targetGroups' => ['developers'],
'status' => 'Not started',
'url' => 'https://example.com',
'userId' => 'U12345',
'sourceMessage' => ['ts' => '123', 'channel' => 'C123']
];
$result = $syncService->createKnowledge($data);
// Returns:
// [
// 'sqlite_id' => 1,
// 'notion_id' => 'notion-page-id',
// 'notion_url' => 'https://notion.so/...'
// ]Process:
- Creates entity in SQLite
- Creates page in Notion
- Links Notion ID to SQLite entity
- Returns both IDs
searchKnowledge(string $query, array $options = []): array
Searches in both SQLite and Notion.
$results = $syncService->searchKnowledge('symfony');
// Returns merged results from both sourcesgetKnowledge(string $id): ?array
Gets knowledge from SQLite or Notion.
$knowledge = $syncService->getKnowledge($id);
// Tries SQLite first, falls back to NotionsyncToNotion(int $limit = 100): array
Syncs existing SQLite knowledge to Notion.
$result = $syncService->syncToNotion(50);
// Returns:
// [
// 'synced' => 45,
// 'failed' => 5,
// 'total' => 50
// ]Use Case: Bulk sync of existing SQLite data to Notion.
NotionPropertyMapper
File: src/Service/Notion/NotionPropertyMapper.php
Description: Static utility class for mapping between Notion property formats and PHP values.
Static Methods:
Property Creators (PHP Notion)
// Title property
NotionPropertyMapper::title('My Title');
// Returns: ['title' => [['text' => ['content' => 'My Title']]]]
// Rich text property
NotionPropertyMapper::richText('Content...');
// Returns: ['rich_text' => [['text' => ['content' => 'Content...']]]]
// Multi-select property
NotionPropertyMapper::multiSelect(['tag1', 'tag2']);
// Returns: ['multi_select' => [['name' => 'tag1'], ['name' => 'tag2']]]
// Select property
NotionPropertyMapper::select('option');
// Returns: ['select' => ['name' => 'option']]
// Status property
NotionPropertyMapper::status('Done');
// Returns: ['status' => ['name' => 'Done']]
// Checkbox property
NotionPropertyMapper::checkbox(true);
// Returns: ['checkbox' => true]
// Number property
NotionPropertyMapper::number(42);
// Returns: ['number' => 42]
// URL property
NotionPropertyMapper::url('https://example.com');
// Returns: ['url' => 'https://example.com']
// Date property
NotionPropertyMapper::date('2026-02-19');
// Returns: ['date' => ['start' => '2026-02-19']]
// Relation property
NotionPropertyMapper::relation(['page-id-1', 'page-id-2']);
// Returns: ['relation' => [['id' => 'page-id-1'], ['id' => 'page-id-2']]]Property Extractors (Notion PHP)
// Extract title
$title = NotionPropertyMapper::extractTitle($property);
// Extract rich text
$text = NotionPropertyMapper::extractRichText($property);
// Extract multi-select
$tags = NotionPropertyMapper::extractMultiSelect($property);
// Returns: ['tag1', 'tag2']
// Extract select
$option = NotionPropertyMapper::extractSelect($property);
// Extract status
$status = NotionPropertyMapper::extractStatus($property);
// Extract checkbox
$checked = NotionPropertyMapper::extractCheckbox($property);
// Extract number
$number = NotionPropertyMapper::extractNumber($property);
// Extract URL
$url = NotionPropertyMapper::extractUrl($property);
// Extract date
$date = NotionPropertyMapper::extractDate($property);
// Extract relation
$ids = NotionPropertyMapper::extractRelation($property);
// Returns: ['page-id-1', 'page-id-2']NotionDatabaseService
File: src/Service/Notion/NotionDatabaseService.php
Description: Database-level operations in Notion.
(Implementation details would be added based on actual code)
NotionDigestService
File: src/Service/Notion/NotionDigestService.php
Description: Digest operations in Notion.
(Implementation details would be added based on actual code)
NotionException
File: src/Service/Notion/NotionException.php
Description: Custom exception for Notion API errors.
throw new NotionException('Failed to create page: ' . $error);Application Services
Located in src/Service/
OpenAiService
File: src/Service/OpenAiService.php
Description: OpenAI API integration for generating AI completions with retry logic and mock mode.
Constructor Parameters:
HttpClientInterface $httpClient- HTTP clientLoggerInterface $logger- Loggerstring $apiKey- OpenAI API keystring $model- Model name (default: 'gpt-4')bool $mockMode- Enable mock mode (default: false)
Key Methods:
generateCompletion(string $prompt, array $options = []): string
Generates an AI completion.
$prompt = "Summarize this article for developers: ...";
$options = [
'temperature' => 0.7,
'max_tokens' => 500
];
$summary = $openAiService->generateCompletion($prompt, $options);Options:
temperature(float, default: 0.7) - Creativity level (0-1)max_tokens(int, default: 500) - Maximum response length
Features:
- Automatic Retries: Retries up to 3 times with exponential backoff
- Timeout: 30-second timeout per request
- Error Handling: Logs warnings and throws exception after max retries
- Mock Mode: Returns predefined responses for testing
Mock Mode: When mockMode is enabled, returns realistic mock summaries based on keywords in the prompt:
- Detects target groups (technical, marketing, management, etc.)
- Returns appropriate mock content
- No API calls made
- Perfect for development/testing
// Enable mock mode
$service = new OpenAiService($httpClient, $logger, '', 'gpt-4', true);
$summary = $service->generateCompletion($prompt);
// Returns mock summary, no API callisMockMode(): bool
Checks if mock mode is enabled.
if ($openAiService->isMockMode()) {
echo "Using mock responses";
}getModel(): string
Gets the configured model.
$model = $openAiService->getModel(); // 'gpt-4'SummaryService
File: src/Service/SummaryService.php
Description: Manages summary generation and storage.
(Implementation details would be added based on actual code)
TargetGroupService
File: src/Service/TargetGroupService.php
Description: Manages target groups for knowledge items.
(Implementation details would be added based on actual code)
SlackHomeRefreshService
File: src/Service/SlackHomeRefreshService.php
Description: Refreshes Slack home tab when knowledge items change.
(Implementation details would be added based on actual code)
Service Configuration
Services are configured in config/services.yaml:
services:
# Notion services
App\Service\Notion\NotionClient:
arguments:
$apiKey: '%env(NOTION_API_KEY)%'
$version: '2022-06-28'
App\Service\Notion\NotionKnowledgeService:
arguments:
$knowledgeDatabaseId: '%env(NOTION_KNOWLEDGE_DATABASE_ID)%'
App\Service\Notion\NotionCategoryService:
arguments:
$categoryDatabaseId: '%env(NOTION_CATEGORIES_DATABASE_ID)%'
App\Service\Notion\NotionSyncService:
arguments:
$knowledgeDatabaseId: '%env(NOTION_KNOWLEDGE_DATABASE_ID)%'
$categoriesDatabaseId: '%env(NOTION_CATEGORIES_DATABASE_ID)%'
# OpenAI service
App\Service\OpenAiService:
arguments:
$apiKey: '%env(OPENAI_API_KEY)%'
$model: '%env(OPENAI_MODEL)%'
$mockMode: '%env(bool:OPENAI_MOCK_MODE)%'Environment Variables
Required environment variables for services:
# Notion API
NOTION_API_KEY=secret_xxx
NOTION_KNOWLEDGE_DATABASE_ID=xxx
NOTION_CATEGORIES_DATABASE_ID=xxx
# OpenAI API
OPENAI_API_KEY=sk-xxx
OPENAI_MODEL=gpt-4
OPENAI_MOCK_MODE=falseError Handling
All services implement proper error handling:
- Logging: Errors are logged with context
- Exceptions: Throw meaningful exceptions
- Retries: Automatic retries for transient failures (OpenAI)
- Fallbacks: Graceful degradation (sync service)
Testing Services
Services can be tested using PHPUnit:
use App\Service\OpenAiService;
use PHPUnit\Framework\TestCase;
class OpenAiServiceTest extends TestCase
{
public function testMockMode(): void
{
$service = new OpenAiService(
$this->createMock(HttpClientInterface::class),
$this->createMock(LoggerInterface::class),
'',
'gpt-4',
true // mock mode
);
$result = $service->generateCompletion('Test prompt');
$this->assertNotEmpty($result);
}
}