Skip to content

Yappa Knowledge Hub - Architecture & Database Design

Version: 1.0 | Date: 2026-02-15


System Overview

Slack Bot (Node.js/Bolt)  ─HTTP─►  Symfony Backend (PHP 8.2)  ─API─►  Notion (Cloud DB)

                                          ├─►  OpenAI API (GPT-4)
                                          └─►  Slack API (Send DMs)

Technology Stack

LayerTechnologyRole
InputSlack Bot (Node.js, @slack/bolt)UI — commands, modals, shortcuts, reactions
InputNotion UIDirect web access to databases
ProcessingSymfony 7.2 (PHP)REST API, business logic, AI orchestration
StorageNotion DatabasesSingle source of truth (3 databases)
AIOpenAI GPT-4Summary generation per target group
CacheRedis (optional)Performance layer, 5-minute TTL

High-Level Architecture


Notion Database Schema

Database 1: Knowledge Items

ID: 306e292a15d58004a8cbc222dcd48bb2

PropertyTypeRequiredDescription
TitletitleKnowledge item name
Contentrich_textFull content (up to 2000 chars)
StatusstatusDraft → Review → Published → Archived/Outdated
Tagsmulti_selectKeywords for filtering
CategoriesrelationLink to Categories DB
PriorityselectHigh / Medium / Low
Target Groupsmulti_selectAudience segments
Source TypeselectSlack Message / Manual / File / URL
Source URLurlOriginal link
AuthorpeopleWho created it
AI Summaryrich_textGenerated per target group
Slack User IDrich_textTraceability
Slack Message TSrich_textMessage timestamp
Slack Channel IDrich_textChannel identifier
View CountnumberAccess tracking
Last RevieweddateContent freshness
AttachmentsfilesSupporting files
Createdcreated_timeAuto
Last Editedlast_edited_timeAuto

Database 2: Categories (Thematic Lists)

ID: 306e292a15d5805dae13e64bed8519c5

PropertyTypeRequiredDescription
NametitleCategory name
Descriptionrich_textPurpose and scope
Iconrich_textEmoji icon
Default Target Groupsmulti_selectAuto-assigned groups for new items
SubscriberspeopleUsers who receive digests
Digest FrequencyselectDaily / Weekly / Bi-weekly / Monthly / On-demand
Digest DayselectDay of week for delivery
ActivecheckboxWhether category is in use
Knowledge CountrollupAutoItems in this category
Last DigestdateWhen last digest was sent
Createdcreated_timeAuto

Database 3: Digest Reports

ID: 306e292a15d580d7a0f6fe8421baff10

PropertyTypeRequiredDescription
TitletitleDigest name
CategoryrelationLink to Categories DB
Period StartdateReport period start
Period EnddateReport period end
Items CountnumberItems included
Target Groupsmulti_selectAudience
Generated BypeopleWho requested
StatusstatusGenerating / Sent / Failed
Slack SentcheckboxSent to Slack DMs
Recipientsrich_textSlack user IDs
Generated Atcreated_timeAuto

API Endpoints

POST   /api/knowledge              Create knowledge item
GET    /api/knowledge              List knowledge items
GET    /api/knowledge/{id}         Get single item
PUT    /api/knowledge/{id}         Update item
DELETE /api/knowledge/{id}         Delete item
POST   /api/knowledge/search       Search knowledge

POST   /api/categories             Create category
GET    /api/categories             List categories
GET    /api/categories/{id}        Get category
PUT    /api/categories/{id}        Update category
DELETE /api/categories/{id}        Delete category

POST   /api/digests/generate       Generate digest report
GET    /api/digests                List digests
GET    /api/digests/{id}           Get digest
POST   /api/digests/{id}/send      Send digest to Slack

POST   /api/notion/sync            Sync data to Notion
GET    /api/notion/sync/status     Check sync status

Data Flow Patterns

Add Knowledge (most common path, ~3-5s)

Generate Digest (~5-10s)

Search Knowledge (~1-2s)

User → Slack → Symfony → Notion Search API → Format → Slack Response

Service Architecture

Symfony Services

ServiceMethodsPurpose
NotionClientrequest(), retry logicHTTP client for Notion API
NotionKnowledgeServiceCRUD operationsKnowledge item management
NotionCategoryServiceCRUD operationsCategory management
NotionPropertyMapperProperty conversionNotion ↔ PHP mapping
AIServicegenerateSummary()OpenAI integration
DigestServicegenerateDigest()Report generation
SlackServicesendDM(), sendMessage()Slack messaging

Slack Bot Handlers (TypeScript)

HandlerFilePurpose
Commandssrc/handlers/commands.ts/knowledge slash command
Actionssrc/handlers/actions.tsButton and menu actions
Submissionssrc/handlers/submissions.tsModal form submissions
Eventssrc/handlers/events.tsURL detection, file shares
Reactionssrc/handlers/reactions.tsEmoji-based capture
Shortcutssrc/handlers/shortcuts.tsMessage & global shortcuts
Homesrc/handlers/home.tsApp Home tab
Dashboardsrc/handlers/dashboard.tsDashboard rendering
Itemssrc/handlers/items.tsKnowledge item operations
Listssrc/handlers/lists.tsCategory/list management
SaveModalssrc/handlers/saveModals.tsSave modal handlers
SearchModalsrc/handlers/searchModal.tsSearch modal interface

File Structure

yappa-knowledge-hub/
├── src/                          # Slack bot (Node.js)
│   ├── app.js                    # Entry point
│   ├── handlers/                 # Slack event handlers
│   ├── services/                 # Business logic
│   └── i18n/nl.js                # Dutch translations
├── backend/                      # Symfony API
│   ├── src/
│   │   ├── Controller/           # REST endpoints
│   │   ├── Entity/               # Doctrine entities
│   │   ├── Service/Notion/       # Notion integration
│   │   └── Kernel.php
│   ├── config/                   # Symfony config
│   └── var/data.db               # SQLite (legacy/backup)
├── tests/                        # Jest tests
├── docs/                         # Documentation
│   ├── weekly/                   # 12 weekly internship reports
│   └── report/                   # Final report
└── scripts/                      # Utility scripts

Design Decisions

DecisionRationale
Symfony backendExisting codebase, strong for background jobs, type safety
Notion as primary DBSingle source of truth, web UI, collaboration
SQLite as backupFallback during Notion outages, local dev
Socket ModeNo public URL needed for development
Dutch localizationBelgian company (Yappa), NL-speaking users
Per-group AI summariesDifferent audiences need different perspectives

Performance Considerations

  • Notion API rate limit: 3 req/sec — batch operations, caching needed
  • OpenAI latency: 2-3s per summary — async processing via Symfony Messenger
  • Redis caching: Optional, for frequently accessed categories/knowledge
  • Pagination: All list endpoints support limit/offset