Entities & Data Models
Last Updated: 2026-05-08
The Yappa Knowledge Hub has 5 entities managed by Doctrine ORM with SQLite.
Entity Relationship Diagram
Primary Entities
Category
Thematic lists that organise knowledge items. Each category has its own digest configuration.
| Field | Type | Description |
|---|---|---|
| id | int (auto) | Primary key |
| name | string (255) | Display name, 2-100 chars, required |
| description | string (255) | Optional description |
| icon | string (50) | Emoji icon, default :file_folder: |
| targetGroups | JSON | Audience labels synced from Notion |
| notionId | string | Notion page reference |
| isActive | bool | Visibility flag, default true |
| sortOrder | int | Display order, default 0 |
| digestEnabled | bool | Scheduled digest flag |
| digestFrequency | enum | weekly/biweekly/monthly/quarterly |
| digestDay | int | Day of week |
| digestTime | string | Time HH:MM |
| lastDigestAt | datetime | Last digest generation timestamp |
| createdAt/updatedAt | datetime | Gedmo auto-managed |
Relationships: OneToMany to Knowledge, Digest, Subscription (CASCADE).
Knowledge
The core data unit — user-submitted content enhanced with URL extraction and AI summaries.
| Field | Type | Description |
|---|---|---|
| id | int (auto) | Primary key |
| title | string (255) | Display title, 3-255 chars, required |
| content | text | User text + extracted URL content |
| tags | JSON | User-defined tags |
| targetGroups | JSON | Audience labels |
| userId | string | Creator's Slack user ID |
| status | string | pending/Not started/In progress/Done/approved/rejected/archived/draft/published |
| url | string (500) | Source URL |
| urlMetadata | JSON | Extraction details (title, length, type) |
| sourceMessage | JSON | Original Slack message data |
| highlight | text | AI-generated 2-3 sentence Dutch summary |
| summaries | JSON | AI summary data from Notion sync |
| notionId | string | Notion page ID |
| notionUrl | string (2048) | Direct Notion page link |
| createdAt/updatedAt | datetime | Gedmo auto-managed |
Relationships: ManyToOne to Category (nullable, SET NULL on delete).
Digest
Generated knowledge reports with AI summaries, persisted and synced to Notion.
| Field | Type | Description |
|---|---|---|
| id | int (auto) | Primary key |
| title | string (255) | Auto-generated: "Digest: {Category} ({dateRange})" |
| content | text | Full Dutch Markdown digest |
| period | string | Date range label |
| status | string | Done/sent |
| statistics | JSON | highlightCount, days, tokenCount, cost, durationMs |
| knowledgeHighlights | JSON | Immutable snapshot of highlights at generation time |
| generatedBy | string | Slack user who triggered generation |
| notionId | string | Notion page ID |
| notionUrl | string (2048) | Notion page link |
| createdAt/updatedAt | datetime | Gedmo auto-managed |
Relationships: ManyToOne to Category (required), ManyToMany to Knowledge via digest_knowledge join table.
DigestDelivery
Per-user delivery tracking for digest distribution with retry support.
| Field | Type | Description |
|---|---|---|
| id | int (auto) | Primary key |
| userId | string | Recipient Slack user ID |
| deliveryChannel | string | slack/notion/email |
| status | string | pending/sent/failed |
| retryCount | int | Retry attempts (max 3) |
| errorMessage | text | Failure details |
| sentAt | datetime | Delivery timestamp |
| createdAt | datetime | Gedmo auto-managed |
Relationships: ManyToOne to Digest (required, CASCADE). Domain methods: markAsSent(), markAsFailed(), canRetry(), resetForRetry().
Subscription
User opt-in to receive digest notifications for a category.
| Field | Type | Description |
|---|---|---|
| id | int (auto) | Primary key |
| userId | string | Subscriber Slack user ID |
| slackUserName | string | Display name |
| isActive | bool | Default true |
| subscribedAt | datetime | Gedmo auto-managed |
| unsubscribedAt | datetime | Set on deactivation |
| notionId | string | Notion page reference |
Relationships: ManyToOne to Category (required, CASCADE). Unique constraint: (userId, categoryId) — one subscription per user per category. Domain methods: deactivate(), reactivate().
Enums
| Enum | Values | Used By |
|---|---|---|
| DigestFrequency | weekly, biweekly, monthly, quarterly | Category.digestFrequency |
| KnowledgeStatus | pending, Not started, In progress, Done, approved, rejected, archived, draft, published | Knowledge.status (validation only) |
Technical Details
- Storage: SQLite via Doctrine ORM
- Timestamps: Gedmo Timestampable (auto-managed, no manual setters)
- Validation: Symfony Assert attributes on all entities
- Serialization: Symfony Serializer groups (
category:read,knowledge:read,digest:read) - Migrations: Schema created via
doctrine:schema:create(no migration files in use)