api

package
v0.27.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 23, 2026 License: MIT Imports: 36 Imported by: 0

Documentation

Index

Constants

View Source
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

View Source
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

func CORSMiddleware(next http.Handler) http.Handler

CORSMiddleware adds CORS headers for browser requests

func CrossOriginProtectionMiddleware

func CrossOriginProtectionMiddleware(next http.Handler) http.Handler

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

func GetRequestID(r *http.Request) string

GetRequestID retrieves the request ID from the request context

func HandlePoolSaturation

func HandlePoolSaturation(w http.ResponseWriter, r *http.Request, err error) bool

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

func LoggingMiddleware(next http.Handler) http.Handler

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

func RequestIDMiddleware(next http.Handler) http.Handler

RequestIDMiddleware adds a unique request ID to each request

func SecurityHeadersMiddleware

func SecurityHeadersMiddleware(next http.Handler) http.Handler

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

func WriteCreated(w http.ResponseWriter, r *http.Request, data any, message string)

WriteCreated writes a standardised success response for created resources

func WriteError

func WriteError(w http.ResponseWriter, r *http.Request, err error, status int, code ErrorCode)

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

func WriteHealthy(w http.ResponseWriter, r *http.Request, service string, version string)

WriteHealthy writes a standardised health check response

func WriteJSON

func WriteJSON(w http.ResponseWriter, r *http.Request, data any, status int)

WriteJSON writes a JSON response with the given status code

func WriteNoContent

func WriteNoContent(w http.ResponseWriter, r *http.Request)

WriteNoContent writes a 204 No Content response

func WriteSuccess

func WriteSuccess(w http.ResponseWriter, r *http.Request, data any, message string)

WriteSuccess writes a standardised success response

func WriteUnhealthy

func WriteUnhealthy(w http.ResponseWriter, r *http.Request, service string, err error)

WriteUnhealthy writes a standardised unhealthy response

Types

type AuthProfileUpdateRequest

type AuthProfileUpdateRequest struct {
	FirstName *string `json:"first_name"`
	LastName  *string `json:"last_name"`
	FullName  *string `json:"full_name"`
}

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

type DomainResponse struct {
	DomainID int    `json:"domain_id"`
	Domain   string `json:"domain"`
}

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"
	ErrCodeUnauthorised     ErrorCode = "UNAUTHORISED"
	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"
	ErrCodeServiceUnavailable ErrorCode = "SERVICE_UNAVAILABLE"
	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

type ExportColumn struct {
	Key   string `json:"key"`
	Label string `json:"label"`
}

ExportColumn describes a column in exported task datasets

type GA4APIError

type GA4APIError struct {
	StatusCode int
	Body       string
}

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

func NewGA4Client(accessToken, clientID, clientSecret string) *GA4Client

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

func (*GA4Client) RefreshAccessToken

func (c *GA4Client) RefreshAccessToken(ctx context.Context, refreshToken string) (string, error)

RefreshAccessToken exchanges a refresh token for a new access token Uses application/x-www-form-urlencoded as required by OAuth 2.0 RFC 6749

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

func (h *Handler) GetActiveOrganisation(w http.ResponseWriter, r *http.Request) string

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

func (h *Handler) SetupRoutes(mux *http.ServeMux)

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

type TaskQueryBuilder struct {
	SelectQuery string
	CountQuery  string
	Args        []any
}

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

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL