Documentation
¶
Index ¶
- Constants
- Variables
- func BadRequest(w http.ResponseWriter, r *http.Request, message string)
- func CORSMiddleware(next http.Handler) http.Handler
- func CrossOriginProtectionMiddleware(next http.Handler) http.Handler
- func DatabaseError(w http.ResponseWriter, r *http.Request, err error)
- func Forbidden(w http.ResponseWriter, r *http.Request, message string)
- func GetMetricsMetadata() map[string]MetricInfo
- func GetRequestID(r *http.Request) string
- func HandlePoolSaturation(w http.ResponseWriter, r *http.Request, err error) bool
- func InternalError(w http.ResponseWriter, r *http.Request, err error)
- func LoggingMiddleware(next http.Handler) http.Handler
- func MethodNotAllowed(w http.ResponseWriter, r *http.Request)
- func NotFound(w http.ResponseWriter, r *http.Request, message string)
- func RequestIDMiddleware(next http.Handler) http.Handler
- func SecurityHeadersMiddleware(next http.Handler) http.Handler
- func ServiceUnavailable(w http.ResponseWriter, r *http.Request, message string)
- func TooManyRequests(w http.ResponseWriter, r *http.Request, message string, ...)
- func Unauthorised(w http.ResponseWriter, r *http.Request, message string)
- func WriteCreated(w http.ResponseWriter, r *http.Request, data any, message string)
- func WriteError(w http.ResponseWriter, r *http.Request, err error, status int, code ErrorCode)
- func WriteErrorMessage(w http.ResponseWriter, r *http.Request, message string, status int, ...)
- func WriteHealthy(w http.ResponseWriter, r *http.Request, service string, version string)
- func WriteJSON(w http.ResponseWriter, r *http.Request, data any, status int)
- func WriteNoContent(w http.ResponseWriter, r *http.Request)
- func WriteSuccess(w http.ResponseWriter, r *http.Request, data any, message string)
- func WriteUnhealthy(w http.ResponseWriter, r *http.Request, service string, err error)
- type AuthProfileUpdateRequest
- type AuthRegisterRequest
- type AuthSessionRequest
- type CreateDomainRequest
- type CreateJobRequest
- type CreateOrganisationRequest
- type DBClient
- type DBInterfaceGA4
- type DomainResponse
- type ErrorCode
- type ErrorResponse
- type ExportColumn
- type GA4APIError
- type GA4Account
- type GA4AccountResponse
- type GA4Client
- func (c *GA4Client) FetchTopPages(ctx context.Context, propertyID string, limit, offset int, ...) ([]PageViewData, error)
- func (c *GA4Client) FetchTopPagesWithRetry(ctx context.Context, propertyID, refreshToken string, limit, offset int, ...) ([]PageViewData, error)
- func (c *GA4Client) RefreshAccessToken(ctx context.Context, refreshToken string) (string, error)
- type GA4Property
- type GoogleConnectionResponse
- type GoogleTokenResponse
- type GoogleUserInfo
- type Handler
- func (h *Handler) AdminResetData(w http.ResponseWriter, r *http.Request)
- func (h *Handler) AdminResetDatabase(w http.ResponseWriter, r *http.Request)
- func (h *Handler) AuthProfile(w http.ResponseWriter, r *http.Request)
- func (h *Handler) AuthRegister(w http.ResponseWriter, r *http.Request)
- func (h *Handler) AuthSession(w http.ResponseWriter, r *http.Request)
- func (h *Handler) DashboardActivity(w http.ResponseWriter, r *http.Request)
- func (h *Handler) DashboardExternalRedirects(w http.ResponseWriter, r *http.Request)
- func (h *Handler) DashboardSlowPages(w http.ResponseWriter, r *http.Request)
- func (h *Handler) DashboardStats(w http.ResponseWriter, r *http.Request)
- func (h *Handler) DatabaseHealthCheck(w http.ResponseWriter, r *http.Request)
- func (h *Handler) DomainsHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) GetAccountProperties(w http.ResponseWriter, r *http.Request, googleAccountID string)
- func (h *Handler) GetActiveOrganisation(w http.ResponseWriter, r *http.Request) string
- func (h *Handler) GetActiveOrganisationWithUser(w http.ResponseWriter, r *http.Request) (*db.User, string, bool)
- func (h *Handler) GoogleConnectionHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) GoogleConnectionsHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) HandleGoogleOAuthCallback(w http.ResponseWriter, r *http.Request)
- func (h *Handler) HandleWebflowOAuthCallback(w http.ResponseWriter, r *http.Request)
- func (h *Handler) HealthCheck(w http.ResponseWriter, r *http.Request)
- func (h *Handler) InitiateGoogleOAuth(w http.ResponseWriter, r *http.Request)
- func (h *Handler) InitiateWebflowOAuth(w http.ResponseWriter, r *http.Request)
- func (h *Handler) JobHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) JobsHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ListGA4Accounts(w http.ResponseWriter, r *http.Request)
- func (h *Handler) MetadataHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) NotificationHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) NotificationsHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) NotificationsReadAllHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) OrganisationInviteAcceptHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) OrganisationInviteHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) OrganisationInvitePreviewHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) OrganisationInvitesHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) OrganisationMemberHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) OrganisationMembersHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) OrganisationPlanHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) OrganisationsHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) PlansHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) RefreshGA4Accounts(w http.ResponseWriter, r *http.Request)
- func (h *Handler) SaveGA4AccountProperties(w http.ResponseWriter, r *http.Request, googleAccountID string)
- func (h *Handler) SaveGoogleProperties(w http.ResponseWriter, r *http.Request)
- func (h *Handler) SaveGoogleProperty(w http.ResponseWriter, r *http.Request)
- func (h *Handler) SchedulerHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) SchedulersHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeAuthCallback(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeAuthModal(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeCliLogin(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeConfigJS(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeDashboard(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeDebugAuth(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeExtensionAuth(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeHomepage(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeInviteWelcome(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeJobDetails(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeNewDashboard(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeSettings(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeSharedJobPage(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeTestComponents(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeTestDataComponents(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeTestLogin(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ServeWelcome(w http.ResponseWriter, r *http.Request)
- func (h *Handler) SetupRoutes(mux *http.ServeMux)
- func (h *Handler) SharedJobHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) SlackConnectionHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) SlackConnectionsHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) SlackOAuthCallback(w http.ResponseWriter, r *http.Request)
- func (h *Handler) SwitchOrganisationHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) UpdateGoogleConnection(w http.ResponseWriter, r *http.Request, connectionID string)
- func (h *Handler) UpdateGooglePropertyStatus(w http.ResponseWriter, r *http.Request, connectionID string)
- func (h *Handler) UsageHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) UsageHistoryHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) WebflowConnectionHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) WebflowConnectionsHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) WebflowSitesHandler(w http.ResponseWriter, r *http.Request)
- func (h *Handler) WebflowWebhook(w http.ResponseWriter, r *http.Request)
- type HealthResponse
- type JobActionRequest
- type JobResponse
- type MetricInfo
- type NotificationResponse
- type NotificationsListResponse
- type OAuthState
- type OrganisationResponse
- type PageViewData
- type PendingGASession
- type ProgressiveFetcher
- type PublicPlan
- type SchedulerRequest
- type SchedulerResponse
- type SlackConnectRequest
- type SlackConnectResponse
- type SlackConnectionResponse
- type SlackLinkUserRequest
- type SlackUpdateNotificationsRequest
- type SlackUserLinkResponse
- type SuccessResponse
- type SwitchOrganisationRequest
- type TaskQueryBuilder
- type TaskQueryParams
- type TaskResponse
- type UpdateAutoPublishRequest
- type UpdateOrganisationMemberRoleRequest
- type UpdateScheduleRequest
- type UserResponse
- type WebflowAuthInfo
- type WebflowConnectionResponse
- type WebflowCustomDomain
- type WebflowSite
- type WebflowSiteSettingResponse
- type WebflowSitesListResponse
- type WebflowSitesResponse
- type WebflowTokenResponse
- type WebflowUserInfo
- type WebflowWebhookPayload
Constants ¶
const ( // GA4InitialBatchSize is the first batch of pages fetched GA4InitialBatchSize = 100 // GA4MediumBatchSize is used for subsequent fetches after the initial batch GA4MediumBatchSize = 1000 // GA4LargeBatchSize is the maximum batch size for bulk fetching // GA4 API supports up to 250,000 rows per request GA4LargeBatchSize = 50000 // GA4MediumBatchThreshold is the offset at which we switch from medium to large batches GA4MediumBatchThreshold = 10000 // Date range lookback periods for analytics queries GA4Lookback7Days = 7 GA4Lookback28Days = 28 GA4Lookback180Days = 180 )
GA4 API limits and constraints
Variables ¶
var Version = "0.4.1"
Version is the current API version (can be set via ldflags at build time)
Functions ¶
func BadRequest ¶
func BadRequest(w http.ResponseWriter, r *http.Request, message string)
BadRequest responds with a 400 Bad Request error
func CORSMiddleware ¶
CORSMiddleware adds CORS headers for browser requests
func CrossOriginProtectionMiddleware ¶
CrossOriginProtectionMiddleware provides protection against CSRF attacks. It is a wrapper around Go's experimental http.CrossOriginProtection.
func DatabaseError ¶
func DatabaseError(w http.ResponseWriter, r *http.Request, err error)
DatabaseError responds with a 500 error for database issues
func Forbidden ¶
func Forbidden(w http.ResponseWriter, r *http.Request, message string)
Forbidden responds with a 403 Forbidden error
func GetMetricsMetadata ¶
func GetMetricsMetadata() map[string]MetricInfo
GetMetricsMetadata returns metadata for all dashboard metrics
func GetRequestID ¶
GetRequestID retrieves the request ID from the request context
func HandlePoolSaturation ¶
HandlePoolSaturation writes a 429 when the error indicates pool exhaustion.
func InternalError ¶
func InternalError(w http.ResponseWriter, r *http.Request, err error)
InternalError responds with a 500 Internal Server Error
func LoggingMiddleware ¶
LoggingMiddleware logs request details and response times
func MethodNotAllowed ¶
func MethodNotAllowed(w http.ResponseWriter, r *http.Request)
MethodNotAllowed responds with a 405 Method Not Allowed error
func NotFound ¶
func NotFound(w http.ResponseWriter, r *http.Request, message string)
NotFound responds with a 404 Not Found error
func RequestIDMiddleware ¶
RequestIDMiddleware adds a unique request ID to each request
func SecurityHeadersMiddleware ¶
SecurityHeadersMiddleware adds security-related headers
func ServiceUnavailable ¶
func ServiceUnavailable(w http.ResponseWriter, r *http.Request, message string)
ServiceUnavailable responds with a 503 Service Unavailable error
func TooManyRequests ¶
func TooManyRequests(w http.ResponseWriter, r *http.Request, message string, retryAfter time.Duration)
TooManyRequests responds with 429 and Retry-After header
func Unauthorised ¶
func Unauthorised(w http.ResponseWriter, r *http.Request, message string)
Unauthorised responds with a 401 Unauthorised error
func WriteCreated ¶
WriteCreated writes a standardised success response for created resources
func WriteError ¶
WriteError writes a standardised error response
func WriteErrorMessage ¶
func WriteErrorMessage(w http.ResponseWriter, r *http.Request, message string, status int, code ErrorCode)
WriteErrorMessage writes a standardised error response with a custom message
func WriteHealthy ¶
WriteHealthy writes a standardised health check response
func WriteNoContent ¶
func WriteNoContent(w http.ResponseWriter, r *http.Request)
WriteNoContent writes a 204 No Content response
func WriteSuccess ¶
WriteSuccess writes a standardised success response
func WriteUnhealthy ¶
WriteUnhealthy writes a standardised unhealthy response
Types ¶
type AuthRegisterRequest ¶
type AuthRegisterRequest struct {
UserID string `json:"user_id"`
Email string `json:"email"`
FirstName *string `json:"first_name,omitempty"`
LastName *string `json:"last_name,omitempty"`
FullName *string `json:"full_name,omitempty"`
OrgName *string `json:"org_name,omitempty"`
}
AuthRegisterRequest represents a user registration request
type AuthSessionRequest ¶
type AuthSessionRequest struct {
Token string `json:"token"`
}
AuthSessionRequest represents a session validation request
type CreateDomainRequest ¶
type CreateDomainRequest struct {
Domain string `json:"domain"`
}
CreateDomainRequest represents the request body for POST /v1/domains
type CreateJobRequest ¶
type CreateJobRequest struct {
Domain string `json:"domain"`
UseSitemap *bool `json:"use_sitemap,omitempty"`
FindLinks *bool `json:"find_links,omitempty"`
Concurrency *int `json:"concurrency,omitempty"`
MaxPages *int `json:"max_pages,omitempty"`
SourceType *string `json:"source_type,omitempty"`
SourceDetail *string `json:"source_detail,omitempty"`
SourceInfo *string `json:"source_info,omitempty"`
}
CreateJobRequest represents the request body for creating a job
type CreateOrganisationRequest ¶
type CreateOrganisationRequest struct {
Name string `json:"name"`
}
CreateOrganisationRequest represents the request to create an organisation
type DBClient ¶
type DBClient interface {
GetDB() *sql.DB
GetOrCreateUser(userID, email string, orgID *string) (*db.User, error)
GetJobStats(organisationID string, startDate, endDate *time.Time) (*db.JobStats, error)
GetJobActivity(organisationID string, startDate, endDate *time.Time) ([]db.ActivityPoint, error)
GetSlowPages(organisationID string, startDate, endDate *time.Time) ([]db.SlowPage, error)
GetExternalRedirects(organisationID string, startDate, endDate *time.Time) ([]db.ExternalRedirect, error)
GetUserByWebhookToken(token string) (*db.User, error)
// Additional methods used by API handlers
GetUser(userID string) (*db.User, error)
UpdateUserNames(userID string, firstName, lastName, fullName *string) error
ResetSchema() error
ResetDataOnly() error
CreateUser(userID, email string, firstName, lastName, fullName *string, orgName string) (*db.User, *db.Organisation, error)
GetOrganisation(organisationID string) (*db.Organisation, error)
ListJobs(organisationID string, limit, offset int, status, dateRange, timezone string) ([]db.JobWithDomain, int, error)
ListJobsWithOffset(organisationID string, limit, offset int, status, dateRange string, tzOffsetMinutes int, includeStats bool) ([]db.JobWithDomain, int, error)
// Scheduler methods
CreateScheduler(ctx context.Context, scheduler *db.Scheduler) error
GetScheduler(ctx context.Context, schedulerID string) (*db.Scheduler, error)
ListSchedulers(ctx context.Context, organisationID string) ([]*db.Scheduler, error)
UpdateScheduler(ctx context.Context, schedulerID string, updates *db.Scheduler, expectedIsEnabled *bool) error
DeleteScheduler(ctx context.Context, schedulerID string) error
GetSchedulersReadyToRun(ctx context.Context, limit int) ([]*db.Scheduler, error)
UpdateSchedulerNextRun(ctx context.Context, schedulerID string, nextRun time.Time) error
GetLastJobStartTimeForScheduler(ctx context.Context, schedulerID string) (*time.Time, error)
GetDomainNameByID(ctx context.Context, domainID int) (string, error)
GetDomainNames(ctx context.Context, domainIDs []int) (map[int]string, error)
// Organisation membership methods
ListUserOrganisations(userID string) ([]db.UserOrganisation, error)
ValidateOrganisationMembership(userID, organisationID string) (bool, error)
SetActiveOrganisation(userID, organisationID string) error
GetEffectiveOrganisationID(user *db.User) string
GetOrganisationMemberRole(ctx context.Context, userID, organisationID string) (string, error)
ListOrganisationMembers(ctx context.Context, organisationID string) ([]db.OrganisationMember, error)
IsOrganisationMemberEmail(ctx context.Context, organisationID, email string) (bool, error)
RemoveOrganisationMember(ctx context.Context, userID, organisationID string) error
UpdateOrganisationMemberRole(ctx context.Context, userID, organisationID, role string) error
CountOrganisationAdmins(ctx context.Context, organisationID string) (int, error)
// Organisation management methods
CreateOrganisation(name string) (*db.Organisation, error)
AddOrganisationMember(userID, organisationID, role string) error
CreateOrganisationInvite(ctx context.Context, invite *db.OrganisationInvite) (*db.OrganisationInvite, error)
ListOrganisationInvites(ctx context.Context, organisationID string) ([]db.OrganisationInvite, error)
RevokeOrganisationInvite(ctx context.Context, inviteID, organisationID string) error
GetOrganisationInviteByToken(ctx context.Context, token string) (*db.OrganisationInvite, error)
AcceptOrganisationInvite(ctx context.Context, token, userID string) (*db.OrganisationInvite, error)
SetOrganisationPlan(ctx context.Context, organisationID, planID string) error
GetOrganisationPlanID(ctx context.Context, organisationID string) (string, error)
ListDailyUsage(ctx context.Context, organisationID string, startDate, endDate time.Time) ([]db.DailyUsageEntry, error)
// Slack integration methods
CreateSlackConnection(ctx context.Context, conn *db.SlackConnection) error
GetSlackConnection(ctx context.Context, connectionID string) (*db.SlackConnection, error)
ListSlackConnections(ctx context.Context, organisationID string) ([]*db.SlackConnection, error)
DeleteSlackConnection(ctx context.Context, connectionID, organisationID string) error
CreateSlackUserLink(ctx context.Context, link *db.SlackUserLink) error
GetSlackUserLink(ctx context.Context, userID, connectionID string) (*db.SlackUserLink, error)
UpdateSlackUserLinkNotifications(ctx context.Context, userID, connectionID string, dmNotifications bool) error
DeleteSlackUserLink(ctx context.Context, userID, connectionID string) error
StoreSlackToken(ctx context.Context, connectionID, token string) error
GetSlackToken(ctx context.Context, connectionID string) (string, error)
// Notification methods
ListNotifications(ctx context.Context, organisationID string, limit, offset int, unreadOnly bool) ([]*db.Notification, int, error)
GetUnreadNotificationCount(ctx context.Context, organisationID string) (int, error)
MarkNotificationRead(ctx context.Context, notificationID, organisationID string) error
MarkAllNotificationsRead(ctx context.Context, organisationID string) error
// Webflow integration methods
CreateWebflowConnection(ctx context.Context, conn *db.WebflowConnection) error
GetWebflowConnection(ctx context.Context, connectionID string) (*db.WebflowConnection, error)
ListWebflowConnections(ctx context.Context, organisationID string) ([]*db.WebflowConnection, error)
DeleteWebflowConnection(ctx context.Context, connectionID, organisationID string) error
StoreWebflowToken(ctx context.Context, connectionID, token string) error
GetWebflowToken(ctx context.Context, connectionID string) (string, error)
// Google Analytics integration methods
CreateGoogleConnection(ctx context.Context, conn *db.GoogleAnalyticsConnection) error
GetGoogleConnection(ctx context.Context, connectionID string) (*db.GoogleAnalyticsConnection, error)
ListGoogleConnections(ctx context.Context, organisationID string) ([]*db.GoogleAnalyticsConnection, error)
DeleteGoogleConnection(ctx context.Context, connectionID, organisationID string) error
UpdateGoogleConnectionStatus(ctx context.Context, connectionID, organisationID, status string) error
StoreGoogleToken(ctx context.Context, connectionID, refreshToken string) error
GetGoogleToken(ctx context.Context, connectionID string) (string, error)
GetActiveGAConnectionForOrganisation(ctx context.Context, orgID string) (*db.GoogleAnalyticsConnection, error)
GetActiveGAConnectionForDomain(ctx context.Context, organisationID string, domainID int) (*db.GoogleAnalyticsConnection, error)
GetDomainsForOrganisation(ctx context.Context, organisationID string) ([]db.OrganisationDomain, error)
UpdateConnectionLastSync(ctx context.Context, connectionID string) error
UpdateConnectionDomains(ctx context.Context, connectionID string, domainIDs []int) error
MarkConnectionInactive(ctx context.Context, connectionID, reason string) error
UpsertPageWithAnalytics(ctx context.Context, organisationID string, domainID int, path string, pageViews map[string]int64, connectionID string) (int, error)
CalculateTrafficScores(ctx context.Context, organisationID string, domainID int) error
ApplyTrafficScoresToTasks(ctx context.Context, organisationID string, domainID int) error
GetOrCreateDomainID(ctx context.Context, domain string) (int, error)
UpsertOrganisationDomain(ctx context.Context, organisationID string, domainID int) error
// Google Analytics accounts methods (for persistent account storage)
UpsertGA4Account(ctx context.Context, account *db.GoogleAnalyticsAccount) error
ListGA4Accounts(ctx context.Context, organisationID string) ([]*db.GoogleAnalyticsAccount, error)
GetGA4Account(ctx context.Context, accountID string) (*db.GoogleAnalyticsAccount, error)
GetGA4AccountByGoogleID(ctx context.Context, organisationID, googleAccountID string) (*db.GoogleAnalyticsAccount, error)
StoreGA4AccountToken(ctx context.Context, accountID, refreshToken string) error
GetGA4AccountToken(ctx context.Context, accountID string) (string, error)
GetGA4AccountWithToken(ctx context.Context, organisationID string) (*db.GoogleAnalyticsAccount, error)
GetGAConnectionWithToken(ctx context.Context, organisationID string) (*db.GoogleAnalyticsConnection, error)
// Platform integration mappings
UpsertPlatformOrgMapping(ctx context.Context, mapping *db.PlatformOrgMapping) error
GetPlatformOrgMapping(ctx context.Context, platform, platformID string) (*db.PlatformOrgMapping, error)
// Usage and plans methods
GetOrganisationUsageStats(ctx context.Context, orgID string) (*db.UsageStats, error)
GetActivePlans(ctx context.Context) ([]db.Plan, error)
// Webflow site settings methods
CreateOrUpdateSiteSetting(ctx context.Context, setting *db.WebflowSiteSetting) error
GetSiteSetting(ctx context.Context, organisationID, webflowSiteID string) (*db.WebflowSiteSetting, error)
GetSiteSettingByID(ctx context.Context, id string) (*db.WebflowSiteSetting, error)
ListConfiguredSiteSettings(ctx context.Context, organisationID string) ([]*db.WebflowSiteSetting, error)
ListAllSiteSettings(ctx context.Context, organisationID string) ([]*db.WebflowSiteSetting, error)
ListSiteSettingsByConnection(ctx context.Context, connectionID string) ([]*db.WebflowSiteSetting, error)
UpdateSiteSchedule(ctx context.Context, organisationID, webflowSiteID string, scheduleIntervalHours *int, schedulerID string) error
UpdateSiteAutoPublish(ctx context.Context, organisationID, webflowSiteID string, enabled bool, webhookID string) error
DeleteSiteSetting(ctx context.Context, organisationID, webflowSiteID string) error
DeleteSiteSettingsByConnection(ctx context.Context, connectionID string) error
}
DBClient is an interface for database operations
type DBInterfaceGA4 ¶
type DBInterfaceGA4 interface {
GetActiveGAConnectionForDomain(ctx context.Context, organisationID string, domainID int) (*db.GoogleAnalyticsConnection, error)
GetDomainNameByID(ctx context.Context, domainID int) (string, error)
GetGoogleToken(ctx context.Context, connectionID string) (string, error)
UpdateConnectionLastSync(ctx context.Context, connectionID string) error
MarkConnectionInactive(ctx context.Context, connectionID, reason string) error
UpsertPageWithAnalytics(ctx context.Context, organisationID string, domainID int, path string, pageViews map[string]int64, connectionID string) (int, error)
CalculateTrafficScores(ctx context.Context, organisationID string, domainID int) error
ApplyTrafficScoresToTasks(ctx context.Context, organisationID string, domainID int) error
}
DBInterfaceGA4 defines the database operations needed by the progressive fetcher
type DomainResponse ¶
DomainResponse represents a domain in API responses
type ErrorCode ¶
type ErrorCode string
ErrorCode represents standard error codes
const ( // Client errors (4xx) ErrCodeBadRequest ErrorCode = "BAD_REQUEST" ErrCodeForbidden ErrorCode = "FORBIDDEN" ErrCodeNotFound ErrorCode = "NOT_FOUND" ErrCodeMethodNotAllowed ErrorCode = "METHOD_NOT_ALLOWED" ErrCodeConflict ErrorCode = "CONFLICT" ErrCodeValidation ErrorCode = "VALIDATION_ERROR" ErrCodeRateLimit ErrorCode = "RATE_LIMIT_EXCEEDED" // Server errors (5xx) ErrCodeInternal ErrorCode = "INTERNAL_ERROR" ErrCodeDatabaseError ErrorCode = "DATABASE_ERROR" )
type ErrorResponse ¶
type ErrorResponse struct {
Status int `json:"status"`
Message string `json:"message"`
Code string `json:"code,omitempty"`
RequestID string `json:"request_id,omitempty"`
}
ErrorResponse represents a standardised error response
type ExportColumn ¶
ExportColumn describes a column in exported task datasets
type GA4APIError ¶
GA4APIError represents a non-200 response from the GA4 Data API.
func (*GA4APIError) Error ¶
func (err *GA4APIError) Error() string
func (*GA4APIError) IsUnauthorised ¶
func (err *GA4APIError) IsUnauthorised() bool
type GA4Account ¶
type GA4Account struct {
AccountID string `json:"account_id"`
DisplayName string `json:"display_name"`
}
GA4Account represents a Google Analytics account
type GA4AccountResponse ¶
type GA4AccountResponse struct {
ID string `json:"id"`
GoogleAccountID string `json:"google_account_id"`
GoogleAccountName string `json:"google_account_name,omitempty"`
GoogleEmail string `json:"google_email,omitempty"`
HasToken bool `json:"has_token"`
CreatedAt string `json:"created_at"`
}
GA4AccountResponse represents a Google Analytics account in API responses
type GA4Client ¶
type GA4Client struct {
// contains filtered or unexported fields
}
GA4Client is an HTTP client for the Google Analytics 4 Data API
func NewGA4Client ¶
NewGA4Client creates a new GA4 Data API client
func (*GA4Client) FetchTopPages ¶
func (c *GA4Client) FetchTopPages(ctx context.Context, propertyID string, limit, offset int, allowedHostnames []string) ([]PageViewData, error)
FetchTopPages fetches top N pages ordered by screenPageViews descending Returns page data for 7-day, 28-day, and 180-day lookback periods Makes 3 separate API calls and merges results by path
func (*GA4Client) FetchTopPagesWithRetry ¶
func (c *GA4Client) FetchTopPagesWithRetry(ctx context.Context, propertyID, refreshToken string, limit, offset int, allowedHostnames []string) ([]PageViewData, error)
FetchTopPagesWithRetry fetches top pages with automatic token refresh on 401
type GA4Property ¶
type GA4Property struct {
PropertyID string `json:"property_id"` // e.g., "123456789"
DisplayName string `json:"display_name"` // e.g., "My Website"
PropertyType string `json:"property_type"` // e.g., "PROPERTY_TYPE_ORDINARY"
}
GA4Property represents a Google Analytics 4 property
type GoogleConnectionResponse ¶
type GoogleConnectionResponse struct {
ID string `json:"id"`
GA4PropertyID string `json:"ga4_property_id,omitempty"`
GA4PropertyName string `json:"ga4_property_name,omitempty"`
GoogleAccountName string `json:"google_account_name,omitempty"`
GoogleEmail string `json:"google_email,omitempty"`
Status string `json:"status"`
DomainIDs pq.Int64Array `json:"domain_ids,omitempty"`
CreatedAt string `json:"created_at"`
}
GoogleConnectionResponse represents a Google Analytics connection in API responses
type GoogleTokenResponse ¶
type GoogleTokenResponse struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
ExpiresIn int `json:"expires_in"`
TokenType string `json:"token_type"`
Scope string `json:"scope"`
}
GoogleTokenResponse represents the response from Google's token endpoint
type GoogleUserInfo ¶
type GoogleUserInfo struct {
ID string `json:"id"`
Email string `json:"email"`
Name string `json:"name"`
}
GoogleUserInfo contains user info from Google
type Handler ¶
type Handler struct {
DB DBClient
JobsManager jobs.JobManagerInterface
Loops *loops.Client
GoogleClientID string
GoogleClientSecret string
}
Handler holds dependencies for API handlers
func NewHandler ¶
func NewHandler(pgDB DBClient, jobsManager jobs.JobManagerInterface, loopsClient *loops.Client, googleClientID, googleClientSecret string) *Handler
NewHandler creates a new API handler with dependencies
func (*Handler) AdminResetData ¶
func (h *Handler) AdminResetData(w http.ResponseWriter, r *http.Request)
AdminResetData handles the admin data-only reset endpoint Clears all data but preserves schema - safe option for clearing test data
func (*Handler) AdminResetDatabase ¶
func (h *Handler) AdminResetDatabase(w http.ResponseWriter, r *http.Request)
AdminResetDatabase handles the admin database reset endpoint Requires valid JWT with admin role and explicit environment enablement
func (*Handler) AuthProfile ¶
func (h *Handler) AuthProfile(w http.ResponseWriter, r *http.Request)
AuthProfile handles GET/PATCH /v1/auth/profile
func (*Handler) AuthRegister ¶
func (h *Handler) AuthRegister(w http.ResponseWriter, r *http.Request)
AuthRegister handles POST /v1/auth/register
func (*Handler) AuthSession ¶
func (h *Handler) AuthSession(w http.ResponseWriter, r *http.Request)
AuthSession handles POST /v1/auth/session
func (*Handler) DashboardActivity ¶
func (h *Handler) DashboardActivity(w http.ResponseWriter, r *http.Request)
DashboardActivity handles dashboard activity chart requests
func (*Handler) DashboardExternalRedirects ¶
func (h *Handler) DashboardExternalRedirects(w http.ResponseWriter, r *http.Request)
DashboardExternalRedirects handles requests for external redirect analysis
func (*Handler) DashboardSlowPages ¶
func (h *Handler) DashboardSlowPages(w http.ResponseWriter, r *http.Request)
DashboardSlowPages handles requests for slow-loading pages analysis
func (*Handler) DashboardStats ¶
func (h *Handler) DashboardStats(w http.ResponseWriter, r *http.Request)
DashboardStats handles dashboard statistics requests
func (*Handler) DatabaseHealthCheck ¶
func (h *Handler) DatabaseHealthCheck(w http.ResponseWriter, r *http.Request)
DatabaseHealthCheck handles database health check requests
func (*Handler) DomainsHandler ¶
func (h *Handler) DomainsHandler(w http.ResponseWriter, r *http.Request)
DomainsHandler handles requests to /v1/domains
func (*Handler) GetAccountProperties ¶
func (h *Handler) GetAccountProperties(w http.ResponseWriter, r *http.Request, googleAccountID string)
GetAccountProperties fetches properties for a Google account using stored refresh token GET /v1/integrations/google/accounts/{googleAccountId}/properties
func (*Handler) GetActiveOrganisation ¶
GetActiveOrganisation validates and returns the active organisation ID for the current user. It writes an error response and returns an empty string if authentication fails or the user doesn't belong to an organisation.
func (*Handler) GetActiveOrganisationWithUser ¶
func (h *Handler) GetActiveOrganisationWithUser(w http.ResponseWriter, r *http.Request) (*db.User, string, bool)
GetActiveOrganisationWithUser validates and returns both the user and active organisation ID. It writes an error response and returns nil, "", false if authentication fails.
func (*Handler) GoogleConnectionHandler ¶
func (h *Handler) GoogleConnectionHandler(w http.ResponseWriter, r *http.Request)
GoogleConnectionHandler handles requests to /v1/integrations/google/:id
func (*Handler) GoogleConnectionsHandler ¶
func (h *Handler) GoogleConnectionsHandler(w http.ResponseWriter, r *http.Request)
GoogleConnectionsHandler handles requests to /v1/integrations/google
func (*Handler) HandleGoogleOAuthCallback ¶
func (h *Handler) HandleGoogleOAuthCallback(w http.ResponseWriter, r *http.Request)
HandleGoogleOAuthCallback processes the OAuth callback from Google After successful auth, it fetches the user's GA4 properties and returns them
func (*Handler) HandleWebflowOAuthCallback ¶
func (h *Handler) HandleWebflowOAuthCallback(w http.ResponseWriter, r *http.Request)
HandleWebflowOAuthCallback processes the OAuth callback from Webflow
func (*Handler) HealthCheck ¶
func (h *Handler) HealthCheck(w http.ResponseWriter, r *http.Request)
HealthCheck handles basic health check requests
func (*Handler) InitiateGoogleOAuth ¶
func (h *Handler) InitiateGoogleOAuth(w http.ResponseWriter, r *http.Request)
InitiateGoogleOAuth starts the OAuth flow
func (*Handler) InitiateWebflowOAuth ¶
func (h *Handler) InitiateWebflowOAuth(w http.ResponseWriter, r *http.Request)
InitiateWebflowOAuth starts the OAuth flow
func (*Handler) JobHandler ¶
func (h *Handler) JobHandler(w http.ResponseWriter, r *http.Request)
JobHandler handles requests to /v1/jobs/:id
func (*Handler) JobsHandler ¶
func (h *Handler) JobsHandler(w http.ResponseWriter, r *http.Request)
JobsHandler handles requests to /v1/jobs
func (*Handler) ListGA4Accounts ¶
func (h *Handler) ListGA4Accounts(w http.ResponseWriter, r *http.Request)
ListGA4Accounts returns stored GA4 accounts from the database GET /v1/integrations/google/accounts
func (*Handler) MetadataHandler ¶
func (h *Handler) MetadataHandler(w http.ResponseWriter, r *http.Request)
MetadataHandler handles GET /v1/metadata/metrics
func (*Handler) NotificationHandler ¶
func (h *Handler) NotificationHandler(w http.ResponseWriter, r *http.Request)
NotificationHandler handles requests to /v1/notifications/{id}
func (*Handler) NotificationsHandler ¶
func (h *Handler) NotificationsHandler(w http.ResponseWriter, r *http.Request)
NotificationsHandler handles requests to /v1/notifications
func (*Handler) NotificationsReadAllHandler ¶
func (h *Handler) NotificationsReadAllHandler(w http.ResponseWriter, r *http.Request)
NotificationsReadAllHandler handles POST /v1/notifications/read-all
func (*Handler) OrganisationInviteAcceptHandler ¶
func (h *Handler) OrganisationInviteAcceptHandler(w http.ResponseWriter, r *http.Request)
OrganisationInviteAcceptHandler handles POST /v1/organisations/invites/accept
func (*Handler) OrganisationInviteHandler ¶
func (h *Handler) OrganisationInviteHandler(w http.ResponseWriter, r *http.Request)
OrganisationInviteHandler handles DELETE /v1/organisations/invites/:id
func (*Handler) OrganisationInvitePreviewHandler ¶
func (h *Handler) OrganisationInvitePreviewHandler(w http.ResponseWriter, r *http.Request)
OrganisationInvitePreviewHandler handles GET /v1/organisations/invites/preview?token=... It is intentionally public so invite recipients can see who invited them before authentication.
func (*Handler) OrganisationInvitesHandler ¶
func (h *Handler) OrganisationInvitesHandler(w http.ResponseWriter, r *http.Request)
OrganisationInvitesHandler handles GET/POST /v1/organisations/invites
func (*Handler) OrganisationMemberHandler ¶
func (h *Handler) OrganisationMemberHandler(w http.ResponseWriter, r *http.Request)
OrganisationMemberHandler handles PATCH/DELETE /v1/organisations/members/:id
func (*Handler) OrganisationMembersHandler ¶
func (h *Handler) OrganisationMembersHandler(w http.ResponseWriter, r *http.Request)
OrganisationMembersHandler handles GET /v1/organisations/members
func (*Handler) OrganisationPlanHandler ¶
func (h *Handler) OrganisationPlanHandler(w http.ResponseWriter, r *http.Request)
OrganisationPlanHandler handles PUT /v1/organisations/plan
func (*Handler) OrganisationsHandler ¶
func (h *Handler) OrganisationsHandler(w http.ResponseWriter, r *http.Request)
OrganisationsHandler handles GET and POST /v1/organisations
func (*Handler) PlansHandler ¶
func (h *Handler) PlansHandler(w http.ResponseWriter, r *http.Request)
PlansHandler handles GET /v1/plans Returns available subscription plans (public endpoint for pricing page)
func (*Handler) RefreshGA4Accounts ¶
func (h *Handler) RefreshGA4Accounts(w http.ResponseWriter, r *http.Request)
RefreshGA4Accounts syncs accounts from Google API and updates the database POST /v1/integrations/google/accounts/refresh
func (*Handler) SaveGA4AccountProperties ¶
func (h *Handler) SaveGA4AccountProperties(w http.ResponseWriter, r *http.Request, googleAccountID string)
SaveGA4AccountProperties saves all properties for a stored GA4 account as inactive POST /v1/integrations/google/accounts/{googleAccountId}/save-properties
func (*Handler) SaveGoogleProperties ¶
func (h *Handler) SaveGoogleProperties(w http.ResponseWriter, r *http.Request)
SaveGoogleProperties saves all properties from a session, with specified ones marked as active
func (*Handler) SaveGoogleProperty ¶
func (h *Handler) SaveGoogleProperty(w http.ResponseWriter, r *http.Request)
SaveGoogleProperty saves the selected GA4 property
func (*Handler) SchedulerHandler ¶
func (h *Handler) SchedulerHandler(w http.ResponseWriter, r *http.Request)
SchedulerHandler handles requests to /v1/schedulers/:id
func (*Handler) SchedulersHandler ¶
func (h *Handler) SchedulersHandler(w http.ResponseWriter, r *http.Request)
SchedulersHandler handles requests to /v1/schedulers
func (*Handler) ServeAuthCallback ¶
func (h *Handler) ServeAuthCallback(w http.ResponseWriter, r *http.Request)
ServeAuthCallback serves the OAuth callback bridge page.
func (*Handler) ServeAuthModal ¶
func (h *Handler) ServeAuthModal(w http.ResponseWriter, r *http.Request)
ServeAuthModal serves the shared authentication modal
func (*Handler) ServeCliLogin ¶
func (h *Handler) ServeCliLogin(w http.ResponseWriter, r *http.Request)
ServeCliLogin serves the CLI login page for browser-based auth flows
func (*Handler) ServeConfigJS ¶
func (h *Handler) ServeConfigJS(w http.ResponseWriter, r *http.Request)
ServeConfigJS exposes Supabase configuration to static pages
func (*Handler) ServeDashboard ¶
func (h *Handler) ServeDashboard(w http.ResponseWriter, r *http.Request)
ServeDashboard serves the dashboard page
func (*Handler) ServeDebugAuth ¶
func (h *Handler) ServeDebugAuth(w http.ResponseWriter, r *http.Request)
ServeDebugAuth serves the debug auth test page
func (*Handler) ServeExtensionAuth ¶
func (h *Handler) ServeExtensionAuth(w http.ResponseWriter, r *http.Request)
ServeExtensionAuth serves the extension auth popup bridge page.
func (*Handler) ServeHomepage ¶
func (h *Handler) ServeHomepage(w http.ResponseWriter, r *http.Request)
ServeHomepage serves the marketing homepage
func (*Handler) ServeInviteWelcome ¶
func (h *Handler) ServeInviteWelcome(w http.ResponseWriter, r *http.Request)
ServeInviteWelcome serves the invite welcome page.
func (*Handler) ServeJobDetails ¶
func (h *Handler) ServeJobDetails(w http.ResponseWriter, r *http.Request)
ServeJobDetails serves the standalone job details page
func (*Handler) ServeNewDashboard ¶
func (h *Handler) ServeNewDashboard(w http.ResponseWriter, r *http.Request)
ServeNewDashboard serves the new Web Components dashboard page
func (*Handler) ServeSettings ¶
func (h *Handler) ServeSettings(w http.ResponseWriter, r *http.Request)
ServeSettings serves the settings page
func (*Handler) ServeSharedJobPage ¶
func (h *Handler) ServeSharedJobPage(w http.ResponseWriter, r *http.Request)
ServeSharedJobPage serves the public shared job view
func (*Handler) ServeTestComponents ¶
func (h *Handler) ServeTestComponents(w http.ResponseWriter, r *http.Request)
ServeTestComponents serves the Web Components test page
func (*Handler) ServeTestDataComponents ¶
func (h *Handler) ServeTestDataComponents(w http.ResponseWriter, r *http.Request)
ServeTestDataComponents serves the data components test page
func (*Handler) ServeTestLogin ¶
func (h *Handler) ServeTestLogin(w http.ResponseWriter, r *http.Request)
ServeTestLogin serves the test login page
func (*Handler) ServeWelcome ¶
func (h *Handler) ServeWelcome(w http.ResponseWriter, r *http.Request)
ServeWelcome serves the post-sign-in welcome page.
func (*Handler) SetupRoutes ¶
SetupRoutes configures all API routes with proper middleware
func (*Handler) SharedJobHandler ¶
func (h *Handler) SharedJobHandler(w http.ResponseWriter, r *http.Request)
func (*Handler) SlackConnectionHandler ¶
func (h *Handler) SlackConnectionHandler(w http.ResponseWriter, r *http.Request)
SlackConnectionHandler handles requests to /v1/integrations/slack/:id and sub-routes
func (*Handler) SlackConnectionsHandler ¶
func (h *Handler) SlackConnectionsHandler(w http.ResponseWriter, r *http.Request)
SlackConnectionsHandler handles requests to /v1/integrations/slack
func (*Handler) SlackOAuthCallback ¶
func (h *Handler) SlackOAuthCallback(w http.ResponseWriter, r *http.Request)
SlackOAuthCallback handles the OAuth callback (no auth middleware)
func (*Handler) SwitchOrganisationHandler ¶
func (h *Handler) SwitchOrganisationHandler(w http.ResponseWriter, r *http.Request)
SwitchOrganisationHandler handles POST /v1/organisations/switch
func (*Handler) UpdateGoogleConnection ¶
func (h *Handler) UpdateGoogleConnection(w http.ResponseWriter, r *http.Request, connectionID string)
UpdateGoogleConnection updates domain mappings for an existing connection PATCH /v1/integrations/google/{id}
func (*Handler) UpdateGooglePropertyStatus ¶
func (h *Handler) UpdateGooglePropertyStatus(w http.ResponseWriter, r *http.Request, connectionID string)
UpdateGooglePropertyStatus updates the status of a Google Analytics connection
func (*Handler) UsageHandler ¶
func (h *Handler) UsageHandler(w http.ResponseWriter, r *http.Request)
UsageHandler handles GET /v1/usage Returns current usage statistics for the user's active organisation
func (*Handler) UsageHistoryHandler ¶
func (h *Handler) UsageHistoryHandler(w http.ResponseWriter, r *http.Request)
UsageHistoryHandler handles GET /v1/usage/history
func (*Handler) WebflowConnectionHandler ¶
func (h *Handler) WebflowConnectionHandler(w http.ResponseWriter, r *http.Request)
WebflowConnectionHandler handles requests to /v1/integrations/webflow/:id
func (*Handler) WebflowConnectionsHandler ¶
func (h *Handler) WebflowConnectionsHandler(w http.ResponseWriter, r *http.Request)
WebflowConnectionsHandler handles requests to /v1/integrations/webflow
func (*Handler) WebflowSitesHandler ¶
func (h *Handler) WebflowSitesHandler(w http.ResponseWriter, r *http.Request)
WebflowSitesHandler handles requests to /v1/integrations/webflow/{connection_id}/sites
func (*Handler) WebflowWebhook ¶
func (h *Handler) WebflowWebhook(w http.ResponseWriter, r *http.Request)
WebflowWebhook handles Webflow site publish webhooks
type HealthResponse ¶
type HealthResponse struct {
Status string `json:"status"`
Timestamp string `json:"timestamp"`
Service string `json:"service"`
Version string `json:"version,omitempty"`
}
HealthResponse represents a health check response
type JobActionRequest ¶
type JobActionRequest struct {
Action string `json:"action"`
}
JobActionRequest represents actions that can be performed on jobs
type JobResponse ¶
type JobResponse struct {
ID string `json:"id"`
DomainID int `json:"domain_id"`
Domain string `json:"domain"`
Status string `json:"status"`
TotalTasks int `json:"total_tasks"`
CompletedTasks int `json:"completed_tasks"`
FailedTasks int `json:"failed_tasks"`
SkippedTasks int `json:"skipped_tasks"`
Progress float64 `json:"progress"`
CreatedAt string `json:"created_at"`
StartedAt *string `json:"started_at,omitempty"`
CompletedAt *string `json:"completed_at,omitempty"`
// Additional fields for dashboard
DurationSeconds *int `json:"duration_seconds,omitempty"`
AvgTimePerTaskSeconds *float64 `json:"avg_time_per_task_seconds,omitempty"`
Stats map[string]any `json:"stats,omitempty"`
SchedulerID *string `json:"scheduler_id,omitempty"`
// Job configuration fields
Concurrency int `json:"concurrency"`
MaxPages int `json:"max_pages"`
SourceType *string `json:"source_type,omitempty"`
CrawlDelaySeconds *int `json:"crawl_delay_seconds,omitempty"`
AdaptiveDelaySeconds int `json:"adaptive_delay_seconds"`
}
JobResponse represents a job in API responses
type MetricInfo ¶
type MetricInfo struct {
Name string `json:"name"`
Description string `json:"description"`
InfoHTML string `json:"info_html"`
}
MetricInfo represents metadata about a metric
type NotificationResponse ¶
type NotificationResponse struct {
ID string `json:"id"`
Type string `json:"type"`
Subject string `json:"subject"`
Preview string `json:"preview"`
Message string `json:"message,omitempty"`
Link string `json:"link,omitempty"`
ReadAt *time.Time `json:"read_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
NotificationResponse is the JSON response for a notification
type NotificationsListResponse ¶
type NotificationsListResponse struct {
Notifications []NotificationResponse `json:"notifications"`
Total int `json:"total"`
UnreadCount int `json:"unread_count"`
}
NotificationsListResponse is the JSON response for listing notifications
type OAuthState ¶
type OAuthState struct {
UserID string `json:"u"`
OrgID string `json:"o"`
Timestamp int64 `json:"t"`
Nonce string `json:"n"`
}
OAuthState contains signed state data for CSRF protection Shared between Slack and Webflow
type OrganisationResponse ¶
type OrganisationResponse struct {
ID string `json:"id"`
Name string `json:"name"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
OrganisationResponse represents an organisation in API responses
type PageViewData ¶
type PageViewData struct {
HostName string
PagePath string
PageViews7d int64
PageViews28d int64
PageViews180d int64
}
PageViewData represents analytics data for a single page
type PendingGASession ¶
type PendingGASession struct {
Accounts []GA4Account // Accounts fetched during OAuth
Properties []GA4Property // Properties fetched when account selected (optional, for backwards compat)
RefreshToken string
AccessToken string
State string
UserID string
Email string
OrgID string // Organisation ID from OAuth state
ExpiresAt time.Time
}
PendingGASession stores OAuth data temporarily until user completes account/property selection
type ProgressiveFetcher ¶
type ProgressiveFetcher struct {
// contains filtered or unexported fields
}
ProgressiveFetcher orchestrates GA4 data fetching in multiple phases
func NewProgressiveFetcher ¶
func NewProgressiveFetcher(database DBInterfaceGA4, clientID, clientSecret string) *ProgressiveFetcher
NewProgressiveFetcher creates a new progressive fetcher instance
func (*ProgressiveFetcher) FetchAndUpdatePages ¶
func (pf *ProgressiveFetcher) FetchAndUpdatePages(ctx context.Context, organisationID string, domainID int) error
FetchAndUpdatePages fetches GA4 data in 3 phases and updates the pages table Phase 1 is blocking (top 100 pages), phases 2-3 run in background goroutines
type PublicPlan ¶
type PublicPlan struct {
ID string `json:"id"`
Name string `json:"name"`
DisplayName string `json:"display_name"`
DailyPageLimit int `json:"daily_page_limit"`
MonthlyPriceCents int `json:"monthly_price_cents"`
}
PublicPlan is a DTO for the public /v1/plans endpoint Excludes internal metadata fields (is_active, sort_order, created_at)
type SchedulerRequest ¶
type SchedulerRequest struct {
Domain string `json:"domain"` // Only used for creation, not update
ScheduleIntervalHours *int `json:"schedule_interval_hours,omitempty"` // Pointer for explicit optional updates
Concurrency *int `json:"concurrency,omitempty"`
FindLinks *bool `json:"find_links,omitempty"`
MaxPages *int `json:"max_pages,omitempty"`
IncludePaths []string `json:"include_paths,omitempty"`
ExcludePaths []string `json:"exclude_paths,omitempty"`
IsEnabled *bool `json:"is_enabled,omitempty"`
ExpectedIsEnabled *bool `json:"expected_is_enabled,omitempty"` // Optional optimistic concurrency hint
}
SchedulerRequest represents the request body for creating/updating a scheduler
type SchedulerResponse ¶
type SchedulerResponse struct {
ID string `json:"id"`
Domain string `json:"domain"`
ScheduleIntervalHours int `json:"schedule_interval_hours"`
NextRunAt string `json:"next_run_at"`
IsEnabled bool `json:"is_enabled"`
Concurrency int `json:"concurrency"`
FindLinks bool `json:"find_links"`
MaxPages int `json:"max_pages"`
IncludePaths []string `json:"include_paths,omitempty"`
ExcludePaths []string `json:"exclude_paths,omitempty"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
SchedulerResponse represents a scheduler in API responses
type SlackConnectRequest ¶
type SlackConnectRequest struct {
RedirectURI string `json:"redirect_uri,omitempty"`
}
SlackConnectRequest represents the request to initiate OAuth
type SlackConnectResponse ¶
type SlackConnectResponse struct {
AuthURL string `json:"auth_url"`
}
SlackConnectResponse returns the OAuth URL to redirect to
type SlackConnectionResponse ¶
type SlackConnectionResponse struct {
ID string `json:"id"`
WorkspaceID string `json:"workspace_id"`
WorkspaceName string `json:"workspace_name"`
CreatedAt string `json:"created_at"`
}
SlackConnectionResponse represents a Slack connection in API responses
type SlackLinkUserRequest ¶
type SlackLinkUserRequest struct {
ConnectionID string `json:"connection_id"`
SlackUserID string `json:"slack_user_id,omitempty"` // Optional if using email match
DMNotifications bool `json:"dm_notifications"`
}
SlackLinkUserRequest represents the request to link a Slack user
type SlackUpdateNotificationsRequest ¶
type SlackUpdateNotificationsRequest struct {
DMNotifications bool `json:"dm_notifications"`
}
SlackUpdateNotificationsRequest updates notification preferences
type SlackUserLinkResponse ¶
type SlackUserLinkResponse struct {
ID string `json:"id"`
SlackUserID string `json:"slack_user_id"`
DMNotifications bool `json:"dm_notifications"`
CreatedAt string `json:"created_at"`
}
SlackUserLinkResponse represents a user link in API responses
type SuccessResponse ¶
type SuccessResponse struct {
Status string `json:"status"`
Data any `json:"data,omitempty"`
Message string `json:"message,omitempty"`
RequestID string `json:"request_id,omitempty"`
}
SuccessResponse represents a standardised success response
type SwitchOrganisationRequest ¶
type SwitchOrganisationRequest struct {
OrganisationID string `json:"organisation_id"`
}
SwitchOrganisationRequest represents the request to switch active organisation
type TaskQueryBuilder ¶
TaskQueryBuilder holds the SQL queries and arguments for task retrieval
type TaskQueryParams ¶
type TaskQueryParams struct {
Limit int
Offset int
Status string
CacheFilter string
PathFilter string
OrderBy string
}
TaskQueryParams holds parameters for task listing queries
type TaskResponse ¶
type TaskResponse struct {
ID string `json:"id"`
JobID string `json:"job_id"`
Path string `json:"path"`
URL string `json:"url"`
Status string `json:"status"`
StatusCode *int `json:"status_code,omitempty"`
ResponseTime *int `json:"response_time,omitempty"`
CacheStatus *string `json:"cache_status,omitempty"`
SecondResponseTime *int `json:"second_response_time,omitempty"`
SecondCacheStatus *string `json:"second_cache_status,omitempty"`
ContentType *string `json:"content_type,omitempty"`
Error *string `json:"error,omitempty"`
SourceType *string `json:"source_type,omitempty"`
SourceURL *string `json:"source_url,omitempty"`
CreatedAt string `json:"created_at"`
StartedAt *string `json:"started_at,omitempty"`
CompletedAt *string `json:"completed_at,omitempty"`
RetryCount int `json:"retry_count"`
PageViews7d *int `json:"page_views_7d,omitempty"`
PageViews28d *int `json:"page_views_28d,omitempty"`
PageViews180d *int `json:"page_views_180d,omitempty"`
}
TaskResponse represents a task in API responses
type UpdateAutoPublishRequest ¶
type UpdateAutoPublishRequest struct {
ConnectionID string `json:"connection_id"`
Enabled bool `json:"enabled"`
}
UpdateAutoPublishRequest represents the request body for toggling auto-publish
type UpdateOrganisationMemberRoleRequest ¶
type UpdateOrganisationMemberRoleRequest struct {
Role string `json:"role"`
}
type UpdateScheduleRequest ¶
type UpdateScheduleRequest struct {
ConnectionID string `json:"connection_id"`
ScheduleIntervalHours *int `json:"schedule_interval_hours"` // nil to remove schedule
}
UpdateScheduleRequest represents the request body for updating a site's schedule
type UserResponse ¶
type UserResponse struct {
ID string `json:"id"`
Email string `json:"email"`
FirstName *string `json:"first_name"`
LastName *string `json:"last_name"`
FullName *string `json:"full_name"`
OrganisationID *string `json:"organisation_id"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
UserResponse represents a user in API responses
type WebflowAuthInfo ¶
type WebflowAuthInfo struct {
UserID string
WorkspaceIDs []string
// User info from authorized_by endpoint
UserEmail string
UserFirstName string
UserLastName string
DisplayName string // Combined name for display (e.g., "Simon Chua" or email)
}
WebflowAuthInfo contains user and workspace info from Webflow's API
type WebflowConnectionResponse ¶
type WebflowConnectionResponse struct {
ID string `json:"id"`
WebflowWorkspaceID string `json:"webflow_workspace_id,omitempty"`
WorkspaceName string `json:"workspace_name,omitempty"`
CreatedAt string `json:"created_at"`
}
WebflowConnectionResponse represents a Webflow connection in API responses
type WebflowCustomDomain ¶
type WebflowCustomDomain struct {
ID string `json:"id"`
URL string `json:"url"`
LastPublished *string `json:"lastPublished,omitempty"`
}
WebflowCustomDomain represents a custom domain from the Webflow API v2
type WebflowSite ¶
type WebflowSite struct {
ID string `json:"id"`
WorkspaceID string `json:"workspaceId,omitempty"`
DisplayName string `json:"displayName"`
ShortName string `json:"shortName"`
LastPublished string `json:"lastPublished,omitempty"`
LastUpdated string `json:"lastUpdated,omitempty"`
CustomDomains []WebflowCustomDomain `json:"customDomains,omitempty"`
}
WebflowSite represents a site from the Webflow API v2
type WebflowSiteSettingResponse ¶
type WebflowSiteSettingResponse struct {
WebflowSiteID string `json:"webflow_site_id"`
SiteName string `json:"site_name"`
PrimaryDomain string `json:"primary_domain"`
LastPublished string `json:"last_published,omitempty"`
ScheduleIntervalHours *int `json:"schedule_interval_hours"`
AutoPublishEnabled bool `json:"auto_publish_enabled"`
SchedulerID *string `json:"scheduler_id,omitempty"`
}
WebflowSiteSettingResponse represents a site with its local settings
type WebflowSitesListResponse ¶
type WebflowSitesListResponse struct {
Sites []WebflowSiteSettingResponse `json:"sites"`
Pagination struct {
Total int `json:"total"`
Page int `json:"page"`
Limit int `json:"limit"`
HasNext bool `json:"has_next"`
} `json:"pagination"`
}
WebflowSitesListResponse represents the paginated sites list response
type WebflowSitesResponse ¶
type WebflowSitesResponse struct {
Sites []WebflowSite `json:"sites"`
}
WebflowSitesResponse represents the response from Webflow's list sites API
type WebflowTokenResponse ¶
type WebflowTokenResponse struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
Scope string `json:"scope"`
}
WebflowTokenResponse represents the response from Webflow's token endpoint
type WebflowUserInfo ¶
type WebflowUserInfo struct {
ID string
Email string
FirstName string
LastName string
DisplayName string
}
WebflowUserInfo contains user details from the authorized_by endpoint
type WebflowWebhookPayload ¶
type WebflowWebhookPayload struct {
TriggerType string `json:"triggerType"`
SiteID string `json:"siteId,omitempty"` // Webflow site ID for per-site settings lookup
Payload struct {
Domains []string `json:"domains"`
PublishedBy struct {
DisplayName string `json:"displayName"`
} `json:"publishedBy"`
} `json:"payload"`
}
WebflowWebhookPayload represents the structure of Webflow's site publish webhook