Adding a New Feature
Relevant source files
The following files were used as context for generating this wiki page:
- README.md
- DESIGN.md
- apps/api/src/features/ai/ai.service.ts
- apps/web/src/features/ai/components/video-analyzer.component.tsx
- apps/web/src/features/youtube/views/channel-analyzer.view.tsx
- package.json
- packages/db/drizzle/0002_amused_wasp.sql
- packages/types/package.json
- packages/ui/README.md
- packages/tailwind-config/shared-styles.css
- packages/db/drizzle/meta/0002_snapshot.json
This document outlines the process and architecture for adding a new feature to the Adfluens application. The project is a Turborepo monorepo, which organizes code into separate apps (the frontend web app and backend api app) and packages (shared code like UI components, types, and database configurations). Understanding this structure is key to contributing effectively.
A new feature typically involves creating components and logic across the api, web, and packages directories. The architecture emphasizes a "feature-based" organization, where all related code for a specific feature (e.g., AI analysis, YouTube integration) is co-located within its respective module. This approach promotes modularity and simplifies maintenance.
Sources: README.md:5-40
1. Project Structure Overview
The monorepo is managed by pnpm workspaces and Turborepo. The top-level directories are apps and packages.
apps/: Contains the runnable applications.web/: The React (Vite) frontend.api/: The Express and tRPC backend.
packages/: Contains shared libraries consumed by the apps.types/: Shared TypeScript types and Zod schemas.ui/: Shared React UI components built with shadcn/ui.db/: Database schema, migrations, and Drizzle ORM configuration.auth/: Authentication configuration and clients.tailwind-config/: Shared Tailwind CSS configuration.
Sources: README.md:5-34, package.json, packages/ui/package.json, packages/auth/package.json
This diagram illustrates the high-level dependency flow within the monorepo.
2. Backend Development (API)
New backend functionality is added to the apps/api/src/features/ directory. Each feature module separates its concerns into two primary file types.
| File Type | Purpose | Example |
|---|---|---|
*.router.ts | Defines tRPC procedures and their input validation (using Zod). This is a thin layer responsible for routing. | ai.router.ts |
*.service.ts | Contains the core business logic, database interactions, and calls to external APIs (e.g., Google Gemini). | ai.service.ts |
Sources: README.md:26-31, README.md:120-124
API Request Flow
The following diagram shows the flow of a request from the frontend to the backend service and an external API.
When adding a new feature, you will create a new service function and expose it via a new tRPC router procedure. For example, the analyzeVideo service function is responsible for constructing a prompt and calling the Gemini AI.
// apps/api/src/features/ai/ai.service.ts
export const analyzeVideo = async (
video: YouTubeVideo,
comments: YouTubeComment[]
): Promise<ViralAnalysisResult> => {
const ai = new GoogleGenAI({ apiKey: env.GEMINI_API_KEY });
// ... prompt construction ...
const response = await ai.models.generateContent({
model: GEMINI_MODEL,
contents: prompt,
config: {
tools: [{ googleSearch: {} }],
},
});
// ... JSON parsing and result formatting ...
return result;
};
Sources: apps/api/src/features/ai/ai.service.ts:13-64
3. Frontend Development (Web)
Frontend features are located in apps/web/src/features/. The structure mirrors the backend, with code organized by feature.
| Directory | Purpose | Example |
|---|---|---|
components/ | Feature-specific React components. | video-analyzer.component.tsx |
views/ | Top-level components that compose a page or a major UI section. | channel-analyzer.view.tsx |
hooks/ | TanStack Query hooks for data fetching, using the tRPC client. | README.md (by convention) |
utils/ | Complex, imperative business logic or data transformation functions. | youtube.utils.ts |
Sources: README.md:8-16, README.md:113-118
Frontend Architecture
A typical feature view composes smaller components and uses the trpcClient (often via custom hooks) to fetch data. State is managed with React hooks (useState, useEffect) and TanStack Query for server state.
This diagram shows how the VideoAnalyzer component fetches and displays data.
4. Shared Logic and Types
To ensure consistency and type safety, new features should leverage the shared packages.
Shared Types (@repo/types)
Define all data structures exchanged between the api and web apps in the @repo/types package. This allows tRPC to provide end-to-end type safety. Types are exported from packages/types/package.json to be easily consumable.
// packages/types/package.json
{
"name": "@repo/types",
// ...
"exports": {
"./ai/viral-analysis-result.type": {
"import": "./src/ai/viral-analysis-result.type.ts",
"types": "./src/ai/viral-analysis-result.type.ts"
},
"./ai/chat-message.type": {
"import": "./src/ai/chat-message.type.ts",
"types": "./src/ai/chat-message.type.ts"
}
}
}
Sources: packages/types/package.json:5-29
Shared UI (@repo/ui)
The @repo/ui package provides a library of accessible, themeable components. When building a new feature's UI, always use these components to maintain visual consistency.
Available Components:
Button, Card, Input, Label, Tabs, ScrollArea, and more.
To add a new component to the library, use the shadcn/ui CLI from within the packages/ui directory.
Sources: packages/ui/README.md:14-27, packages/ui/README.md:90-93
5. Database and Schema Changes
The project uses Drizzle ORM for database interactions. Schema and migrations are managed in the @repo/db package.
Creating a New Table
To add a new feature that requires data persistence, you will need to:
- Define a new table schema in the
@repo/dbpackage. - Generate a migration using the provided npm scripts.
The following ER diagram shows the relationship between users, organizations, and teams, as defined in a database migration.
Database Scripts
The root package.json provides scripts for managing the database.
| Script | Description |
|---|---|
pnpm db:generate | Generates Drizzle migration files based on schema changes. |
pnpm db:migrate | Applies pending migrations to the database. |
pnpm db:push | Pushes schema changes directly to the database (for development). |
pnpm db:studio | Starts the Drizzle Studio GUI to browse data. |
Sources: package.json:13-16
6. Design and UI Implementation
All UI development must adhere to the "The Digital Prism" design system, which is documented in DESIGN.md.
Core Principles
- Opinionated Minimalism: Remove visual noise, not features. Use structural clarity over generic card layouts.
- Editorial Precision: Information-dense layouts with strict hierarchy and typography.
- Soft Brutalism: Merge modern SaaS usability with the edge of brutalism. This means
1pxsolid borders, tight corner radii (2px-8px), and a strict avoidance of blurred drop shadows. Instead of shadows, use hard "offset" borders or outlines on hover.
Sources: DESIGN.md:17-25, DESIGN.md:82-90
Theming and Styles
The application supports light ("Paper & Ink") and dark ("Obsidian & Neon") modes. Colors, fonts, and other theme properties are defined as CSS variables in packages/tailwind-config/shared-styles.css.
/* packages/tailwind-config/shared-styles.css */
/* ===== Light Mode - "Paper & Ink" from DESIGN.md ===== */
:root {
--background: oklch(0.99 0 0); /* Alabaster #FDFDFC */
--foreground: oklch(0.11 0 0); /* Carbon #0A0A0A */
--primary: oklch(0.65 0.27 34); /* #FF4F00 */
--border: oklch(0.91 0 0); /* Smoke #E5E5E5 */
}
/* ===== Dark Mode - "Obsidian & Neon" from DESIGN.md ===== */
.dark {
--background: oklch(0.07 0 0); /* Obsidian #050505 */
--foreground: oklch(0.94 0 0); /* Mist #EDEDED */
--primary: oklch(0.65 0.27 34); /* #FF4F00 */
--border: oklch(0.23 0 0); /* Graphite #262626 */
}
Sources: DESIGN.md:43-78, packages/tailwind-config/shared-styles.css:184-232
When implementing a new component, use these variables and the utility classes provided by Tailwind to ensure it conforms to the design system.
Summary
Adding a new feature is a systematic process that touches multiple parts of the monorepo. By following the established feature-based architecture, leveraging the shared packages for types and UI, adhering to the design system, and correctly managing database changes, developers can build robust and consistent features efficiently. The separation of concerns between apps and packages, and between router and service files, is fundamental to the project's scalability and maintainability.
Relevant source files
The following files were used as context for generating this wiki page:
- README.md
- DESIGN.md
- apps/api/src/features/ai/ai.service.ts
- apps/web/src/features/ai/components/video-analyzer.component.tsx
- apps/web/src/features/youtube/views/channel-analyzer.view.tsx
- package.json
- packages/db/drizzle/0002_amused_wasp.sql
- packages/types/package.json
- packages/ui/README.md
- packages/tailwind-config/shared-styles.css
- packages/db/drizzle/meta/0002_snapshot.json
This document outlines the process and architecture for adding a new feature to the Adfluens application. The project is a Turborepo monorepo, which organizes code into separate apps (the frontend web app and backend api app) and packages (shared code like UI components, types, and database configurations). Understanding this structure is key to contributing effectively.
A new feature typically involves creating components and logic across the api, web, and packages directories. The architecture emphasizes a "feature-based" organization, where all related code for a specific feature (e.g., AI analysis, YouTube integration) is co-located within its respective module. This approach promotes modularity and simplifies maintenance.
Sources: README.md:5-40
1. Project Structure Overview
The monorepo is managed by pnpm workspaces and Turborepo. The top-level directories are apps and packages.
apps/: Contains the runnable applications.web/: The React (Vite) frontend.api/: The Express and tRPC backend.
packages/: Contains shared libraries consumed by the apps.types/: Shared TypeScript types and Zod schemas.ui/: Shared React UI components built with shadcn/ui.db/: Database schema, migrations, and Drizzle ORM configuration.auth/: Authentication configuration and clients.tailwind-config/: Shared Tailwind CSS configuration.
Sources: README.md:5-34, package.json, packages/ui/package.json, packages/auth/package.json
This diagram illustrates the high-level dependency flow within the monorepo.
2. Backend Development (API)
New backend functionality is added to the apps/api/src/features/ directory. Each feature module separates its concerns into two primary file types.
| File Type | Purpose | Example |
|---|---|---|
*.router.ts | Defines tRPC procedures and their input validation (using Zod). This is a thin layer responsible for routing. | ai.router.ts |
*.service.ts | Contains the core business logic, database interactions, and calls to external APIs (e.g., Google Gemini). | ai.service.ts |
Sources: README.md:26-31, README.md:120-124
API Request Flow
The following diagram shows the flow of a request from the frontend to the backend service and an external API.
When adding a new feature, you will create a new service function and expose it via a new tRPC router procedure. For example, the analyzeVideo service function is responsible for constructing a prompt and calling the Gemini AI.
// apps/api/src/features/ai/ai.service.ts
export const analyzeVideo = async (
video: YouTubeVideo,
comments: YouTubeComment[]
): Promise<ViralAnalysisResult> => {
const ai = new GoogleGenAI({ apiKey: env.GEMINI_API_KEY });
// ... prompt construction ...
const response = await ai.models.generateContent({
model: GEMINI_MODEL,
contents: prompt,
config: {
tools: [{ googleSearch: {} }],
},
});
// ... JSON parsing and result formatting ...
return result;
};
Sources: apps/api/src/features/ai/ai.service.ts:13-64
3. Frontend Development (Web)
Frontend features are located in apps/web/src/features/. The structure mirrors the backend, with code organized by feature.
| Directory | Purpose | Example |
|---|---|---|
components/ | Feature-specific React components. | video-analyzer.component.tsx |
views/ | Top-level components that compose a page or a major UI section. | channel-analyzer.view.tsx |
hooks/ | TanStack Query hooks for data fetching, using the tRPC client. | README.md (by convention) |
utils/ | Complex, imperative business logic or data transformation functions. | youtube.utils.ts |
Sources: README.md:8-16, README.md:113-118
Frontend Architecture
A typical feature view composes smaller components and uses the trpcClient (often via custom hooks) to fetch data. State is managed with React hooks (useState, useEffect) and TanStack Query for server state.
This diagram shows how the VideoAnalyzer component fetches and displays data.
4. Shared Logic and Types
To ensure consistency and type safety, new features should leverage the shared packages.
Shared Types (@repo/types)
Define all data structures exchanged between the api and web apps in the @repo/types package. This allows tRPC to provide end-to-end type safety. Types are exported from packages/types/package.json to be easily consumable.
// packages/types/package.json
{
"name": "@repo/types",
// ...
"exports": {
"./ai/viral-analysis-result.type": {
"import": "./src/ai/viral-analysis-result.type.ts",
"types": "./src/ai/viral-analysis-result.type.ts"
},
"./ai/chat-message.type": {
"import": "./src/ai/chat-message.type.ts",
"types": "./src/ai/chat-message.type.ts"
}
}
}
Sources: packages/types/package.json:5-29
Shared UI (@repo/ui)
The @repo/ui package provides a library of accessible, themeable components. When building a new feature's UI, always use these components to maintain visual consistency.
Available Components:
Button, Card, Input, Label, Tabs, ScrollArea, and more.
To add a new component to the library, use the shadcn/ui CLI from within the packages/ui directory.
Sources: packages/ui/README.md:14-27, packages/ui/README.md:90-93
5. Database and Schema Changes
The project uses Drizzle ORM for database interactions. Schema and migrations are managed in the @repo/db package.
Creating a New Table
To add a new feature that requires data persistence, you will need to:
- Define a new table schema in the
@repo/dbpackage. - Generate a migration using the provided npm scripts.
The following ER diagram shows the relationship between users, organizations, and teams, as defined in a database migration.
Database Scripts
The root package.json provides scripts for managing the database.
| Script | Description |
|---|---|
pnpm db:generate | Generates Drizzle migration files based on schema changes. |
pnpm db:migrate | Applies pending migrations to the database. |
pnpm db:push | Pushes schema changes directly to the database (for development). |
pnpm db:studio | Starts the Drizzle Studio GUI to browse data. |
Sources: package.json:13-16
6. Design and UI Implementation
All UI development must adhere to the "The Digital Prism" design system, which is documented in DESIGN.md.
Core Principles
- Opinionated Minimalism: Remove visual noise, not features. Use structural clarity over generic card layouts.
- Editorial Precision: Information-dense layouts with strict hierarchy and typography.
- Soft Brutalism: Merge modern SaaS usability with the edge of brutalism. This means
1pxsolid borders, tight corner radii (2px-8px), and a strict avoidance of blurred drop shadows. Instead of shadows, use hard "offset" borders or outlines on hover.
Sources: DESIGN.md:17-25, DESIGN.md:82-90
Theming and Styles
The application supports light ("Paper & Ink") and dark ("Obsidian & Neon") modes. Colors, fonts, and other theme properties are defined as CSS variables in packages/tailwind-config/shared-styles.css.
/* packages/tailwind-config/shared-styles.css */
/* ===== Light Mode - "Paper & Ink" from DESIGN.md ===== */
:root {
--background: oklch(0.99 0 0); /* Alabaster #FDFDFC */
--foreground: oklch(0.11 0 0); /* Carbon #0A0A0A */
--primary: oklch(0.65 0.27 34); /* #FF4F00 */
--border: oklch(0.91 0 0); /* Smoke #E5E5E5 */
}
/* ===== Dark Mode - "Obsidian & Neon" from DESIGN.md ===== */
.dark {
--background: oklch(0.07 0 0); /* Obsidian #050505 */
--foreground: oklch(0.94 0 0); /* Mist #EDEDED */
--primary: oklch(0.65 0.27 34); /* #FF4F00 */
--border: oklch(0.23 0 0); /* Graphite #262626 */
}
Sources: DESIGN.md:43-78, packages/tailwind-config/shared-styles.css:184-232
When implementing a new component, use these variables and the utility classes provided by Tailwind to ensure it conforms to the design system.
Summary
Adding a new feature is a systematic process that touches multiple parts of the monorepo. By following the established feature-based architecture, leveraging the shared packages for types and UI, adhering to the design system, and correctly managing database changes, developers can build robust and consistent features efficiently. The separation of concerns between apps and packages, and between router and service files, is fundamental to the project's scalability and maintainability.