Feature: Speakers
Relevant source files
The following files were used as context for generating this wiki page:
- src/app/speakers/[speakerSlug]/page.tsx
- convex/model/speakers/mutations.ts
- convex/model/speakers/queries.ts
- src/app/speakers/[speakerSlug]/_components/speaker-content-sections.tsx
- src/features/speakers/components/speaker-form-fields.tsx
- src/app/speakers/page.tsx
- convex/lib/utils.ts
- src/app/speakers/[speakerSlug]/_components/speaker-hero.tsx
Feature: Speakers manages and displays profiles for faith-based content creators and ministers. The system centralizes biographical information, ministry affiliations, and media associations to provide a comprehensive view of a speaker's contributions to the platform.
The module supports CRUD operations through Convex mutations, specialized queries for public and admin views, and dynamic frontend routes for individual speaker profiles. It integrates directly with Talks, Clips, and Collections to aggregate all related media under a single speaker entity.
Sources: src/app/speakers/page.tsx:16-17, convex/model/speakers/queries.ts:46-52
Data Architecture
The Speaker entity serves as a primary relational anchor in the database. Every speaker requires a unique slug, generated from their first and last name, to facilitate SEO-friendly routing.
Entity Relationships
Speakers hold one-to-many relationships with talks and clips. They also have an indirect relationship with collections via the talks they contribute to.
The diagram illustrates how the Speaker entity connects to various content types and user interactions.
Sources: convex/model/speakers/mutations.ts:57-79, convex/model/speakers/queries.ts:58-86
Speaker Fields and Validation
| Field | Type | Description |
|---|---|---|
firstName | string | The speaker's given name. Required and cannot be empty. |
lastName | string | The speaker's family name. Required and cannot be empty. |
slug | string | URL-friendly identifier. Auto-generated or manually set. |
role | enum | Professional or ecclesiastical title (e.g., Pastor, Author). |
ministry | string | Church or organization affiliation. |
imageUrl | url | Link to the speaker's profile photograph. |
featured | boolean | Toggle for prominent display on index pages. |
Sources: convex/model/speakers/mutations.ts:16-24, src/features/speakers/components/speaker-form-fields.tsx:29-87
Backend Logic and Mutations
Backend operations ensure data integrity, particularly regarding unique identification and cascading effects during deletion.
Speaker Creation and Slugification
When a new speaker is created, the system generates a slug by combining the first and last name. The slugify utility removes special characters and replaces spaces with hyphens. The system throws a throwDuplicateSlug error if the generated slug already exists in the speakers table.
The flow demonstrates the validation and unique identifier generation process for new entries.
Sources: convex/model/speakers/mutations.ts:25-45, convex/lib/utils.ts:19-29
Deletion Protection
To prevent orphaned data, the destroySpeaker mutation performs reference checks. If a speaker has associated talks or clips, the mutation throws a validation error. Before a speaker is permanently deleted, the system automatically removes all entries from the userFavoriteSpeakers table to clean up user-specific associations.
Sources: convex/model/speakers/mutations.ts:57-89
Data Retrieval and Queries
The system provides specialized queries to support different application layers, from sitemaps to admin dashboards.
Public Speaker List
The listSpeakers query handles the main directory. It supports:
- Filtering: By search term (name) or role.
- Sorting: Alphabetical or featured priority.
- Pagination: Uses
paginateArrayfor in-memory handling when custom filters are applied. - Content Check: By default, it only returns speakers who have at least one published talk or clip.
Sources: convex/model/speakers/queries.ts:121-177
Speaker Detail Enrichment
The getSpeakerBySlug query retrieves a complete profile package. It fetches the speaker metadata and concurrently gathers all published talks and clips. It also resolves associated collections by mapping unique collectionId values found in the speaker's talks.
The sequence shows the aggregation of media assets required for a full speaker profile view.
Sources: convex/model/speakers/queries.ts:46-87
Frontend Components and Layouts
Speaker profiles use the EditorialProfileLayout to provide a consistent visual structure.
Profile Page Structure
The SpeakerPage component organizes the layout into two primary areas:
- Hero Section: Displays the speaker's identity and a rotated "Featured Talk" if available.
- Content Sections: A main column for media grids (Talks, Collections, Clips) and a metadata sidebar.
Sources: src/app/speakers/[speakerSlug]/page.tsx:88-109, src/app/speakers/[speakerSlug]/_components/speaker-content-sections.tsx:43-60
Content Rotation
To keep the UI dynamic, the SpeakerPage uses a rotateContent utility. It selects a "Featured Talk" from the speaker's list on a daily period. If the featured talk is a video, it is displayed prominently in the hero; otherwise, it remains in the standard talk list.
const [featuredTalk] = rotateContent(
featuredCandidates.length > 0 ? featuredCandidates : talks,
{
count: 1,
period: 'daily',
}
);
Sources: src/app/speakers/[speakerSlug]/page.tsx:50-57
Metadata Sidebar
The SpeakerMetadataSidebar displays supplementary information:
- About: The speaker's biography.
- Ministry: Links to their church or external website via
SpeakerMinistryLink. - Actions: Interaction buttons for sharing the profile or adding the speaker to favorites.
Sources: src/app/speakers/[speakerSlug]/_components/speaker-metadata-sidebar.tsx:16-56
Summary
Feature: Speakers provides a robust framework for managing content creators. By enforcing slug uniqueness in the backend and providing enriched relational queries, the system ensures that every speaker profile is both highly performant and content-rich. The integration of rotation logic and administrative safeguards allows the platform to scale while maintaining a high quality of content presentation.