Skip to content

Step 1 — Input: Create Lists & Add Knowledge

This step establishes the full architectural foundation — every layer from Slack UI down to database persistence. Users can create themed lists, add knowledge items through the App Home, and save any Slack message as knowledge via message actions.

User Stories

Story 1.1 — Create a List

As a user, I can create a thematic list via Slack so I can organize knowledge items.

Flow:

App Home → Click "Lijst toevoegen" → Fill modal (Name, Description, Icon) → Submit
  → Backend persists Category entity → Appears in App Home list

Story 1.2 & 1.3 — Add Knowledge (Shared Modal)

Both of the following stories open the same AddKnowledge modal and hit the same POST /api/knowledge endpoint. The only difference is how the modal is opened and what gets pre-filled.

The AddKnowledge Modal

FieldTypeRequiredNotes
TitleText inputShort title for the knowledge item
ContentTextareaFree-form text, notes, or context
CategoryDropdownSelect from existing lists
TagsText inputComma-separated tags
URLURL inputOptional link. In Step 1, stored as-is. In Step 2, triggers content extraction.

Story 1.2 — Add Knowledge via App Home

As a user, I can add a knowledge item from the App Home.

App Home → Click "Kennis toevoegen" → AddKnowledge modal opens (empty) → Fill fields → Submit

All fields start empty. The user fills in everything manually.

Story 1.3 — Save a Message via Message Action (⋮)

As a user, I can save any Slack message as a knowledge item using the three-dot menu.

Hover over message → Click ⋮ → "More actions" → "Opslaan in Knowledge Hub"
  → AddKnowledge modal opens pre-filled → User completes remaining fields → Submit

Pre-fill logic:

FieldPre-filled withExample
ContentFull message text"Kijk deze resource over accessibility: https://web.dev/learn"
URLFirst URL found in the message (regex)https://web.dev/learn
TitleEmpty — user must fill in
CategoryEmpty — user must select

TIP

Both stories share the same modal, the same Slack service call, and the same backend endpoint. Story 1.3 simply pre-fills the modal using data from the Slack message context (body.message.text).


What Happens to the URL in Step 1?

In Step 1, the URL is stored as a plain string on the Knowledge entity. Nothing is fetched or extracted — that's Step 2's job.

StepURL Behavior
Step 1 onlyURL saved in the url field. content = whatever the user typed. urlMetadata = null.
After Step 2URL saved in url field. Backend fetches the page → extracts text → appends to content. urlMetadata = extraction details.

Architecture Flow

The create knowledge flow demonstrates the full Orchestrator Pipeline from the 10-Layer Architecture:


Backend Files (~40 files including dependencies)

Constants (13 files)

Required by entities, DTOs, and services for validation, limits, and field names:

  • Entity/EntityLimits.php - Max lengths for fields
  • ErrorMessages.php - Validation error messages
  • Validation/ValidationConstants.php - Validation constraints
  • Validation/ValidationMessages.php - Validation error messages
  • Gedmo/GedmoConstants.php - Timestampable constants
  • Entity/EntityFields.php - Entity field names
  • Entity/OrmConstants.php - ORM relationship constants
  • Entity/RequestKeys.php - Request payload keys
  • Notion/NotionConstants.php - Notion-related constants
  • DtoKeys.php - DTO property keys
  • Response/ResponseKeys.php - Response keys
  • LogMessages.php - Logging messages
  • Mapper/MapperMethods.php - Mapper method names

Enums (2 files)

  • Enum/Status.php - Base status enum
  • Enum/KnowledgeStatus.php - Knowledge-specific statuses

Base Infrastructure — The Foundation (5 files)

These 5 classes are shipped at full size — they are the base that every service in the MVP will extend.

FilePurposeExtends~LOC
Service/BaseService.phpLogger, EntityManager, flush pattern60
Service/BaseDomainService.phpDomain-specific logging, validation failure loggingBaseService100
Service/BaseOrchestrator.phpexecuteWithLogging(), operation start/success/failure loggingOrchestratorInterface155
Mapper/BaseMapper.phptoDto(), toEntity(), toDtoCollection() template methodsMapperInterface80
Service/BaseQueryService.phpRead-only query base with logging, no persist/flushBaseService60

Entities (2 files)

FileKey PropertiesRelationships~LOC
Entity/Category.phpid, name, description, icon, notionId, timestamps, isActiveknowledges (OneToMany → Knowledge)130
Entity/Knowledge.phpid, title, content, tags (JSON), userId, status, url, urlMetadata (JSON), notionId, timestampscategory (ManyToOne → Category)200

IMPORTANT

Excluded from entities: targetGroups (ManyToMany), subscriptions, summaries, sourceMessage, attachments. These are MVP concerns.

Repositories (2 files)

FileInherited MethodsCustom Methods~LOC
Repository/CategoryRepository.phpfind(), findAll(), findOneBy()25
Repository/KnowledgeRepository.phpfind(), findAll(), findBy()findByCategoryAndDateRange() (used in Step 3)50

Mappers (2 files)

FiletoDto() MapstoEntity() Maps~LOC
Mapper/CategoryMapper.phpid, name, description, icon, notionId, createdAt, isActivename, description, icon60
Mapper/KnowledgeMapper.phpid, title, content, category, tags, userId, status, url, createdAttitle, content, categoryId, tags, userId, url80

Services (5 files)

FileLayerMethods~LOC
Service/Category/CategoryPersistenceService.phpPersistencecreate(Category): Category40
Service/Knowledge/KnowledgePersistenceService.phpPersistencecreate(Knowledge): Knowledge40
Service/Category/CategoryOrchestrator.phpOrchestrationcreate(), list()100
Service/Knowledge/KnowledgeOrchestrator.phpOrchestrationcreate(), list()130
Service/EmojiConverter.phpHelperEmoji conversion50

Controllers (2 files)

FileRoutes~LOC
Controller/CategoryController.phpPOST /api/categories (create), GET /api/categories (list)60
Controller/KnowledgeController.phpPOST /api/knowledge (create), GET /api/knowledge (list)70

WARNING

Only these 4 routes exist. No show, update, delete, or sync endpoints.

Request DTOs (2 files)

FilePurpose~LOC
DTO/Request/Category/CreateCategoryRequest.phpCategory creation validation30
DTO/Request/Knowledge/CreateKnowledgeRequest.phpKnowledge creation validation40

Response DTOs (5 files)

FilePurpose~LOC
DTO/Response/BaseResult.phpBase response wrapper20
DTO/Response/Category/CategoryListResponse.phpCategory list response30
DTO/Response/Category/CategoryResponse.phpSingle category response40
DTO/Response/Knowledge/KnowledgeListResponse.phpKnowledge list response30
DTO/Response/Knowledge/KnowledgeResponse.phpSingle knowledge response50

Slack Files (Separate POC)

IMPORTANT

Slack/TypeScript files are in a SEPARATE POC. This document covers only the Symfony/PHP backend. See the Slack POC for frontend implementation details.

The Slack app implements the same user stories with these components:

  • Views (4): dynamicHomeTab, categoriesView, addList modal, addKnowledge modal
  • Handlers (1): index.ts (view submissions, actions, message shortcuts)
  • Services (2): categories.ts, knowledge.ts
  • App Entry (1): app.ts (event handlers, health check)

These are NOT included in this Symfony POC scope.

Views

FileWhat It Renders~LOC
views/home/dynamicHomeTab.tsApp Home with Quick Actions bar, statistics, categories list. Categories view only — no knowledge items view, no AI summaries view100
views/home/categoriesView.tsList of categories with icon, name, description, item count. Overflow menu: "Kennis toevoegen"80
views/modals/categories/addList.tsModal: Name (required), Description (optional), Icon (optional). No target groups60
views/modals/knowledge/addKnowledge.tsShared modal for Story 1.2 and 1.3. Accepts optional prefill parameter to populate fields from message action context. Fields: Title, Content, Category select, Tags, URL. No target groups, no AI checkbox50

Handlers

FileHandles~LOC
handlers/index.tsView submissions: ADD_LISTaddCategory(), ADD_KNOWLEDGEaddKnowledge(). Actions: home buttons → open modals, category overflow → pre-select category. Message shortcut: save_to_knowledge_hub → extract message text + URL → open AddKnowledge modal with pre-fill220

Services

FileAPI Calls~LOC
services/categories.tslistCategories() — GET, addCategory() — POST40
services/knowledge.tsaddKnowledge() — POST with title, content, categoryId, tags, url, userId40

App Entry

FileRegisters~LOC
app.tsapp_home_opened, app.view(/.*/), app.action(/.*/), app.shortcut() (message action). Express health check. Category pre-cache on startup. No slash commands, no global shortcuts90

Verification Checklist

Story 1.1 — Create a List

  • [ ] GET /health → 200 OK
  • [ ] Open App Home → welcome header + quick action buttons + empty list
  • [ ] Click "Lijst toevoegen" → modal opens → fill name → submit → list appears in App Home

Story 1.2 — Add Knowledge via App Home

  • [ ] Click "Kennis toevoegen" → modal opens empty → fill fields → select category → submit → item saved
  • [ ] GET /api/knowledge → returns created knowledge item with category link

Story 1.3 — Save Message via Action

  • [ ] Hover over a Slack message → ⋮ → "Opslaan in Knowledge Hub" → AddKnowledge modal opens
  • [ ] Modal content field is pre-filled with the message text
  • [ ] If message contains a URL → url field is pre-filled with that URL
  • [ ] Fill in Title and Category → submit → item saved
  • [ ] Verify saved item has user's message as content

General

  • [ ] GET /api/categories → returns created categories as JSON
  • [ ] Add multiple items → App Home stats update (item count, list count)

Step 1 LOC Summary (Symfony Backend Only)

LayerFiles~LOC
Constants13200
Enums230
Base infrastructure5455
Entities2330
Repositories275
Mappers2140
Services5360
Controllers2130
Request DTOs270
Response DTOs5170
Total40~1,960

NOTE

| Slack/TypeScript files are in a separate POC (~790 LOC, 11 files) |