Skip to content

Entities Documentation

This document provides comprehensive documentation for all Doctrine entities in the Yappa Knowledge Hub backend.

Overview

The backend has 6 main entities representing the database schema:

  1. Knowledge - Main knowledge items with Notion sync
  2. Category - Knowledge categories with target groups
  3. Resource - External resources (URLs, PDFs, etc.)
  4. ResourceContent - Content extracted from resources
  5. Summary - AI-generated summaries
  6. Tag - Tags for resources

Entity Relationship Diagram


Knowledge Entity

File: src/Entity/Knowledge.php

Table: knowledge

Description: Main entity for knowledge items. Stores knowledge in SQLite and syncs with Notion.

Properties

PropertyTypeNullableDescription
idintNoPrimary key (auto-increment)
titlestring(255)NoKnowledge item title
contenttextNoFull content/description
categoryCategoryYesRelated category (ManyToOne)
tagsarray (JSON)YesArray of tag strings
targetGroupsarray (JSON)YesArray of target group strings
userIdstring(255)YesUser who created it (Slack user ID)
statusstring(50)YesStatus (default: 'pending')
urlstring(500)YesSource URL
urlMetadataarray (JSON)YesMetadata from URL scraping
sourceMessagearray (JSON)YesOriginal Slack message data
attachmentsarray (JSON)YesFile attachments
summariesarray (JSON)YesAI-generated summaries
createdAtDateTimeImmutableNoCreation timestamp
updatedAtDateTimeImmutableNoLast update timestamp
notionIdstring(255)YesNotion page ID (UUID)
notionUrlstring(500)YesNotion page URL
lastSyncedAtDateTimeImmutableYesLast sync timestamp
notionLastEditedAtDateTimeImmutableYesNotion last edit timestamp

Relationships

  • ManyToOne with Category: A knowledge item belongs to one category
    • Property: category
    • Inverse: knowledges (OneToMany in Category)

Methods

php
// Getters
public function getId(): ?int
public function getTitle(): ?string
public function getContent(): ?string
public function getCategory(): ?Category
public function getTags(): ?array
public function getTargetGroups(): ?array
public function getUserId(): ?string
public function getStatus(): ?string
public function getUrl(): ?string
public function getUrlMetadata(): ?array
public function getSourceMessage(): ?array
public function getAttachments(): ?array
public function getSummaries(): ?array
public function getCreatedAt(): ?\DateTimeImmutable
public function getUpdatedAt(): ?\DateTimeImmutable
public function getNotionId(): ?string
public function getNotionUrl(): ?string
public function getLastSyncedAt(): ?\DateTimeImmutable
public function getNotionLastEditedAt(): ?\DateTimeImmutable

// Setters (fluent interface)
public function setTitle(string $title): static
public function setContent(string $content): static
public function setCategory(?Category $category): static
public function setTags(?array $tags): static
public function setTargetGroups(?array $targetGroups): static
public function setUserId(?string $userId): static
public function setStatus(?string $status): static
public function setUrl(?string $url): static
public function setUrlMetadata(?array $urlMetadata): static
public function setSourceMessage(?array $sourceMessage): static
public function setAttachments(?array $attachments): static
public function setSummaries(?array $summaries): static
public function setCreatedAt(\DateTimeImmutable $createdAt): static
public function setUpdatedAt(\DateTimeImmutable $updatedAt): static
public function setNotionId(?string $notionId): static
public function setNotionUrl(?string $notionUrl): static
public function setLastSyncedAt(?\DateTimeImmutable $lastSyncedAt): static
public function setNotionLastEditedAt(?\DateTimeImmutable $notionLastEditedAt): static

Example Usage

php
use App\Entity\Knowledge;
use App\Entity\Category;

// Create new knowledge
$knowledge = new Knowledge();
$knowledge->setTitle('Symfony Best Practices')
    ->setContent('Detailed guide on Symfony best practices...')
    ->setTags(['symfony', 'php', 'best-practices'])
    ->setTargetGroups(['developers'])
    ->setStatus('published')
    ->setUrl('https://symfony.com/doc/current/best_practices.html')
    ->setUserId('U12345');

// Set category
$category = $entityManager->getRepository(Category::class)->find(1);
$knowledge->setCategory($category);

// Persist
$entityManager->persist($knowledge);
$entityManager->flush();

// Query
$repository = $entityManager->getRepository(Knowledge::class);
$items = $repository->findBy(['status' => 'published']);

Category Entity

File: src/Entity/Category.php

Table: category

Description: Categories for organizing knowledge items. Syncs with Notion.

Properties

PropertyTypeNullableDescription
idintNoPrimary key (auto-increment)
namestring(255)NoCategory name
descriptionstring(255)YesCategory description
iconstring(50)YesEmoji icon (default: '📁')
targetGroupsarray (JSON)YesDefault target groups (default: [])
notionIdstring(255)YesNotion page ID
lastSyncedAtDateTimeImmutableYesLast sync timestamp
notionLastEditedAtDateTimeImmutableYesNotion last edit timestamp
createdAtDateTimeImmutableYesCreation timestamp
isActiveboolYesActive status (default: true)
sortOrderintYesSort order (default: 0)
knowledgesCollection-Related knowledge items (OneToMany)

Relationships

  • OneToMany with Knowledge: A category has many knowledge items
    • Property: knowledges
    • Inverse: category (ManyToOne in Knowledge)

Methods

php
// Getters
public function getId(): ?int
public function getName(): ?string
public function getDescription(): ?string
public function getIcon(): ?string
public function getTargetGroups(): ?array
public function getNotionId(): ?string
public function getLastSyncedAt(): ?\DateTimeImmutable
public function getNotionLastEditedAt(): ?\DateTimeImmutable
public function getCreatedAt(): ?\DateTimeImmutable
public function getIsActive(): bool
public function getSortOrder(): int
public function getKnowledges(): Collection

// Setters (fluent interface)
public function setName(string $name): static
public function setDescription(?string $description): static
public function setIcon(?string $icon): static
public function setTargetGroups(?array $targetGroups): static
public function setNotionId(?string $notionId): static
public function setLastSyncedAt(?\DateTimeImmutable $lastSyncedAt): static
public function setNotionLastEditedAt(?\DateTimeImmutable $notionLastEditedAt): static
public function setCreatedAt(?\DateTimeImmutable $createdAt): static
public function setIsActive(?bool $isActive): static
public function setSortOrder(?int $sortOrder): static

// Collection management
public function addKnowledge(Knowledge $knowledge): static
public function removeKnowledge(Knowledge $knowledge): static

Example Usage

php
use App\Entity\Category;

// Create category
$category = new Category();
$category->setName('Development')
    ->setDescription('Development resources and guides')
    ->setIcon('')
    ->setTargetGroups(['developers', 'devops'])
    ->setIsActive(true)
    ->setSortOrder(1);

$entityManager->persist($category);
$entityManager->flush();

// Query with knowledge items
$category = $repository->find(1);
foreach ($category->getKnowledges() as $knowledge) {
    echo $knowledge->getTitle() . "\n";
}

Resource Entity

File: src/Entity/Resource.php

Table: resource

Description: External resources like URLs, PDFs, videos, etc. with content extraction and summaries.

Properties

PropertyTypeNullableDescription
idintNoPrimary key (auto-increment)
titlestring(255)NoResource title
urlstring(500)YesResource URL
sourceTypeSourceType (enum)NoType of source (default: TEXT)
statusStatus (enum)NoProcessing status (default: PENDING)
notionIdstring(255)YesNotion page ID
lastSyncedAtDateTimeImmutableYesLast sync timestamp
notionLastEditedAtDateTimeImmutableYesNotion last edit timestamp
createdAtDateTimeImmutableNoCreation timestamp
updatedAtDateTimeImmutableNoLast update timestamp
tagsCollection-Related tags (ManyToMany)
categoriesCollection-Related categories (ManyToMany)
contentsCollection-Extracted content (OneToMany)
summariesCollection-AI summaries (OneToMany)

Enums

SourceType (src/Enum/SourceType.php):

php
enum SourceType: string
{
    case URL = 'url';
    case TEXT = 'text';
    case PDF = 'pdf';
    case RSS = 'rss';
    case YOUTUBE = 'youtube';
    case PODCAST = 'podcast';
}

Status (src/Enum/Status.php):

php
enum Status: string
{
    case PENDING = 'pending';
    case PROCESSING = 'processing';
    case DONE = 'done';
    case FAILED = 'failed';
}

Relationships

  • ManyToMany with Tag: A resource can have many tags

    • Property: tags
    • Join table: resource_tag
    • Inverse: resources (ManyToMany in Tag)
  • ManyToMany with Category: A resource can belong to many categories

    • Property: categories
    • Join table: resource_list
    • Inverse: resources (ManyToMany in Category)
  • OneToMany with ResourceContent: A resource has many content versions

    • Property: contents
    • Cascade: persist, remove
    • Inverse: resource (ManyToOne in ResourceContent)
  • OneToMany with Summary: A resource has many summaries

    • Property: summaries
    • Cascade: persist, remove
    • Inverse: resource (ManyToOne in Summary)

Methods

php
// Getters
public function getId(): ?int
public function getTitle(): ?string
public function getUrl(): ?string
public function getSourceType(): SourceType
public function getStatus(): Status
public function getNotionId(): ?string
public function getLastSyncedAt(): ?\DateTimeImmutable
public function getNotionLastEditedAt(): ?\DateTimeImmutable
public function getCreatedAt(): ?\DateTimeImmutable
public function getUpdatedAt(): ?\DateTimeImmutable
public function getTags(): Collection
public function getCategories(): Collection
public function getContents(): Collection
public function getSummaries(): Collection

// Setters (fluent interface)
public function setTitle(string $title): static
public function setUrl(?string $url): static
public function setSourceType(SourceType $sourceType): static
public function setStatus(Status $status): static
public function setNotionId(?string $notionId): static
public function setLastSyncedAt(?\DateTimeImmutable $lastSyncedAt): static
public function setNotionLastEditedAt(?\DateTimeImmutable $notionLastEditedAt): static

// Collection management
public function addTag(Tag $tag): static
public function removeTag(Tag $tag): static
public function addCategory(Category $category): static
public function removeCategory(Category $category): static
public function addContent(ResourceContent $content): static
public function removeContent(ResourceContent $content): static
public function addSummary(Summary $summary): static
public function removeSummary(Summary $summary): static

// Lifecycle callbacks
#[ORM\PreUpdate]
public function updateTimestamp(): void

Example Usage

php
use App\Entity\Resource;
use App\Enum\SourceType;
use App\Enum\Status;

// Create resource
$resource = new Resource();
$resource->setTitle('Symfony Documentation')
    ->setUrl('https://symfony.com/doc')
    ->setSourceType(SourceType::URL)
    ->setStatus(Status::PENDING);

// Add tags
$tag1 = $entityManager->getRepository(Tag::class)->findOneBy(['name' => 'symfony']);
$resource->addTag($tag1);

// Add content
$content = new ResourceContent();
$content->setContent('Extracted content from URL...')
    ->setContentType('text/html');
$resource->addContent($content);

$entityManager->persist($resource);
$entityManager->flush();

ResourceContent Entity

File: src/Entity/ResourceContent.php

Table: resource_content

Description: Stores extracted content from resources (HTML, text, etc.).

Properties

PropertyTypeNullableDescription
idintNoPrimary key (auto-increment)
contenttextNoExtracted content
contentTypestring(50)YesMIME type (default: 'text/plain')
resourceResourceNoParent resource (ManyToOne)
createdAtDateTimeImmutableNoCreation timestamp

Relationships

  • ManyToOne with Resource: Content belongs to one resource
    • Property: resource
    • Inverse: contents (OneToMany in Resource)

Methods

php
public function getId(): ?int
public function getContent(): ?string
public function setContent(string $content): static
public function getContentType(): ?string
public function setContentType(?string $contentType): static
public function getResource(): ?Resource
public function setResource(?Resource $resource): static
public function getCreatedAt(): ?\DateTimeImmutable

Example Usage

php
use App\Entity\ResourceContent;

$content = new ResourceContent();
$content->setContent('<html>...</html>')
    ->setContentType('text/html')
    ->setResource($resource);

$entityManager->persist($content);
$entityManager->flush();

Summary Entity

File: src/Entity/Summary.php

Table: summary

Description: AI-generated summaries for resources.

Properties

PropertyTypeNullableDescription
idintNoPrimary key (auto-increment)
contenttextNoSummary text
modelstring(50)YesAI model used (e.g., 'gpt-4')
resourceResourceNoParent resource (ManyToOne)
createdAtDateTimeImmutableNoCreation timestamp

Relationships

  • ManyToOne with Resource: Summary belongs to one resource
    • Property: resource
    • Inverse: summaries (OneToMany in Resource)

Methods

php
public function getId(): ?int
public function getContent(): ?string
public function setContent(string $content): static
public function getModel(): ?string
public function setModel(?string $model): static
public function getResource(): ?Resource
public function setResource(?Resource $resource): static
public function getCreatedAt(): ?\DateTimeImmutable

Example Usage

php
use App\Entity\Summary;

$summary = new Summary();
$summary->setContent('This article discusses Symfony best practices...')
    ->setModel('gpt-4')
    ->setResource($resource);

$entityManager->persist($summary);
$entityManager->flush();

Tag Entity

File: src/Entity/Tag.php

Table: tag

Description: Tags for categorizing resources. Many-to-many relationship with resources.

Properties

PropertyTypeNullableDescription
idintNoPrimary key (auto-increment)
namestring(255)NoTag name (unique)
resourcesCollection-Related resources (ManyToMany)

Relationships

  • ManyToMany with Resource: A tag can be used by many resources
    • Property: resources
    • Mapped by: tags (in Resource)

Methods

php
public function getId(): ?int
public function getName(): ?string
public function setName(string $name): static
public function getResources(): Collection
public function addResource(Resource $resource): static
public function removeResource(Resource $resource): static

Example Usage

php
use App\Entity\Tag;

// Create tag
$tag = new Tag('symfony');
$entityManager->persist($tag);
$entityManager->flush();

// Find or create tag
$tag = $repository->findOneBy(['name' => 'symfony']);
if (!$tag) {
    $tag = new Tag('symfony');
    $entityManager->persist($tag);
}

// Add to resource
$resource->addTag($tag);
$entityManager->flush();

Database Schema

SQLite Schema

sql
-- Category table
CREATE TABLE category (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name VARCHAR(255) NOT NULL,
    description VARCHAR(255),
    icon VARCHAR(50) DEFAULT ':file_folder:',
    target_groups TEXT,  -- JSON
    notion_id VARCHAR(255),
    last_synced_at DATETIME,
    notion_last_edited_at DATETIME,
    created_at DATETIME,
    is_active BOOLEAN DEFAULT 1,
    sort_order INTEGER DEFAULT 0
);

-- Knowledge table
CREATE TABLE knowledge (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    title VARCHAR(255) NOT NULL,
    content TEXT NOT NULL,
    category_id INTEGER,
    tags TEXT,  -- JSON
    target_groups TEXT,  -- JSON
    user_id VARCHAR(255),
    status VARCHAR(50) DEFAULT 'pending',
    url VARCHAR(500),
    url_metadata TEXT,  -- JSON
    source_message TEXT,  -- JSON
    attachments TEXT,  -- JSON
    summaries TEXT,  -- JSON
    created_at DATETIME NOT NULL,
    updated_at DATETIME NOT NULL,
    notion_id VARCHAR(255),
    notion_url VARCHAR(500),
    last_synced_at DATETIME,
    notion_last_edited_at DATETIME,
    FOREIGN KEY (category_id) REFERENCES category(id)
);

-- Resource table
CREATE TABLE resource (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    title VARCHAR(255) NOT NULL,
    url VARCHAR(500),
    source_type VARCHAR(20) NOT NULL,
    status VARCHAR(20) NOT NULL,
    notion_id VARCHAR(255),
    last_synced_at DATETIME,
    notion_last_edited_at DATETIME,
    created_at DATETIME NOT NULL,
    updated_at DATETIME NOT NULL
);

-- ResourceContent table
CREATE TABLE resource_content (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    content TEXT NOT NULL,
    content_type VARCHAR(50) DEFAULT 'text/plain',
    resource_id INTEGER NOT NULL,
    created_at DATETIME NOT NULL,
    FOREIGN KEY (resource_id) REFERENCES resource(id) ON DELETE CASCADE
);

-- Summary table
CREATE TABLE summary (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    content TEXT NOT NULL,
    model VARCHAR(50),
    resource_id INTEGER NOT NULL,
    created_at DATETIME NOT NULL,
    FOREIGN KEY (resource_id) REFERENCES resource(id) ON DELETE CASCADE
);

-- Tag table
CREATE TABLE tag (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name VARCHAR(255) NOT NULL UNIQUE
);

-- Join tables
CREATE TABLE resource_tag (
    resource_id INTEGER NOT NULL,
    tag_id INTEGER NOT NULL,
    PRIMARY KEY (resource_id, tag_id),
    FOREIGN KEY (resource_id) REFERENCES resource(id) ON DELETE CASCADE,
    FOREIGN KEY (tag_id) REFERENCES tag(id) ON DELETE CASCADE
);

CREATE TABLE resource_list (
    resource_id INTEGER NOT NULL,
    category_id INTEGER NOT NULL,
    PRIMARY KEY (resource_id, category_id),
    FOREIGN KEY (resource_id) REFERENCES resource(id) ON DELETE CASCADE,
    FOREIGN KEY (category_id) REFERENCES category(id) ON DELETE CASCADE
);

-- Indexes
CREATE INDEX IDX_knowledge_category ON knowledge(category_id);
CREATE INDEX IDX_knowledge_notion_id ON knowledge(notion_id);
CREATE INDEX IDX_category_notion_id ON category(notion_id);
CREATE INDEX IDX_resource_notion_id ON resource(notion_id);

Repositories

Each entity has a corresponding repository in src/Repository/:

  • KnowledgeRepository - Custom queries for knowledge items
  • CategoryRepository - Custom queries for categories
  • ResourceRepository - Custom queries for resources
  • ResourceContentRepository - Custom queries for content
  • SummaryRepository - Custom queries for summaries
  • TagRepository - Custom queries for tags

Example Repository Usage

php
// Get repository
$repository = $entityManager->getRepository(Knowledge::class);

// Find by ID
$knowledge = $repository->find(1);

// Find one by criteria
$knowledge = $repository->findOneBy(['notionId' => 'notion-page-id']);

// Find all by criteria
$items = $repository->findBy(['status' => 'published'], ['createdAt' => 'DESC']);

// Custom query
$qb = $repository->createQueryBuilder('k')
    ->where('k.title LIKE :search')
    ->setParameter('search', '%symfony%')
    ->orderBy('k.createdAt', 'DESC')
    ->setMaxResults(10);
$results = $qb->getQuery()->getResult();