Notion Integration
YapHub maintains a bidirectional sync with Notion, using it as a secondary data store and collaboration layer. Every action in Slack is automatically reflected in Notion, and changes made in Notion can be pulled back into the system.
Notion Databases
The system connects to four Notion databases:
| Database | Purpose | Sync Direction |
|---|---|---|
| Knowledge | Knowledge items with content, tags, AI summaries | Bidirectional |
| Categories | Thematic lists with settings and target groups | Bidirectional |
| Digests | Generated digest reports with statistics | Local → Notion |
| Subscriptions | User category subscriptions | Bidirectional |
Sync Architecture
Outbound Sync (Slack → Notion)
Triggered immediately when entities are created or updated:
- Knowledge — A Notion page is created with properties for title, content, tags, status, URL, AI summary, highlight, and category relation
- Categories — Properties include name, description, icon, target groups, digest settings
- Digests — Full Markdown content is embedded as page content (not just properties), plus statistics and linked knowledge items
- Subscriptions — User ID, category, active status, and timestamps
The NotionMarkdownContentService handles embedding full digest content (Markdown) into Notion pages via the Notion API's block children endpoints.
Inbound Sync (Notion → Local)
Triggered via API endpoints, typically from an admin action or scheduled job:
POST /api/notion/sync/from-notion— Pulls knowledge items from Notion, creating or updating local recordsPOST /api/notion/sync/categories-from-notion— Pulls categories including target groupsPOST /api/notion/sync/to-notion— Pushes local knowledge items to Notion (bulk)
Inbound sync includes a force parameter to overwrite local changes with Notion data.
Notion Service Layer
The Notion integration is built on a layered architecture:
| Component | Responsibility |
|---|---|
NotionSyncService | Coordinates bidirectional sync for all entity types |
NotionRepositoryManager | Resolves the correct repository for a given entity class and ID format |
NotionKnowledgeRepository | CRUD operations on the Notion Knowledge database |
NotionCategoryRepository | CRUD operations on the Notion Categories database |
NotionDigestRepository | CRUD operations on the Notion Digests database |
NotionSubscriptionRepository | CRUD operations on the Notion Subscriptions database |
NotionPageBuilder | Fluent builder for constructing Notion page properties |
NotionPropertyExtractor | Reads and extracts typed values from Notion page properties |
NotionMarkdownContentService | Embeds Markdown content as Notion blocks via HTTP API |
Dual-ID Resolution
The system maintains two ID systems:
- Local ID — Auto-incrementing integer (SQLite primary key)
- Notion ID — UUID string (Notion page ID)
The DatabaseResolverInterface implemented by each repository handles this duality: it can look up entities by either local ID or Notion UUID, routing to the correct repository via NotionRepositoryManager.
Property Mapping
Notion properties are mapped to and from local entities using dedicated mappers:
| Mapper | Handles |
|---|---|
KnowledgeMapper | Knowledge entity ↔ Notion page ↔ KnowledgeDTO |
CategoryMapper | Category entity ↔ Notion page |
DigestMapper | Digest entity ↔ Notion page |
SubscriptionMapper | Subscription entity ↔ Notion page |
Each mapper handles type conversions (e.g., Notion rich text → PHP string, Notion multi-select → PHP array, Notion date → DateTimeImmutable).
Offline Resilience
The system uses SQLite as its primary database. Notion is treated as a sync target, not the source of truth. If Notion is unavailable:
- Knowledge items, categories, digests, and subscriptions are still created locally
- Sync failures are logged but don't block user operations
- Data is synced to Notion when connectivity is restored