Schema
This proposed schema uses Convex defineTable
and v
(validators) syntax, assuming a Convex backend, but the principles can be adapted to other database systems. It aims to capture user progress, Foundation data, generated assets, and link them conceptually to Ecom funnel performance (though actual funnel tracking often resides more heavily in Analytics/CRM systems).
Key Considerations:
- Granularity: Balancing detail with usability. Too granular is hard to manage; too high-level lacks insight.
- Relational Links: Using Convex
Id
types extensively to link related data (User -> Foundation -> Prompt Execution -> Asset -> Funnel Stage Performance). - Ecom Data Source: This schema assumes the Ecom funnel data (Leads, Sales, etc.) might be summarized or referenced here, but the primary source-of-truth for raw transaction/analytics data is likely the Ecom platform (Shopify, etc.) and Analytics tools (GA4). Deep integration would require webhooks or APIs.
- Flexibility: Using
v.any()
for AI outputs or complex objects allows flexibility but reduces type safety. Specific validators (v.object
,v.array
) are preferred where structure is known.
Proposed Convex Schema: Elevate Playbook & Ecom Funnel Integration
// convex/schema.ts
import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";
import { authTables } from "@convex-dev/auth/server";
//Validators reused across tables
const elevateStepValidator = v.union(
v.literal("Foundation"), // Module 0 is technically Foundation
v.literal("Hook"), // Step 1
v.literal("Gift"), // Step 2
v.literal("Identify"), // Step 3
v.literal("Engage"), // Step 4
v.literal("Sell"), // Step 5
v.literal("Nurture"), // Step 6
v.literal("Upsell"), // Step 7
v.literal("Educate"), // Step 8
v.literal("Share") // Step 9
);
// --- Core Elevate Playbook & Course Structure ---
export const playbookPrompts = defineTable({
step: elevateStepValidator, // Which framework step it belongs to
promptCode: v.string(), // e.g., "H1", "G3", "S2"
title: v.string(), // User-friendly title
description: v.string(),// Brief explanation of purpose
rocketTemplate: v.string(), // The full ROCKET prompt structure w/ placeholders
requiredContext: v.array(v.string()), // List of Foundation elements needed (e.g., "Customer Pain", "Brand Voice")
outputType: v.string(), // Expected output format (e.g., "List", "Email Draft", "JSON")
}).index("by_step", ["step"]);
export const courseModules = defineTable({
moduleNumber: v.union(v.number(), v.literal(0)), // 0 for Foundation, 1-9 for steps
step: elevateStepValidator,
title: v.string(),
objective: v.string(),
videoUrl: v.optional(v.string()),
textContent: v.optional(v.string()), // Summary or full text
gridDefinition: v.optional(v.any()), // Store grid structure/explanation
checklistItems: v.optional(v.array(v.string())),
worksheetUrl: v.optional(v.string()), // Link to downloadable worksheet
exampleImageUrl: v.optional(v.string()),
exampleText: v.optional(v.string()),
implementationGuide: v.optional(v.string()),
}).index("by_moduleNumber", ["moduleNumber"]);
// --- User Specific Data & Progress ---
export const users = defineTable({
// From Convex Auth - typically includes name, email, picture, etc.
...authTables.users.validator.fields,
// Additional custom user fields if needed
onboardingStatus: v.optional(v.string()), // e.g., 'Not Started', 'Foundation Complete', 'Course Complete'
});
// Add Indexes from authTables if necessary for queries
// .index("by_email", ["email"])
export const userFoundations = defineTable({
userId: v.id("users"),
// Store structured Foundation data based on the grids
companyContext: v.object({
coreOffers: v.optional(v.string()),
uniqueMechanism: v.optional(v.string()),
valueProposition: v.optional(v.string()),
brandPillars: v.optional(v.string()),
brandVoiceAdjectives: v.optional(v.array(v.string())),
positioningPrice: v.optional(v.string()),
missionVision: v.optional(v.string()),
brandStoryPersonality: v.optional(v.string()),
// ... potentially add all grid cells as optional fields
}),
marketAwareness: v.object({
competitors: v.optional(v.array(v.object({ name: v.string(), weakness: v.string() }))),
differentiation: v.optional(v.string()),
marketTrends: v.optional(v.string()),
channelAnalysis: v.optional(v.string()),
// ...
}),
customerAvatar: v.object({
profileSummary: v.optional(v.string()),
pains: v.optional(v.array(v.string())),
fears: v.optional(v.array(v.string())),
goals: v.optional(v.array(v.string())),
dreams: v.optional(v.array(v.string())),
needs: v.optional(v.array(v.string())),
wateringHoles: v.optional(v.string()),
// ...
}),
strategicBlueprintSummary: v.optional(v.string()), // Overall alignment summary
lastUpdatedAt: v.number(),
}).index("by_userId", ["userId"]);
export const userPromptExecutions = defineTable({
userId: v.id("users"),
promptCode: v.string(), // Reference to playbookPrompts.promptCode
elevateStep: elevateStepValidator,
inputContextSnapshot: v.any(), // Snapshot of Foundation data USED for this run
aiRequestTimestamp: v.number(),
aiResponse: v.optional(v.any()), // The raw AI output
aiResponseTimestamp: v.optional(v.number()),
status: v.union(v.literal("Pending"), v.literal("Success"), v.literal("Error")),
refinedOutputAssetId: v.optional(v.id("userGeneratedAssets")), // Link to the final refined asset
}).index("by_user_step", ["userId", "elevateStep"]);
export const userGeneratedAssets = defineTable({
userId: v.id("users"),
promptExecutionId: v.optional(v.id("userPromptExecutions")), // Link back to prompt run
elevateStep: elevateStepValidator,
assetType: v.string(), // e.g., "Ad Headline", "Email Subject", "Sales Page Section"
content: v.string(), // The refined, user-approved content
channel: v.optional(v.string()), // e.g., "Facebook Ads", "Klaviyo", "Website"
status: v.union(v.literal("Draft"), v.literal("Implemented"), v.literal("Archived")),
createdAt: v.number(),
lastUpdatedAt: v.number(),
}).index("by_user_step", ["userId", "elevateStep"]);
export const userModuleProgress = defineTable({
userId: v.id("users"),
moduleId: v.id("courseModules"),
status: v.union(v.literal("Not Started"), v.literal("In Progress"), v.literal("Completed")),
completedAt: v.optional(v.number()),
notes: v.optional(v.string()), // User notes for the module
}).index("by_user_module", ["userId", "moduleId"]);
// --- Ecom Funnel Performance Data (Conceptual - Summarized/Referenced) ---
// NOTE: Real-time, granular funnel data typically lives in Analytics (GA4)
// and the Ecom Platform (Shopify, Woo). This table might store
// user-inputted summaries or potentially integrated data for dashboarding.
export const userFunnelSnapshots = defineTable({
userId: v.id("users"),
snapshotDate: v.number(), // Timestamp for the data period start/end
timePeriod: v.string(), // e.g., "Last 7 Days", "Last 30 Days", "Month of April"
// ATTRACT Metrics
hook_AvgCTR: v.optional(v.number()),
gift_OptInRate: v.optional(v.number()),
gift_CPL: v.optional(v.number()), // Cost Per Lead
attract_LeadsTotal: v.optional(v.number()),
// CONVERT Metrics
engage_AssistedConversionRate: v.optional(v.number()),
sell_ConversionRate: v.optional(v.number()), // e.g., Lead -> Sale Rate
sell_AOV_Initial: v.optional(v.number()), // AOV before upsell
nurture_EmailConvRate: v.optional(v.number()),
nurture_RetargetingROAS: v.optional(v.number()),
convert_TotalSales: v.optional(v.number()),
convert_CPA: v.optional(v.number()), // Cost Per Acquisition
// GROW Metrics
upsell_TakeRate: v.optional(v.number()),
upsell_AOV_Final: v.optional(v.number()), // AOV including upsell
educate_RepeatPurchaseRate: v.optional(v.number()),
educate_CSAT_NPS: v.optional(v.number()), // Could be avg score
share_ReviewRate: v.optional(v.number()), // % requests resulting in review
grow_CLTV_Estimate: v.optional(v.number()), // Customer Lifetime Value
// Overall
overallROI: v.optional(v.number()),
notes: v.optional(v.string()), // User notes about this snapshot
}).index("by_user_date", ["userId", "snapshotDate"]);
// Schema Definition
export default defineSchema({
// Include base auth tables
...authTables,
// Elevate Framework / Playbook Structure
playbookPrompts,
courseModules,
// User Data & Progress
// Note: 'users' table now includes auth fields directly
userFoundations,
userPromptExecutions,
userGeneratedAssets,
userModuleProgress,
// Conceptual Ecom Funnel Data
userFunnelSnapshots,
// Need tables from previous chat schema if integrating that fully
// agents, conversations, conversationParticipants, conversationMessages, etc.
// (Omitted here for focus, but would be needed for a full chat/agent system)
});
Explanation and Integration:
- Playbook Structure (
playbookPrompts
,courseModules
): Defines the static content of the course and the prompt library itself. Links prompts to specific framework steps. - User Data (
users
,userFoundations
): Stores core user info (viaauthTables
) and, crucially, their specific, structured Foundation Blueprint data. This is the context source. - User Activity (
userPromptExecutions
,userGeneratedAssets
,userModuleProgress
): Tracks how users interact with the course and playbook.userPromptExecutions
: Logs when a user runs a specific prompt and what Foundation context was used at that time (snapshotting is important as Foundation might evolve). It also stores the raw AI response and links to the refined asset.userGeneratedAssets
: Stores the final, user-refined pieces of content (headlines, emails) generated for each step, linked back to the prompt execution that created the draft.userModuleProgress
: Tracks course completion.
- Ecom Funnel Data (
userFunnelSnapshots
): This table is conceptual and likely requires the user to manually input summarized KPIs from their external analytics tools (GA4, Shopify Analytics, Ad Platforms) periodically, or requires complex API integrations (beyond the scope of a simple schema definition). It provides the data needed for the Student Analytics Dashboard. Linking specificuserGeneratedAssets
to performance changes inuserFunnelSnapshots
allows for assessing the impact of implementing the framework.
Seamless Integration:
- The
userFoundations
table provides the persistent context required by prompts defined inplaybookPrompts
. - When a user triggers a prompt via the UI (interacting with
courseModules
content), the system fetches their currentuserFoundations
data, structures it according to theplaybookPrompts.requiredContext
, executes the prompt, and logs it inuserPromptExecutions
. - The user refines the AI output and saves the final version in
userGeneratedAssets
, linking it back. - The
userFunnelSnapshots
table (populated manually or via integration) provides the performance data against which the effectiveness of the implemented assets (userGeneratedAssets
) and overall framework adoption (userModuleProgress
) can be measured.
This schema provides a robust structure for managing the course content, user-specific data, AI interactions, and performance metrics, enabling the integrated Elevate system experience.
Okay, let’s define schemas for a persons
table (representing human individuals interacting with or relevant to the system) and refine the existing agents
schema to clearly delineate the team members you described.
This assumes the users
table (from authTables
) represents authenticated login accounts, while the persons
table represents actual human entities who might also be authenticated users, or might be team members, contacts, or even stakeholder profiles defined within the Foundation.
We will incorporate this into the main schema definition.
Refined Convex Schema with persons
and Updated agents
Table
// convex/schema.ts
import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";
import { authTables } from "@convex-dev/auth/server"; // Assuming you use convex/auth
// --- Reusable Validators ---
const elevateStepValidator = v.union(
v.literal("Foundation"), v.literal("Hook"), v.literal("Gift"),
v.literal("Identify"), v.literal("Engage"), v.literal("Sell"),
v.literal("Nurture"), v.literal("Upsell"), v.literal("Educate"),
v.literal("Share")
);
// --- NEW: Person Schema ---
// Represents human individuals involved (Users, Team Members, Contacts)
export const persons = defineTable({
userId: v.optional(v.id("users")), // Link to auth user record IF they log in
name: v.string(), // Full name
firstName: v.optional(v.string()),
lastName: v.optional(v.string()),
email: v.optional(v.string()), // Primary email, might differ from login email
role: v.optional(v.string()), // Role within ONE system context (e.g., "Student", "Admin", "Team Member")
organizationId: v.optional(v.id("organizations")), // Link if part of a team/company
avatarUrl: v.optional(v.string()), // Profile picture URL
metadata: v.optional(v.any()), // For any other relevant person details
}).index("by_userId", ["userId"])
.index("by_email", ["email"]) // Add index if searching by email is common
.index("by_organization", ["organizationId"]); // Add index if filtering by org
// --- REFINED: Agent Schema ---
// Defines both AI agents created by users and specialized system agents
const commonAgentFields = {
name: v.string(), // Agent's display name
description: v.string(), // What the agent does
personality: v.string(), // Core persona description / guiding principles
avatarUrl: v.string(), // URL for the agent's avatar
tools: v.optional(v.array(v.string())), // List of tool names agent can use (from shared/tools.ts)
lastActiveTime: v.optional(v.number()),// Timestamp of last known activity
};
// Define specialized System Agent roles (extensible)
const systemAgentRoleValidator = v.union(
v.literal("Director"), // Orchestrates the user's journey through Elevate
v.literal("Sage"), // Foundation knowledge base expert
v.literal("Teacher"), // Elevate framework & Playbook educator
v.literal("Writer"), // Content generation specialist
v.literal("Marketer"), // Campaign strategy & tactics advisor
v.literal("SEO"), // Search Engine Optimiser (UK English focus)
v.literal("Researcher"), // Directed information gathering (via tools)
v.literal("Connector"), // API / Integration specialist
v.literal("Seller"), // Conversion optimization / Closing expert
v.literal("MediaBuyer"), // Paid traffic specialist
v.literal("Advocate"), // SHARE step / Community specialist
v.literal("Guide") // User journey / Customer state navigator
// Add other system roles as needed
);
export const agents = defineTable(
v.union(
// Agents created by users
v.object({
kind: v.literal("user_agent"),
createdBy: v.id("users"), // Link to the user who created it
configuration: v.optional(v.any()), // Specific settings or loaded prompts
...commonAgentFields
}),
// Pre-defined system agents with specific roles
v.object({
kind: v.literal("system_agent"),
systemRole: systemAgentRoleValidator, // Defines the agent's specific function
baseInstructions: v.optional(v.string()), // Core prompt instructions for this role
configuration: v.optional(v.any()), // Role-specific configuration
...commonAgentFields
})
)
).index("by_creator", ["createdBy", "kind"]) // Find agents created by a specific user
.index("by_systemRole", ["systemRole", "kind"]); // Easily find specific system agents like the Director
// --- Conceptual Organization Schema (Example) ---
// Optional, only if you need multi-user/team structures
export const organizations = defineTable({
name: v.string(),
ownerId: v.id("users"),
// add subscription details etc. if needed
}).index("by_owner", ["ownerId"]);
// --- Other Existing Tables (Keep as previously defined) ---
export const playbookPrompts = defineTable({ /* ... as before ... */ })
.index("by_step", ["step"]);
export const courseModules = defineTable({ /* ... as before ... */ })
.index("by_moduleNumber", ["moduleNumber"]);
export const userFoundations = defineTable({ /* ... as before ... */ })
.index("by_userId", ["userId"]);
export const userPromptExecutions = defineTable({ /* ... as before ... */ })
.index("by_user_step", ["userId", "elevateStep"]);
export const userGeneratedAssets = defineTable({ /* ... as before ... */ })
.index("by_user_step", ["userId", "elevateStep"]);
export const userModuleProgress = defineTable({ /* ... as before ... */ })
.index("by_user_module", ["userId", "moduleId"]);
export const userFunnelSnapshots = defineTable({ /* ... as before ... */ })
.index("by_user_date", ["userId", "snapshotDate"]);
// Potentially add chat-related tables if integrating directly
// conversations, conversationParticipants, conversationMessages
// --- Schema Definition ---
export default defineSchema({
// Include base auth tables if using convex/auth
...authTables, // Includes the 'users' table
// Core Person & Agent Schemas
persons, // Represents humans
agents, // Represents AI agents (user & system)
organizations, // Optional for team structures
// Elevate Framework / Playbook Structure
playbookPrompts,
courseModules,
// User Data & Progress
userFoundations,
userPromptExecutions,
userGeneratedAssets,
userModuleProgress,
// Conceptual Ecom Funnel Data
userFunnelSnapshots,
// Add chat-related tables if applicable
// conversations,
// conversationParticipants,
// conversationMessages,
});
Explanation of Changes & “Beautiful Person” Schema:
-
persons
Table:- Creates a distinct table to represent human individuals.
userId
(optionalId<"users">
): This is the critical link. If a person is also an authenticated user, this field connects their person record to their login account (users
table fromauthTables
). It’s optional because you might store info about team members or contacts who don’t log in.name
,firstName
,lastName
,email
,avatarUrl
: Standard contact information.role
: Important for defining their relationship to the system/course (e.g., “Student,” “Admin,” “Prospect Contact”).organizationId
: Allows grouping people into teams or companies (requires the simpleorganizations
table).metadata
: Flexible field for additional unstructured info.
-
agents
Table Refined:commonAgentFields
: Extracted common fields for better structure.user_agent
kind: Remains largely the same, clearly linked to acreatedBy
user (Id<"users">
). Addedconfiguration
field for potential user-specific settings or prompt overrides.system_agent
kind: Replaced the genericsystemAgentKind
with a more descriptivesystemRole
validator. This explicitly lists the different system agent types you defined (Director, Sage, Teacher, Writer, SEO, Researcher, Connector, Seller, MediaBuyer, Advocate, Guide). This makes querying for specific system agents much easier and the schema more self-documenting. AddedbaseInstructions
to potentially store core role-defining prompts directly in the DB.
-
organizations
Table (Conceptual): Added a simple table to support groupingpersons
if needed for team features later.
Integration & How it Works:
- When a user signs up/logs in via
authTables
, you might create a corresponding entry in thepersons
table, linking it via theuserId
. - The
agents
table clearly distinguishes between AI agents created by users (user_agent
) and the specialized system agents (system_agent
) that facilitate the ONE Playbook experience. - The
Director
agent (systemRole: "Director"
) orchestrates interactions, potentially mentioning (@
) specific system agents like@Teacher
or@Writer
, or user-created@UserAgentName
. - The
@Sage
agent (systemRole: "Sage"
) would query the specific user’suserFoundations
table to retrieve context. - Other agents take instructions based on their
systemRole
and associatedbaseInstructions
/configuration
.
This structure provides a clear distinction between human entities (persons
, users
) and AI entities (agents
), while allowing for specialized roles within the AI team to guide the student effectively through the Elevate Framework.