Skip to content

POC Scope & Achievements

What Was the POC

The Proof of Concept was a focused development phase that validated the technical feasibility of building a Slack-based knowledge management system with Notion integration and AI-powered summaries.

The POC proved:

  • Slack Socket Mode integration provides reliable real-time event handling
  • Symfony backend can orchestrate business logic with clean layered architecture
  • AI integration (OpenAI/OpenRouter) can generate useful Dutch-language summaries
  • The full Input → Process → Output loop works end-to-end

What the POC Delivered

The POC was implemented in 3 steps that each built on the previous:

Step 1 — Input: Create Lists & Add Knowledge

What was built:

  • Full Orchestrator Pipeline: Controller → Orchestrator → PersistenceService → Repository
  • 5 base infrastructure classes (BaseService, BaseDomainService, BaseOrchestrator, BaseMapper, BaseQueryService)
  • Category and Knowledge entities with Doctrine ORM
  • Slack Bolt app with App Home, Add List modal, Add Knowledge modal, message shortcut

API routes: 4 (POST/GET /api/categories, POST/GET /api/knowledge)

Step 2 — Process: Backend Content Extraction

What was built:

  • ContentExtractionService with SSRF protection
  • HtmlContentExtractor with Readability-based parsing
  • Automatic URL content appending to knowledge items
  • Graceful failure handling (never blocks saves)

New files: 3 (+ 1 modified orchestrator)

Step 3 — Output: AI-Enhanced Digest & DM Delivery

What was built:

  • Full AI provider stack: AiProviderInterface → OpenAIService
  • DigestOrchestrator with per-item AI summary generation
  • Block Kit DM delivery via Slack chat.postMessage
  • Mock mode for testing without API calls

New files: 12 (9 backend, 3 Slack)

How the POC Evolved into the MVP

The POC directly evolved into the current system. Key additions made during the MVP phase:

Feature AddedPOC BaselineMVP Implementation
Digest PersistenceEphemeral DTO returned to SlackFull Digest entity with database persistence
DistributionSlack handler built and sent DM directlyBackend DigestDistributionService with per-user delivery tracking
SubscriptionsNot implementedSubscription entity with subscribe/unsubscribe/soft-delete
Category SettingsBasic name/description/iconDigest frequency, day, time, enabled toggle
Scheduled DigestsManual onlyDigestSchedulerService with cron support
Notion SyncOutbound only (Slack → Notion)Bidirectional for all 4 entity types
AI Highlight StorageNot persistedKnowledge.highlight field with lazy generation
Delivery TrackingNot implementedDigestDelivery entity with retry support

Technical Stack

LayerTechnologyPurpose
BackendPHP 8.2 + Symfony 7.3API, business logic, AI integration
DatabaseSQLite + Doctrine ORMLocal persistence
AIOpenAI / OpenRouterDutch-language summaries
Bot Framework@slack/bolt v3.17.1 + TypeScriptSlack event handling
ExternalNotion API v2022-06-28Secondary storage and sync

Architecture Delivered

Entities: 5

Category ──OneToMany──→ Knowledge
Category ──OneToMany──→ Digest
Category ──OneToMany──→ Subscription (CASCADE)
Digest ──ManyToMany──→ Knowledge (via join table)
Digest ──OneToMany──→ DigestDelivery (CASCADE)

Services: 38 files across 12 directories

Service/
├── Ai/ (2) — Provider interface + OpenAI/OpenRouter
├── Content/ (2) — Content extraction + HTML parser
├── Digest/ (10) — Full digest pipeline
├── Knowledge/ (3) — Creation, persistence, query
├── Notion/ (11) — Sync, repositories, builders, mappers
├── Orchestrator/ (2) — Digest + Knowledge orchestrators
├── Slack/ (1) — Slack DM delivery
├── Subscription/ (3) — Facade + query/persistence
├── Transport/ (2) — Message transport interface + Slack impl
└── Root (2) — CategoryService + EmojiConverter

API Routes: 18 across 6 controllers

All routes authenticated with bearer token (ROLE_ADMIN).

Code Statistics

MetricValue
Backend files~80+ (entities, services, controllers, DTOs, mappers, constants, enums)
Slack bot files~15 (handlers, views, services, app entry)
Total services38
Total entities5
Total API routes18
DatabaseSQLite (8 tables)
AI providerOpenAI + OpenRouter
TestingPHPUnit (backend) + Playwright (E2E)

Lessons Learned

What Worked Well

  1. Layered architecture — The Orchestrator → Service → Repository pattern scaled well from POC to MVP
  2. SQLite for MVP — Simple, no external dependencies, fast enough for the team's scale
  3. Slack as UI — Zero frontend framework needed, native experience
  4. AI provider abstractionAiProviderInterface allowed swapping OpenAI for OpenRouter seamlessly
  5. Lazy AI generation — Generating summaries only when needed (digest time) kept knowledge creation fast

What Changed from Plan

  1. No entity renames — Knowledge stayed as Knowledge (not renamed to Resource), Category stayed as Category (not ThematicList)
  2. No Redis/Messenger — Synchronous SQLite proved sufficient; adding these would be premature optimization
  3. No per-role summaries — Single summary per item was simpler and still valuable
  4. No PromptTemplate entity — Hardcoded prompt works well for one summary type
  5. No separate Tag entity — JSON arrays on entities were simpler and sufficient