2
0

feat(pages): add A/B testing framework for landing pages

Implement comprehensive A/B testing system for landing page optimization:
- Database models for experiments, variants, and events
- AI-powered variant generation and analysis
- Visitor tracking with conversion metrics
- Experiment lifecycle management (draft/active/paused/completed)
- Email notifications for experiment results
- Cron job for automated experiment monitoring
- UI for viewing experiment results and statistics
This commit is contained in:
2026-03-07 12:39:42 -05:00
parent 64b4a9ceed
commit 3a8bdd936c
27 changed files with 1371 additions and 84 deletions

View File

@@ -213,6 +213,20 @@ func (c *Client) InspectWorkflow(ctx context.Context, req *InspectWorkflowReques
return resp, nil
}
// ExecuteTask executes a generic AI task via the sidecar
func (c *Client) ExecuteTask(ctx context.Context, req *ExecuteTaskRequest) (*ExecuteTaskResponse, error) {
if !IsEnabled() {
return nil, errors.New("AI service is not enabled")
}
var resp ExecuteTaskResponse
if err := c.doRequest(ctx, http.MethodPost, "/execute-task", req, &resp); err != nil {
log.Error("AI ExecuteTask failed: %v", err)
return nil, err
}
return &resp, nil
}
// CheckHealth checks the health of the AI service
func (c *Client) CheckHealth(ctx context.Context) (*HealthCheckResponse, error) {
var resp HealthCheckResponse

View File

@@ -258,6 +258,22 @@ type InspectWorkflowResponse struct {
OutputTokens int `json:"output_tokens"`
}
// ExecuteTaskRequest is the request for executing a generic AI task
type ExecuteTaskRequest struct {
ProviderConfig *ProviderConfig `json:"provider_config,omitempty"`
RepoID int64 `json:"repo_id"`
Task string `json:"task"`
Context map[string]string `json:"context"`
AllowedTools []string `json:"allowed_tools,omitempty"`
}
// ExecuteTaskResponse is the response from executing a generic AI task
type ExecuteTaskResponse struct {
Success bool `json:"success"`
Result string `json:"result"`
Error string `json:"error,omitempty"`
}
// HealthCheckResponse is the response from a health check
type HealthCheckResponse struct {
Healthy bool `json:"healthy"`

View File

@@ -47,6 +47,9 @@ type LandingConfig struct {
// Blog section
Blog BlogSectionConfig `yaml:"blog,omitempty"`
// Navigation visibility
Navigation NavigationConfig `yaml:"navigation,omitempty"`
// Footer
Footer FooterConfig `yaml:"footer,omitempty"`
@@ -61,6 +64,9 @@ type LandingConfig struct {
// Advanced settings
Advanced AdvancedConfig `yaml:"advanced,omitempty"`
// A/B testing experiments
Experiments ExperimentConfig `yaml:"experiments,omitempty"`
}
// BrandConfig represents brand/identity settings
@@ -69,6 +75,7 @@ type BrandConfig struct {
LogoURL string `yaml:"logo_url,omitempty"`
LogoSource string `yaml:"logo_source,omitempty"` // "url" (default), "repo", or "org" — selects avatar source
Tagline string `yaml:"tagline,omitempty"`
FaviconURL string `yaml:"favicon_url,omitempty"`
}
// HeroConfig represents hero section settings
@@ -159,6 +166,15 @@ type BlogSectionConfig struct {
CTAButton CTAButton `yaml:"cta_button,omitempty"` // "View All Posts" link
}
// NavigationConfig controls which built-in navigation links appear in the header and footer
type NavigationConfig struct {
ShowDocs bool `yaml:"show_docs,omitempty"`
ShowAPI bool `yaml:"show_api,omitempty"`
ShowRepository bool `yaml:"show_repository,omitempty"`
ShowReleases bool `yaml:"show_releases,omitempty"`
ShowIssues bool `yaml:"show_issues,omitempty"`
}
// FooterConfig represents footer settings
type FooterConfig struct {
Links []FooterLink `yaml:"links,omitempty"`
@@ -209,6 +225,14 @@ type UmamiConfig struct {
URL string `yaml:"url,omitempty"`
}
// ExperimentConfig represents A/B testing experiment settings
type ExperimentConfig struct {
Enabled bool `yaml:"enabled,omitempty"`
AutoOptimize bool `yaml:"auto_optimize,omitempty"`
MinImpressions int `yaml:"min_impressions,omitempty"`
ApprovalRequired bool `yaml:"approval_required,omitempty"`
}
// AdvancedConfig represents advanced settings
type AdvancedConfig struct {
CustomCSS string `yaml:"custom_css,omitempty"`
@@ -272,6 +296,11 @@ func DefaultConfig() *LandingConfig {
{Title: "Flexible", Description: "Adapts to your workflow, not the other way around.", Icon: "gear"},
{Title: "Open Source", Description: "Free forever. Community driven.", Icon: "heart"},
},
Navigation: NavigationConfig{
ShowDocs: true,
ShowRepository: true,
ShowReleases: true,
},
CTASection: CTASectionConfig{
Headline: "Ready to get started?",
Subheadline: "Join thousands of developers already using this project.",