Documentation
¶
Index ¶
- type AdminHandler
- func (h *AdminHandler) AddLicenseAddon(c *gin.Context)
- func (h *AdminHandler) AnalyticsActivationTrend(c *gin.Context)
- func (h *AdminHandler) AnalyticsBreakdown(c *gin.Context)
- func (h *AdminHandler) AnalyticsInsights(c *gin.Context)
- func (h *AdminHandler) AnalyticsSummary(c *gin.Context)
- func (h *AdminHandler) AnalyticsUsageTop(c *gin.Context)
- func (h *AdminHandler) ChangeLicensePlan(c *gin.Context)
- func (h *AdminHandler) CreateAPIKey(c *gin.Context)
- func (h *AdminHandler) CreateAddon(c *gin.Context)
- func (h *AdminHandler) CreateEntitlement(c *gin.Context)
- func (h *AdminHandler) CreateLicense(c *gin.Context)
- func (h *AdminHandler) CreatePlan(c *gin.Context)
- func (h *AdminHandler) CreateProduct(c *gin.Context)
- func (h *AdminHandler) DeleteAPIKey(c *gin.Context)
- func (h *AdminHandler) DeleteActivation(c *gin.Context)
- func (h *AdminHandler) DeleteAddon(c *gin.Context)
- func (h *AdminHandler) DeleteEntitlement(c *gin.Context)
- func (h *AdminHandler) DeletePlan(c *gin.Context)
- func (h *AdminHandler) DeleteProduct(c *gin.Context)
- func (h *AdminHandler) ExportLicenses(c *gin.Context)
- func (h *AdminHandler) GetEmailTemplates(c *gin.Context)
- func (h *AdminHandler) GetLicense(c *gin.Context)
- func (h *AdminHandler) GetPlan(c *gin.Context)
- func (h *AdminHandler) GetProduct(c *gin.Context)
- func (h *AdminHandler) GetSettings(c *gin.Context)
- func (h *AdminHandler) GetUserDetail(c *gin.Context)
- func (h *AdminHandler) InviteTeamMember(c *gin.Context)
- func (h *AdminHandler) ListAPIKeys(c *gin.Context)
- func (h *AdminHandler) ListAddons(c *gin.Context)
- func (h *AdminHandler) ListAnalytics(c *gin.Context)
- func (h *AdminHandler) ListAuditLogs(c *gin.Context)
- func (h *AdminHandler) ListFloatingSessions(c *gin.Context)
- func (h *AdminHandler) ListLicenseAddons(c *gin.Context)
- func (h *AdminHandler) ListLicenseSeats(c *gin.Context)
- func (h *AdminHandler) ListLicenseUsage(c *gin.Context)
- func (h *AdminHandler) ListLicenses(c *gin.Context)
- func (h *AdminHandler) ListPlans(c *gin.Context)
- func (h *AdminHandler) ListProducts(c *gin.Context)
- func (h *AdminHandler) ListTeamMembers(c *gin.Context)
- func (h *AdminHandler) ListUsers(c *gin.Context)
- func (h *AdminHandler) RefundLicense(c *gin.Context)
- func (h *AdminHandler) ReinstateLicense(c *gin.Context)
- func (h *AdminHandler) RemoveLicenseAddon(c *gin.Context)
- func (h *AdminHandler) RemoveTeamMember(c *gin.Context)
- func (h *AdminHandler) ResetLicenseUsage(c *gin.Context)
- func (h *AdminHandler) RevokeLicense(c *gin.Context)
- func (h *AdminHandler) RotateAPIKey(c *gin.Context)
- func (h *AdminHandler) RunExpiryChecks(c *gin.Context)
- func (h *AdminHandler) RunMeteredSync(c *gin.Context)
- func (h *AdminHandler) SendTestEmail(c *gin.Context)
- func (h *AdminHandler) Stats(c *gin.Context)
- func (h *AdminHandler) SuspendLicense(c *gin.Context)
- func (h *AdminHandler) UpdateAddon(c *gin.Context)
- func (h *AdminHandler) UpdateEntitlement(c *gin.Context)
- func (h *AdminHandler) UpdatePlan(c *gin.Context)
- func (h *AdminHandler) UpdateProduct(c *gin.Context)
- func (h *AdminHandler) UpdateSettings(c *gin.Context)
- type AuthHandler
- func (h *AuthHandler) AcceptInvite(svc *service.SeatService) gin.HandlerFunc
- func (h *AuthHandler) DevLogin(c *gin.Context)
- func (h *AuthHandler) Logout(c *gin.Context)
- func (h *AuthHandler) Me(c *gin.Context)
- func (h *AuthHandler) OTPSend(c *gin.Context)
- func (h *AuthHandler) OTPVerify(c *gin.Context)
- func (h *AuthHandler) Providers(c *gin.Context)
- func (h *AuthHandler) Refresh(c *gin.Context)
- type EntitlementHandler
- type FloatingHandler
- type LicenseHandler
- type PortalActivationsHandler
- type ReleaseAdminHandler
- func (h *ReleaseAdminHandler) AddArtifact(c *gin.Context)
- func (h *ReleaseAdminHandler) Create(c *gin.Context)
- func (h *ReleaseAdminHandler) Delete(c *gin.Context)
- func (h *ReleaseAdminHandler) DeleteArtifact(c *gin.Context)
- func (h *ReleaseAdminHandler) FinalizeArtifact(c *gin.Context)
- func (h *ReleaseAdminHandler) Get(c *gin.Context)
- func (h *ReleaseAdminHandler) List(c *gin.Context)
- func (h *ReleaseAdminHandler) Publish(c *gin.Context)
- func (h *ReleaseAdminHandler) Unyank(c *gin.Context)
- func (h *ReleaseAdminHandler) Update(c *gin.Context)
- func (h *ReleaseAdminHandler) Yank(c *gin.Context)
- type ReleasePublicConfig
- type ReleasePublicHandler
- type ReleaseSigningAdminHandler
- func (h *ReleaseSigningAdminHandler) Deactivate(c *gin.Context)
- func (h *ReleaseSigningAdminHandler) DownloadPublicKey(c *gin.Context)
- func (h *ReleaseSigningAdminHandler) DownloadPublicKeyTauri(c *gin.Context)
- func (h *ReleaseSigningAdminHandler) Generate(c *gin.Context)
- func (h *ReleaseSigningAdminHandler) List(c *gin.Context)
- func (h *ReleaseSigningAdminHandler) Rotate(c *gin.Context)
- type SeatHandler
- type SetupHandler
- type SystemHandler
- type UsageHandler
- type WebhookAdminHandler
- func (h *WebhookAdminHandler) CreateWebhook(c *gin.Context)
- func (h *WebhookAdminHandler) DeleteWebhook(c *gin.Context)
- func (h *WebhookAdminHandler) GetDelivery(c *gin.Context)
- func (h *WebhookAdminHandler) ListDeliveries(c *gin.Context)
- func (h *WebhookAdminHandler) ListWebhooks(c *gin.Context)
- func (h *WebhookAdminHandler) ResendDelivery(c *gin.Context)
- func (h *WebhookAdminHandler) TestWebhook(c *gin.Context)
- func (h *WebhookAdminHandler) UpdateWebhook(c *gin.Context)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AdminHandler ¶
type AdminHandler struct {
Store *store.Store
Webhook *service.WebhookService
Email *service.EmailService
Expiry *service.ExpiryChecker
Metered *service.MeteredBillingSyncer
}
func NewAdminHandler ¶
func NewAdminHandler(s *store.Store, wh *service.WebhookService, em *service.EmailService, ex *service.ExpiryChecker, ms *service.MeteredBillingSyncer) *AdminHandler
func (*AdminHandler) AddLicenseAddon ¶
func (h *AdminHandler) AddLicenseAddon(c *gin.Context)
func (*AdminHandler) AnalyticsActivationTrend ¶
func (h *AdminHandler) AnalyticsActivationTrend(c *gin.Context)
func (*AdminHandler) AnalyticsBreakdown ¶
func (h *AdminHandler) AnalyticsBreakdown(c *gin.Context)
func (*AdminHandler) AnalyticsInsights ¶
func (h *AdminHandler) AnalyticsInsights(c *gin.Context)
func (*AdminHandler) AnalyticsSummary ¶
func (h *AdminHandler) AnalyticsSummary(c *gin.Context)
func (*AdminHandler) AnalyticsUsageTop ¶
func (h *AdminHandler) AnalyticsUsageTop(c *gin.Context)
func (*AdminHandler) ChangeLicensePlan ¶
func (h *AdminHandler) ChangeLicensePlan(c *gin.Context)
func (*AdminHandler) CreateAPIKey ¶
func (h *AdminHandler) CreateAPIKey(c *gin.Context)
func (*AdminHandler) CreateAddon ¶
func (h *AdminHandler) CreateAddon(c *gin.Context)
func (*AdminHandler) CreateEntitlement ¶
func (h *AdminHandler) CreateEntitlement(c *gin.Context)
func (*AdminHandler) CreateLicense ¶
func (h *AdminHandler) CreateLicense(c *gin.Context)
func (*AdminHandler) CreatePlan ¶
func (h *AdminHandler) CreatePlan(c *gin.Context)
func (*AdminHandler) CreateProduct ¶
func (h *AdminHandler) CreateProduct(c *gin.Context)
func (*AdminHandler) DeleteAPIKey ¶
func (h *AdminHandler) DeleteAPIKey(c *gin.Context)
func (*AdminHandler) DeleteActivation ¶
func (h *AdminHandler) DeleteActivation(c *gin.Context)
func (*AdminHandler) DeleteAddon ¶
func (h *AdminHandler) DeleteAddon(c *gin.Context)
func (*AdminHandler) DeleteEntitlement ¶
func (h *AdminHandler) DeleteEntitlement(c *gin.Context)
func (*AdminHandler) DeletePlan ¶
func (h *AdminHandler) DeletePlan(c *gin.Context)
func (*AdminHandler) DeleteProduct ¶
func (h *AdminHandler) DeleteProduct(c *gin.Context)
func (*AdminHandler) ExportLicenses ¶
func (h *AdminHandler) ExportLicenses(c *gin.Context)
ExportLicenses exports all licenses as CSV or JSON. GET /api/v1/admin/licenses/export?format=csv&product_id=xxx&status=xxx
func (*AdminHandler) GetEmailTemplates ¶
func (h *AdminHandler) GetEmailTemplates(c *gin.Context)
GetEmailTemplates returns all email templates (custom from DB + hardcoded defaults).
func (*AdminHandler) GetLicense ¶
func (h *AdminHandler) GetLicense(c *gin.Context)
func (*AdminHandler) GetPlan ¶
func (h *AdminHandler) GetPlan(c *gin.Context)
func (*AdminHandler) GetProduct ¶
func (h *AdminHandler) GetProduct(c *gin.Context)
func (*AdminHandler) GetSettings ¶
func (h *AdminHandler) GetSettings(c *gin.Context)
func (*AdminHandler) GetUserDetail ¶
func (h *AdminHandler) GetUserDetail(c *gin.Context)
func (*AdminHandler) InviteTeamMember ¶
func (h *AdminHandler) InviteTeamMember(c *gin.Context)
InviteTeamMember promotes an existing user to admin, or creates a placeholder admin user. Only owners can invite new admins.
func (*AdminHandler) ListAPIKeys ¶
func (h *AdminHandler) ListAPIKeys(c *gin.Context)
func (*AdminHandler) ListAddons ¶
func (h *AdminHandler) ListAddons(c *gin.Context)
func (*AdminHandler) ListAnalytics ¶
func (h *AdminHandler) ListAnalytics(c *gin.Context)
func (*AdminHandler) ListAuditLogs ¶
func (h *AdminHandler) ListAuditLogs(c *gin.Context)
func (*AdminHandler) ListFloatingSessions ¶
func (h *AdminHandler) ListFloatingSessions(c *gin.Context)
func (*AdminHandler) ListLicenseAddons ¶
func (h *AdminHandler) ListLicenseAddons(c *gin.Context)
func (*AdminHandler) ListLicenseSeats ¶
func (h *AdminHandler) ListLicenseSeats(c *gin.Context)
func (*AdminHandler) ListLicenseUsage ¶
func (h *AdminHandler) ListLicenseUsage(c *gin.Context)
func (*AdminHandler) ListLicenses ¶
func (h *AdminHandler) ListLicenses(c *gin.Context)
func (*AdminHandler) ListPlans ¶
func (h *AdminHandler) ListPlans(c *gin.Context)
func (*AdminHandler) ListProducts ¶
func (h *AdminHandler) ListProducts(c *gin.Context)
func (*AdminHandler) ListTeamMembers ¶
func (h *AdminHandler) ListTeamMembers(c *gin.Context)
ListTeamMembers returns all platform admins (owner + admin roles).
func (*AdminHandler) ListUsers ¶
func (h *AdminHandler) ListUsers(c *gin.Context)
func (*AdminHandler) RefundLicense ¶
func (h *AdminHandler) RefundLicense(c *gin.Context)
func (*AdminHandler) ReinstateLicense ¶
func (h *AdminHandler) ReinstateLicense(c *gin.Context)
func (*AdminHandler) RemoveLicenseAddon ¶
func (h *AdminHandler) RemoveLicenseAddon(c *gin.Context)
func (*AdminHandler) RemoveTeamMember ¶
func (h *AdminHandler) RemoveTeamMember(c *gin.Context)
RemoveTeamMember demotes an admin back to regular user. Only owners can remove admins. Cannot remove the last owner.
func (*AdminHandler) ResetLicenseUsage ¶
func (h *AdminHandler) ResetLicenseUsage(c *gin.Context)
func (*AdminHandler) RevokeLicense ¶
func (h *AdminHandler) RevokeLicense(c *gin.Context)
func (*AdminHandler) RotateAPIKey ¶ added in v0.1.1
func (h *AdminHandler) RotateAPIKey(c *gin.Context)
RotateAPIKey generates a new secret for an existing key. The old secret stops working immediately — pre-launch we don't ship a grace period because rolling two valid secrets at once doubles the blast radius if either leaks during the rotation window.
The key ID is stable so callers can update their config without touching the row's name / scopes / product_id.
func (*AdminHandler) RunExpiryChecks ¶ added in v0.1.1
func (h *AdminHandler) RunExpiryChecks(c *gin.Context)
RunExpiryChecks triggers one full pass of the lifecycle checker on demand. Useful for admins (apply new grace_days immediately, debug "did expiry mailer run last night?") and for end-to-end tests of the expiring / dunning / renewal email paths that are otherwise on an hourly cron.
func (*AdminHandler) RunMeteredSync ¶ added in v0.1.1
func (h *AdminHandler) RunMeteredSync(c *gin.Context)
RunMeteredSync triggers one drain pass of the Stripe meter-event queue on demand. Useful for operators who just attached an entitlement to a Stripe meter and want to ship the backlog immediately, and for end-to-end tests that don't want to wait for the 5-minute loop.
func (*AdminHandler) SendTestEmail ¶
func (h *AdminHandler) SendTestEmail(c *gin.Context)
SendTestEmail sends a real test message through the configured SMTP server so the admin can verify host/port/credentials end-to-end. Body: { "to": "user@example.com" } — optional; defaults to the logged-in admin's own email address.
func (*AdminHandler) Stats ¶
func (h *AdminHandler) Stats(c *gin.Context)
func (*AdminHandler) SuspendLicense ¶
func (h *AdminHandler) SuspendLicense(c *gin.Context)
func (*AdminHandler) UpdateAddon ¶
func (h *AdminHandler) UpdateAddon(c *gin.Context)
func (*AdminHandler) UpdateEntitlement ¶
func (h *AdminHandler) UpdateEntitlement(c *gin.Context)
func (*AdminHandler) UpdatePlan ¶
func (h *AdminHandler) UpdatePlan(c *gin.Context)
func (*AdminHandler) UpdateProduct ¶
func (h *AdminHandler) UpdateProduct(c *gin.Context)
func (*AdminHandler) UpdateSettings ¶
func (h *AdminHandler) UpdateSettings(c *gin.Context)
type AuthHandler ¶ added in v0.1.1
func (*AuthHandler) AcceptInvite ¶ added in v0.1.1
func (h *AuthHandler) AcceptInvite(svc *service.SeatService) gin.HandlerFunc
AcceptInvite consumes a seat-invite token and, on success, ALSO issues a session for the invitee. Reasoning: the plain token in the email is proof of email ownership (we mailed it there), so requiring the invitee to *separately* OTP themselves in after clicking the link is theater — and bad UX. They'd hit /login and have to round-trip through the same mailbox. By issuing a session here, "click link → land in portal" is one step.
Service is provided as a parameter rather than as a field so we don't have to widen AuthHandler's surface; main.go closes over it.
func (*AuthHandler) DevLogin ¶ added in v0.1.1
func (h *AuthHandler) DevLogin(c *gin.Context)
DevLogin is a development-only endpoint that creates a session without email OTP. Security: This endpoint is ONLY available when BOTH conditions are met:
- ENVIRONMENT is explicitly set to "development"
- The server is NOT listening on a public interface (checked via BASE_URL)
This prevents accidental exposure in production deployments.
func (*AuthHandler) Logout ¶ added in v0.1.1
func (h *AuthHandler) Logout(c *gin.Context)
func (*AuthHandler) Me ¶ added in v0.1.1
func (h *AuthHandler) Me(c *gin.Context)
func (*AuthHandler) OTPSend ¶ added in v0.1.1
func (h *AuthHandler) OTPSend(c *gin.Context)
OTPSend handles POST /api/v1/auth/otp/send
func (*AuthHandler) OTPVerify ¶ added in v0.1.1
func (h *AuthHandler) OTPVerify(c *gin.Context)
OTPVerify handles POST /api/v1/auth/otp/verify
func (*AuthHandler) Providers ¶ added in v0.1.1
func (h *AuthHandler) Providers(c *gin.Context)
func (*AuthHandler) Refresh ¶ added in v0.1.1
func (h *AuthHandler) Refresh(c *gin.Context)
type EntitlementHandler ¶
type EntitlementHandler struct {
// contains filtered or unexported fields
}
func NewEntitlementHandler ¶
func NewEntitlementHandler(svc *service.EntitlementService) *EntitlementHandler
func (*EntitlementHandler) Check ¶
func (h *EntitlementHandler) Check(c *gin.Context)
type FloatingHandler ¶
type FloatingHandler struct {
// contains filtered or unexported fields
}
func NewFloatingHandler ¶
func NewFloatingHandler(svc *service.FloatingService) *FloatingHandler
func (*FloatingHandler) CheckIn ¶
func (h *FloatingHandler) CheckIn(c *gin.Context)
func (*FloatingHandler) CheckOut ¶
func (h *FloatingHandler) CheckOut(c *gin.Context)
func (*FloatingHandler) Heartbeat ¶
func (h *FloatingHandler) Heartbeat(c *gin.Context)
type LicenseHandler ¶
type LicenseHandler struct {
// contains filtered or unexported fields
}
func NewLicenseHandler ¶
func NewLicenseHandler(svc *service.LicenseService) *LicenseHandler
func (*LicenseHandler) Activate ¶
func (h *LicenseHandler) Activate(c *gin.Context)
func (*LicenseHandler) Deactivate ¶
func (h *LicenseHandler) Deactivate(c *gin.Context)
func (*LicenseHandler) Verify ¶
func (h *LicenseHandler) Verify(c *gin.Context)
type PortalActivationsHandler ¶ added in v0.1.1
type PortalActivationsHandler struct {
// contains filtered or unexported fields
}
PortalActivationsHandler exposes self-service activation management to the license owner (the user matching license.email) OR any accepted seat on the license (admin or member). The "member can also manage activation slots" rule matches the use case: a teammate who lost their laptop must be able to free their own slot without filing a support ticket.
GET /api/v1/portal/licenses/:license_key/activations DELETE /api/v1/portal/licenses/:license_key/activations/:activation_id
The classic UX problem this solves: "I lost my old laptop, all 3 activation slots are taken, I can't activate the new machine". Without self-service, that's a customer-support ticket every time.
func NewPortalActivationsHandler ¶ added in v0.1.1
func NewPortalActivationsHandler(s *store.Store) *PortalActivationsHandler
func (*PortalActivationsHandler) Delete ¶ added in v0.1.1
func (h *PortalActivationsHandler) Delete(c *gin.Context)
DELETE /api/v1/portal/licenses/:license_key/activations/:activation_id
func (*PortalActivationsHandler) List ¶ added in v0.1.1
func (h *PortalActivationsHandler) List(c *gin.Context)
GET /api/v1/portal/licenses/:license_key/activations
type ReleaseAdminHandler ¶ added in v0.1.1
type ReleaseAdminHandler struct {
// contains filtered or unexported fields
}
ReleaseAdminHandler exposes admin-only release management endpoints.
Industry-aligned API:
POST /admin/releases Create draft release GET /admin/releases List releases GET /admin/releases/:id Get release with artifacts PATCH /admin/releases/:id Update display name + notes DELETE /admin/releases/:id Delete draft (cascades artifacts) POST /admin/releases/:id/artifacts Add artifact (returns presigned PUT) POST /admin/releases/:id/artifacts/:aid/finalize Finalize artifact upload DELETE /admin/releases/:id/artifacts/:aid Delete artifact (draft only) POST /admin/releases/:id/actions/publish Publish (signs all artifacts) POST /admin/releases/:id/actions/yank Yank POST /admin/releases/:id/actions/unyank Unyank
Nested artifact endpoints validate that :aid belongs to :id — a request for a real artifact ID under the wrong release returns 404, not the artifact's data — to avoid IDOR-style cross-release access.
func NewReleaseAdminHandler ¶ added in v0.1.1
func NewReleaseAdminHandler(svc *service.ReleaseService, st *store.Store) *ReleaseAdminHandler
func (*ReleaseAdminHandler) AddArtifact ¶ added in v0.1.1
func (h *ReleaseAdminHandler) AddArtifact(c *gin.Context)
POST /api/v1/admin/releases/:id/artifacts
Body: { platform, content_type?, expected_size?, filename? }
func (*ReleaseAdminHandler) Create ¶ added in v0.1.1
func (h *ReleaseAdminHandler) Create(c *gin.Context)
POST /api/v1/admin/releases
Body: { product_id, version, channel?, name?, release_notes? }
func (*ReleaseAdminHandler) Delete ¶ added in v0.1.1
func (h *ReleaseAdminHandler) Delete(c *gin.Context)
DELETE /api/v1/admin/releases/:id (draft only; cascades artifacts).
func (*ReleaseAdminHandler) DeleteArtifact ¶ added in v0.1.1
func (h *ReleaseAdminHandler) DeleteArtifact(c *gin.Context)
DELETE /api/v1/admin/releases/:id/artifacts/:aid
func (*ReleaseAdminHandler) FinalizeArtifact ¶ added in v0.1.1
func (h *ReleaseAdminHandler) FinalizeArtifact(c *gin.Context)
POST /api/v1/admin/releases/:id/artifacts/:aid/finalize
Body: { expected_sha256? }
The server reads the uploaded bytes from storage and computes the authoritative sha256 itself. expected_sha256 (legacy alias: sha256) is optional — when provided, the server compares it to the computed digest and returns 409 SHA256_MISMATCH on disagreement. Clients should move to expected_sha256; sha256 is accepted for one release cycle.
func (*ReleaseAdminHandler) Get ¶ added in v0.1.1
func (h *ReleaseAdminHandler) Get(c *gin.Context)
GET /api/v1/admin/releases/:id
func (*ReleaseAdminHandler) List ¶ added in v0.1.1
func (h *ReleaseAdminHandler) List(c *gin.Context)
GET /api/v1/admin/releases
func (*ReleaseAdminHandler) Publish ¶ added in v0.1.1
func (h *ReleaseAdminHandler) Publish(c *gin.Context)
POST /api/v1/admin/releases/:id/actions/publish
func (*ReleaseAdminHandler) Unyank ¶ added in v0.1.1
func (h *ReleaseAdminHandler) Unyank(c *gin.Context)
POST /api/v1/admin/releases/:id/actions/unyank
func (*ReleaseAdminHandler) Update ¶ added in v0.1.1
func (h *ReleaseAdminHandler) Update(c *gin.Context)
PATCH /api/v1/admin/releases/:id
Body: { name?, release_notes? }
Only display fields are mutable post-create. version / channel / status / artifacts are immutable from this endpoint — version & channel are part of the release identity (carve a new release if you need to change them); status moves through dedicated action endpoints.
func (*ReleaseAdminHandler) Yank ¶ added in v0.1.1
func (h *ReleaseAdminHandler) Yank(c *gin.Context)
POST /api/v1/admin/releases/:id/actions/yank
Body: { reason }
type ReleasePublicConfig ¶ added in v0.1.1
type ReleasePublicHandler ¶ added in v0.1.1
type ReleasePublicHandler struct {
// contains filtered or unexported fields
}
ReleasePublicHandler exposes the endpoints clients use:
POST /api/v1/license/download license-gated download URL GET /api/v1/releases/:product_slug/feed.xml Sparkle appcast (per-platform) GET /api/v1/releases/:product_slug/feed.json Velopack feed (per-platform) GET /api/v1/releases/:product_slug/upgrade.json Tauri manifest (single latest)
Auth model: feeds are PUBLIC for every channel — stable, beta, alpha, dev. Industry convention (Sparkle / Tauri / npm / GitHub Releases): trust = the artifact's Ed25519 signature, NOT URL secrecy. Genuinely private builds belong on internal CI/CD distribution (private R2 bucket, TestFlight, Firebase App Distribution); they don't ship through these feeds at all.
License gating happens at app start (the SDK calls /license/verify), not at update time. License rotation never bricks installed clients.
func NewReleasePublicHandler ¶ added in v0.1.1
func NewReleasePublicHandler(c ReleasePublicConfig) *ReleasePublicHandler
func (*ReleasePublicHandler) Download ¶ added in v0.1.1
func (h *ReleasePublicHandler) Download(c *gin.Context)
POST /api/v1/license/download
Body: { license_key, platform, version?, channel? }
func (*ReleasePublicHandler) FeedSparkle ¶ added in v0.1.1
func (h *ReleasePublicHandler) FeedSparkle(c *gin.Context)
GET /api/v1/releases/:product_slug/feed.xml — Sparkle appcast
func (*ReleasePublicHandler) FeedTauri ¶ added in v0.1.1
func (h *ReleasePublicHandler) FeedTauri(c *gin.Context)
GET /api/v1/releases/:product_slug/upgrade.json — Tauri (single-release manifest)
func (*ReleasePublicHandler) FeedVelopack ¶ added in v0.1.1
func (h *ReleasePublicHandler) FeedVelopack(c *gin.Context)
GET /api/v1/releases/:product_slug/feed.json — Velopack feed
type ReleaseSigningAdminHandler ¶ added in v0.1.1
type ReleaseSigningAdminHandler struct {
// contains filtered or unexported fields
}
ReleaseSigningAdminHandler exposes admin-only signing key management.
Operational note: the API never returns the encrypted private key, only the public key and metadata. Callers (the admin UI) embed the public key into client app binaries; the private key never leaves the server.
func NewReleaseSigningAdminHandler ¶ added in v0.1.1
func NewReleaseSigningAdminHandler(svc *service.ReleaseSigningService, st *store.Store) *ReleaseSigningAdminHandler
func (*ReleaseSigningAdminHandler) Deactivate ¶ added in v0.1.1
func (h *ReleaseSigningAdminHandler) Deactivate(c *gin.Context)
DELETE /api/v1/admin/products/:id/signing-key
Deactivates the current active key without creating a replacement. Future releases will be unsigned until a new key is generated.
Request body: { "note": "..." } // optional
func (*ReleaseSigningAdminHandler) DownloadPublicKey ¶ added in v0.1.1
func (h *ReleaseSigningAdminHandler) DownloadPublicKey(c *gin.Context)
GET /api/v1/admin/products/:id/signing-key/public.pem
Returns the active public key as a PEM document for direct download. Operators embed this file in their client app source tree (e.g. public_key.pem next to Sparkle's Info.plist or Tauri's tauri.conf.json).
func (*ReleaseSigningAdminHandler) DownloadPublicKeyTauri ¶ added in v0.1.1
func (h *ReleaseSigningAdminHandler) DownloadPublicKeyTauri(c *gin.Context)
GET /api/v1/admin/products/:id/signing-key/tauri-pubkey
Returns the active public key in Tauri's minisign-wrapped format (base64 of "Ed" + 8-byte key_id + 32-byte raw key). Tauri's `tauri.conf.json -> bundle.updater.pubkey` field expects exactly this shape; the raw PEM/Sparkle key fails Tauri's verifier.
func (*ReleaseSigningAdminHandler) Generate ¶ added in v0.1.1
func (h *ReleaseSigningAdminHandler) Generate(c *gin.Context)
POST /api/v1/admin/products/:id/signing-key
Generates a fresh keypair for the product. Fails 409 if an active key already exists; the admin must rotate instead.
func (*ReleaseSigningAdminHandler) List ¶ added in v0.1.1
func (h *ReleaseSigningAdminHandler) List(c *gin.Context)
GET /api/v1/admin/products/:id/signing-keys
Returns the full signing-key history for a product. Active key first, then inactive sorted by creation time desc.
func (*ReleaseSigningAdminHandler) Rotate ¶ added in v0.1.1
func (h *ReleaseSigningAdminHandler) Rotate(c *gin.Context)
POST /api/v1/admin/products/:id/signing-key/rotate
Request body: { "note": "..." } // optional but recommended
Generates a new active key and deactivates the previous one (if any).
type SeatHandler ¶
type SeatHandler struct {
// contains filtered or unexported fields
}
func NewSeatHandler ¶
func NewSeatHandler(svc *service.SeatService) *SeatHandler
func (*SeatHandler) AcceptInvite ¶ added in v0.1.1
func (h *SeatHandler) AcceptInvite(c *gin.Context)
AcceptInvite consumes the plain token shipped in the seat-invite email and binds the seat to a user account (creating one keyed off the seat email if necessary).
Auth-free: the token IS the proof of email ownership. We deliberately don't accept the email from the request — using the token's stored seat.email guarantees the inviter's intent.
func (*SeatHandler) AddSeat ¶
func (h *SeatHandler) AddSeat(c *gin.Context)
func (*SeatHandler) ListSeats ¶
func (h *SeatHandler) ListSeats(c *gin.Context)
func (*SeatHandler) RemoveSeat ¶
func (h *SeatHandler) RemoveSeat(c *gin.Context)
type SetupHandler ¶
SetupHandler manages the first-run setup wizard.
func NewSetupHandler ¶
func NewSetupHandler(s *store.Store) *SetupHandler
func (*SetupHandler) Initialize ¶
func (h *SetupHandler) Initialize(c *gin.Context)
Initialize completes setup in one call. This is the ONLY endpoint that allows creating the first owner without authentication. POST /api/v1/setup/initialize
func (*SetupHandler) Status ¶
func (h *SetupHandler) Status(c *gin.Context)
Status returns whether setup is needed and which step the wizard is on. GET /api/v1/setup/status
type SystemHandler ¶
type SystemHandler struct {
Store *store.Store
RepoOwner string
RepoName string
// contains filtered or unexported fields
}
func NewSystemHandler ¶
func NewSystemHandler(s *store.Store) *SystemHandler
func (*SystemHandler) CheckUpdate ¶
func (h *SystemHandler) CheckUpdate(c *gin.Context)
CheckUpdate checks GitHub for a newer release. Results are cached for 1 hour. On startup, the background checker calls this periodically so the dashboard always shows fresh update status without the admin clicking anything.
func (*SystemHandler) GetMigrationStatus ¶
func (h *SystemHandler) GetMigrationStatus(c *gin.Context)
func (*SystemHandler) GetVersion ¶
func (h *SystemHandler) GetVersion(c *gin.Context)
func (*SystemHandler) StartAutoCheck ¶
func (h *SystemHandler) StartAutoCheck(done <-chan struct{})
StartAutoCheck runs a background loop that checks for updates every 6 hours. The result is cached so the admin dashboard always has fresh data.
type UsageHandler ¶
type UsageHandler struct {
// contains filtered or unexported fields
}
func NewUsageHandler ¶
func NewUsageHandler(svc *service.UsageService) *UsageHandler
func (*UsageHandler) GetQuotaStatus ¶
func (h *UsageHandler) GetQuotaStatus(c *gin.Context)
func (*UsageHandler) RecordUsage ¶
func (h *UsageHandler) RecordUsage(c *gin.Context)
type WebhookAdminHandler ¶
type WebhookAdminHandler struct {
Store *store.Store
Webhook *service.WebhookService
}
func NewWebhookAdminHandler ¶
func NewWebhookAdminHandler(s *store.Store, wh *service.WebhookService) *WebhookAdminHandler
func (*WebhookAdminHandler) CreateWebhook ¶
func (h *WebhookAdminHandler) CreateWebhook(c *gin.Context)
func (*WebhookAdminHandler) DeleteWebhook ¶
func (h *WebhookAdminHandler) DeleteWebhook(c *gin.Context)
func (*WebhookAdminHandler) GetDelivery ¶ added in v0.1.1
func (h *WebhookAdminHandler) GetDelivery(c *gin.Context)
GET /admin/webhooks/:id/deliveries/:delivery_id
Detail view used by the admin UI to show the full payload + raw response body for diagnosing a failed delivery.
func (*WebhookAdminHandler) ListDeliveries ¶
func (h *WebhookAdminHandler) ListDeliveries(c *gin.Context)
func (*WebhookAdminHandler) ListWebhooks ¶
func (h *WebhookAdminHandler) ListWebhooks(c *gin.Context)
func (*WebhookAdminHandler) ResendDelivery ¶ added in v0.1.1
func (h *WebhookAdminHandler) ResendDelivery(c *gin.Context)
POST /admin/webhooks/:id/deliveries/:delivery_id/resend
Manual re-fire of a previous delivery. Common during integration: the receiver was down / mis-configured and the admin wants to replay an event without trying to recreate the original action. The replay carries the SAME payload bytes (so receiver-side idempotency keys still match) but a fresh X-Keygate-Delivery and a new row in the deliveries table so retry counters are clean.
func (*WebhookAdminHandler) TestWebhook ¶
func (h *WebhookAdminHandler) TestWebhook(c *gin.Context)
func (*WebhookAdminHandler) UpdateWebhook ¶
func (h *WebhookAdminHandler) UpdateWebhook(c *gin.Context)