feat(desktop): implement workspace foundation + desktop-client skeleton

Plan 0 (workspaces): add workspaces + workspace_memberships schema, extend
JWT/Actor/claims with primary_workspace_id, seed default workspace per tenant,
thread workspace_id through tenant monitoring quota.

Plan A (desktop skeleton): new Electron app (apps/desktop-client) with main/
preload/renderer, shared Vue component package (packages/ui-shared), and server
surface — desktop client registration + token rotation + heartbeat, SSE task
event stream, desktop accounts/tasks/content handlers, publish job endpoint,
and supporting repositories, services, sqlc queries, and migrations.

Hard cutover per plan: remove browser-extension monitoring callback endpoints,
stub legacy media API in admin-web, and delete monitoring_callback_handler.go.
This commit is contained in:
2026-04-19 14:18:20 +08:00
parent 98f9e95875
commit b16e9f0bd1
141 changed files with 21533 additions and 357 deletions
+18 -15
View File
@@ -20,11 +20,12 @@ type UserRecord struct {
}
type MembershipRecord struct {
ID int64
TenantID int64
UserID int64
TenantRole string
CreatedAt time.Time
ID int64
TenantID int64
UserID int64
PrimaryWorkspaceID int64
TenantRole string
CreatedAt time.Time
}
type AuthRepository interface {
@@ -87,11 +88,12 @@ func (r *authRepository) GetTenantMembership(ctx context.Context, userID int64)
}
return &MembershipRecord{
ID: row.ID,
TenantID: row.TenantID,
UserID: row.UserID,
TenantRole: row.TenantRole,
CreatedAt: timeFromTimestamp(row.CreatedAt),
ID: row.ID,
TenantID: row.TenantID,
UserID: row.UserID,
PrimaryWorkspaceID: row.PrimaryWorkspaceID,
TenantRole: row.TenantRole,
CreatedAt: timeFromTimestamp(row.CreatedAt),
}, nil
}
@@ -105,10 +107,11 @@ func (r *authRepository) GetTenantMembershipByTenantAndUser(ctx context.Context,
}
return &MembershipRecord{
ID: row.ID,
TenantID: row.TenantID,
UserID: row.UserID,
TenantRole: row.TenantRole,
CreatedAt: timeFromTimestamp(row.CreatedAt),
ID: row.ID,
TenantID: row.TenantID,
UserID: row.UserID,
PrimaryWorkspaceID: row.PrimaryWorkspaceID,
TenantRole: row.TenantRole,
CreatedAt: timeFromTimestamp(row.CreatedAt),
}, nil
}
@@ -1,8 +1,10 @@
package repository
import (
"encoding/json"
"time"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype"
"github.com/geo-platform/tenant-api/internal/tenant/repository/generated"
@@ -86,3 +88,40 @@ func pgTimestamp(value *time.Time) pgtype.Timestamptz {
}
return pgtype.Timestamptz{Time: *value, Valid: true}
}
func pgUUID(value uuid.UUID) pgtype.UUID {
return pgtype.UUID{Bytes: value, Valid: true}
}
func uuidFromPG(value pgtype.UUID) uuid.UUID {
if !value.Valid {
return uuid.Nil
}
return uuid.UUID(value.Bytes)
}
func nullableUUID(value pgtype.UUID) *uuid.UUID {
if !value.Valid {
return nil
}
parsed := uuid.UUID(value.Bytes)
return &parsed
}
func marshalJSON(value any) ([]byte, error) {
if value == nil {
return nil, nil
}
return json.Marshal(value)
}
func unmarshalStringSlice(data []byte) ([]string, error) {
if len(data) == 0 {
return nil, nil
}
var items []string
if err := json.Unmarshal(data, &items); err != nil {
return nil, err
}
return items, nil
}
@@ -0,0 +1,459 @@
package repository
import (
"context"
"fmt"
"time"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype"
"github.com/geo-platform/tenant-api/internal/tenant/repository/generated"
)
type DesktopAccount struct {
DesktopID uuid.UUID
TenantID int64
WorkspaceID int64
UserID int64
ClientID *uuid.UUID
Platform string
PlatformUID string
AccountFingerprint *string
DisplayName string
Health string
VerifiedAt *time.Time
Tags []string
SyncVersion int64
DeletedAt *time.Time
DeleteRequestedAt *time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
type UpsertDesktopAccountParams struct {
DesktopID uuid.UUID
TenantID int64
WorkspaceID int64
UserID int64
ClientID uuid.UUID
Platform string
PlatformUID string
AccountFingerprint *string
DisplayName string
Health string
VerifiedAt *time.Time
Tags []string
IfSyncVersion *int64
}
type PatchDesktopAccountParams struct {
DesktopID uuid.UUID
WorkspaceID int64
DisplayName *string
Health *string
VerifiedAt *time.Time
Tags *[]string
IfSyncVersion int64
}
type DesktopAccountRepository interface {
ListByClient(ctx context.Context, workspaceID int64, clientID uuid.UUID) ([]DesktopAccount, error)
GetByDesktopID(ctx context.Context, desktopID uuid.UUID, workspaceID int64) (*DesktopAccount, error)
GetByIdentity(ctx context.Context, workspaceID int64, platform, platformUID string) (*DesktopAccount, error)
Upsert(ctx context.Context, params UpsertDesktopAccountParams) (*DesktopAccount, error)
Patch(ctx context.Context, params PatchDesktopAccountParams) (*DesktopAccount, error)
Tombstone(ctx context.Context, desktopID uuid.UUID, workspaceID, ifSyncVersion int64) (*DesktopAccount, error)
MarkDeleteRequested(ctx context.Context, desktopID uuid.UUID, workspaceID int64) (*DesktopAccount, error)
ClearDeleteRequested(ctx context.Context, desktopID uuid.UUID, workspaceID int64) (*DesktopAccount, error)
}
type desktopAccountRepository struct {
q generated.Querier
}
func NewDesktopAccountRepository(db generated.DBTX) DesktopAccountRepository {
return &desktopAccountRepository{q: newQuerier(db)}
}
func (r *desktopAccountRepository) ListByClient(ctx context.Context, workspaceID int64, clientID uuid.UUID) ([]DesktopAccount, error) {
rows, err := r.q.ListDesktopAccountsByClient(ctx, generated.ListDesktopAccountsByClientParams{
WorkspaceID: workspaceID,
ClientID: pgUUID(clientID),
})
if err != nil {
return nil, err
}
items := make([]DesktopAccount, 0, len(rows))
for _, row := range rows {
item, err := desktopAccountFromListRow(row)
if err != nil {
return nil, err
}
items = append(items, *item)
}
return items, nil
}
func (r *desktopAccountRepository) GetByDesktopID(ctx context.Context, desktopID uuid.UUID, workspaceID int64) (*DesktopAccount, error) {
row, err := r.q.GetDesktopAccountByDesktopID(ctx, generated.GetDesktopAccountByDesktopIDParams{
DesktopID: pgUUID(desktopID),
WorkspaceID: workspaceID,
})
if err != nil {
return nil, err
}
return desktopAccountFromGetRow(row)
}
func (r *desktopAccountRepository) GetByIdentity(ctx context.Context, workspaceID int64, platform, platformUID string) (*DesktopAccount, error) {
row, err := r.q.GetDesktopAccountByIdentity(ctx, generated.GetDesktopAccountByIdentityParams{
WorkspaceID: workspaceID,
PlatformID: platform,
PlatformUid: platformUID,
})
if err != nil {
return nil, err
}
return desktopAccountFromIdentityRow(row)
}
func (r *desktopAccountRepository) Upsert(ctx context.Context, params UpsertDesktopAccountParams) (*DesktopAccount, error) {
tagsJSON, err := marshalJSON(params.Tags)
if err != nil {
return nil, fmt.Errorf("marshal tags: %w", err)
}
var metadataJSON []byte
if len(tagsJSON) > 0 {
metadataJSON, err = marshalJSON(map[string]any{"tags": params.Tags})
if err != nil {
return nil, fmt.Errorf("marshal metadata: %w", err)
}
}
row, err := r.q.UpsertDesktopAccount(ctx, generated.UpsertDesktopAccountParams{
DesktopID: pgUUID(params.DesktopID),
TenantID: params.TenantID,
WorkspaceID: params.WorkspaceID,
UserID: params.UserID,
ClientID: pgUUID(params.ClientID),
PlatformID: params.Platform,
PlatformUid: params.PlatformUID,
DisplayName: params.DisplayName,
LegacyStatus: legacyStatusFromHealth(params.Health),
MetadataJson: metadataJSON,
VerifiedAt: pgTimestamp(params.VerifiedAt),
AccountFingerprint: pgText(params.AccountFingerprint),
Health: params.Health,
Tags: tagsJSON,
IfSyncVersion: pgInt8(params.IfSyncVersion),
})
if err != nil {
return nil, err
}
return desktopAccountFromUpsertRow(row)
}
func (r *desktopAccountRepository) Patch(ctx context.Context, params PatchDesktopAccountParams) (*DesktopAccount, error) {
var tagsJSON []byte
var err error
if params.Tags != nil {
tagsJSON, err = marshalJSON(*params.Tags)
if err != nil {
return nil, fmt.Errorf("marshal tags: %w", err)
}
}
row, err := r.q.PatchDesktopAccount(ctx, generated.PatchDesktopAccountParams{
DisplayName: pgText(params.DisplayName),
Health: pgText(params.Health),
LegacyStatus: pgText(legacyStatusPtrFromHealth(params.Health)),
VerifiedAt: pgTimestamp(params.VerifiedAt),
Tags: tagsJSON,
DesktopID: pgUUID(params.DesktopID),
WorkspaceID: params.WorkspaceID,
IfSyncVersion: params.IfSyncVersion,
})
if err != nil {
return nil, err
}
return desktopAccountFromPatchRow(row)
}
func (r *desktopAccountRepository) Tombstone(ctx context.Context, desktopID uuid.UUID, workspaceID, ifSyncVersion int64) (*DesktopAccount, error) {
row, err := r.q.TombstoneDesktopAccount(ctx, generated.TombstoneDesktopAccountParams{
DesktopID: pgUUID(desktopID),
WorkspaceID: workspaceID,
IfSyncVersion: ifSyncVersion,
})
if err != nil {
return nil, err
}
return desktopAccountFromTombstoneRow(row)
}
func (r *desktopAccountRepository) MarkDeleteRequested(ctx context.Context, desktopID uuid.UUID, workspaceID int64) (*DesktopAccount, error) {
row, err := r.q.MarkDesktopAccountDeleteRequested(ctx, generated.MarkDesktopAccountDeleteRequestedParams{
DesktopID: pgUUID(desktopID),
WorkspaceID: workspaceID,
})
if err != nil {
return nil, err
}
return desktopAccountFromMarkDeleteRow(row)
}
func (r *desktopAccountRepository) ClearDeleteRequested(ctx context.Context, desktopID uuid.UUID, workspaceID int64) (*DesktopAccount, error) {
row, err := r.q.ClearDesktopAccountDeleteRequested(ctx, generated.ClearDesktopAccountDeleteRequestedParams{
DesktopID: pgUUID(desktopID),
WorkspaceID: workspaceID,
})
if err != nil {
return nil, err
}
return desktopAccountFromClearDeleteRow(row)
}
func desktopAccountFromListRow(row generated.ListDesktopAccountsByClientRow) (*DesktopAccount, error) {
return buildDesktopAccount(
row.DesktopID,
row.TenantID,
row.WorkspaceID,
row.UserID,
row.ClientID,
row.PlatformID,
row.PlatformUid,
row.AccountFingerprint,
row.DisplayName,
row.Health,
row.VerifiedAt,
row.Tags,
row.SyncVersion,
row.DeletedAt,
row.DeleteRequestedAt,
row.CreatedAt,
row.UpdatedAt,
)
}
func desktopAccountFromGetRow(row generated.GetDesktopAccountByDesktopIDRow) (*DesktopAccount, error) {
return buildDesktopAccount(
row.DesktopID,
row.TenantID,
row.WorkspaceID,
row.UserID,
row.ClientID,
row.PlatformID,
row.PlatformUid,
row.AccountFingerprint,
row.DisplayName,
row.Health,
row.VerifiedAt,
row.Tags,
row.SyncVersion,
row.DeletedAt,
row.DeleteRequestedAt,
row.CreatedAt,
row.UpdatedAt,
)
}
func desktopAccountFromIdentityRow(row generated.GetDesktopAccountByIdentityRow) (*DesktopAccount, error) {
return buildDesktopAccount(
row.DesktopID,
row.TenantID,
row.WorkspaceID,
row.UserID,
row.ClientID,
row.PlatformID,
row.PlatformUid,
row.AccountFingerprint,
row.DisplayName,
row.Health,
row.VerifiedAt,
row.Tags,
row.SyncVersion,
row.DeletedAt,
row.DeleteRequestedAt,
row.CreatedAt,
row.UpdatedAt,
)
}
func desktopAccountFromUpsertRow(row generated.UpsertDesktopAccountRow) (*DesktopAccount, error) {
return buildDesktopAccount(
row.DesktopID,
row.TenantID,
row.WorkspaceID,
row.UserID,
row.ClientID,
row.PlatformID,
row.PlatformUid,
row.AccountFingerprint,
row.DisplayName,
row.Health,
row.VerifiedAt,
row.Tags,
row.SyncVersion,
row.DeletedAt,
row.DeleteRequestedAt,
row.CreatedAt,
row.UpdatedAt,
)
}
func desktopAccountFromPatchRow(row generated.PatchDesktopAccountRow) (*DesktopAccount, error) {
return buildDesktopAccount(
row.DesktopID,
row.TenantID,
row.WorkspaceID,
row.UserID,
row.ClientID,
row.PlatformID,
row.PlatformUid,
row.AccountFingerprint,
row.DisplayName,
row.Health,
row.VerifiedAt,
row.Tags,
row.SyncVersion,
row.DeletedAt,
row.DeleteRequestedAt,
row.CreatedAt,
row.UpdatedAt,
)
}
func desktopAccountFromTombstoneRow(row generated.TombstoneDesktopAccountRow) (*DesktopAccount, error) {
return buildDesktopAccount(
row.DesktopID,
row.TenantID,
row.WorkspaceID,
row.UserID,
row.ClientID,
row.PlatformID,
row.PlatformUid,
row.AccountFingerprint,
row.DisplayName,
row.Health,
row.VerifiedAt,
row.Tags,
row.SyncVersion,
row.DeletedAt,
row.DeleteRequestedAt,
row.CreatedAt,
row.UpdatedAt,
)
}
func desktopAccountFromMarkDeleteRow(row generated.MarkDesktopAccountDeleteRequestedRow) (*DesktopAccount, error) {
return buildDesktopAccount(
row.DesktopID,
row.TenantID,
row.WorkspaceID,
row.UserID,
row.ClientID,
row.PlatformID,
row.PlatformUid,
row.AccountFingerprint,
row.DisplayName,
row.Health,
row.VerifiedAt,
row.Tags,
row.SyncVersion,
row.DeletedAt,
row.DeleteRequestedAt,
row.CreatedAt,
row.UpdatedAt,
)
}
func desktopAccountFromClearDeleteRow(row generated.ClearDesktopAccountDeleteRequestedRow) (*DesktopAccount, error) {
return buildDesktopAccount(
row.DesktopID,
row.TenantID,
row.WorkspaceID,
row.UserID,
row.ClientID,
row.PlatformID,
row.PlatformUid,
row.AccountFingerprint,
row.DisplayName,
row.Health,
row.VerifiedAt,
row.Tags,
row.SyncVersion,
row.DeletedAt,
row.DeleteRequestedAt,
row.CreatedAt,
row.UpdatedAt,
)
}
func buildDesktopAccount(
desktopID pgtype.UUID,
tenantID int64,
workspaceID int64,
userID int64,
clientID pgtype.UUID,
platform string,
platformUID string,
accountFingerprint pgtype.Text,
displayName string,
health string,
verifiedAt pgtype.Timestamptz,
tags []byte,
syncVersion int64,
deletedAt pgtype.Timestamptz,
deleteRequestedAt pgtype.Timestamptz,
createdAt pgtype.Timestamptz,
updatedAt pgtype.Timestamptz,
) (*DesktopAccount, error) {
tagList, err := unmarshalStringSlice(tags)
if err != nil {
return nil, fmt.Errorf("unmarshal desktop account tags: %w", err)
}
return &DesktopAccount{
DesktopID: uuidFromPG(desktopID),
TenantID: tenantID,
WorkspaceID: workspaceID,
UserID: userID,
ClientID: nullableUUID(clientID),
Platform: platform,
PlatformUID: platformUID,
AccountFingerprint: nullableText(accountFingerprint),
DisplayName: displayName,
Health: health,
VerifiedAt: optionalTime(verifiedAt),
Tags: tagList,
SyncVersion: syncVersion,
DeletedAt: optionalTime(deletedAt),
DeleteRequestedAt: optionalTime(deleteRequestedAt),
CreatedAt: timeFromTimestamp(createdAt),
UpdatedAt: timeFromTimestamp(updatedAt),
}, nil
}
func legacyStatusFromHealth(health string) string {
switch health {
case "live":
return "active"
case "captcha":
return "captcha"
case "risk":
return "risk"
default:
return "expired"
}
}
func legacyStatusPtrFromHealth(health *string) *string {
if health == nil {
return nil
}
value := legacyStatusFromHealth(*health)
return &value
}
@@ -0,0 +1,174 @@
package repository
import (
"context"
"time"
"github.com/google/uuid"
"github.com/geo-platform/tenant-api/internal/tenant/repository/generated"
)
type DesktopClient struct {
ID uuid.UUID
TenantID int64
WorkspaceID int64
UserID int64
TokenHash []byte
DeviceName *string
OS *string
CPUArch *string
ClientVersion *string
Channel *string
CreatedAt time.Time
LastSeenAt *time.Time
LastRotatedAt *time.Time
RevokedAt *time.Time
}
type RegisterDesktopClientParams struct {
ID uuid.UUID
TenantID int64
WorkspaceID int64
UserID int64
TokenHash []byte
DeviceName *string
OS *string
CPUArch *string
ClientVersion *string
Channel *string
}
type HeartbeatDesktopClientParams struct {
ID uuid.UUID
WorkspaceID int64
DeviceName *string
OS *string
CPUArch *string
ClientVersion *string
Channel *string
}
type RotateDesktopClientTokenParams struct {
ID uuid.UUID
WorkspaceID int64
TokenHash []byte
}
type DesktopClientRepository interface {
Register(ctx context.Context, params RegisterDesktopClientParams) (*DesktopClient, error)
GetByTokenHash(ctx context.Context, tokenHash []byte) (*DesktopClient, error)
RotateToken(ctx context.Context, params RotateDesktopClientTokenParams) (*DesktopClient, error)
Heartbeat(ctx context.Context, params HeartbeatDesktopClientParams) (*DesktopClient, error)
Revoke(ctx context.Context, id uuid.UUID, workspaceID int64) (*DesktopClient, error)
ListByWorkspace(ctx context.Context, workspaceID int64) ([]DesktopClient, error)
}
type desktopClientRepository struct {
q generated.Querier
}
func NewDesktopClientRepository(db generated.DBTX) DesktopClientRepository {
return &desktopClientRepository{q: newQuerier(db)}
}
func (r *desktopClientRepository) Register(ctx context.Context, params RegisterDesktopClientParams) (*DesktopClient, error) {
row, err := r.q.RegisterDesktopClient(ctx, generated.RegisterDesktopClientParams{
ID: pgUUID(params.ID),
TenantID: params.TenantID,
WorkspaceID: params.WorkspaceID,
UserID: params.UserID,
TokenHash: params.TokenHash,
DeviceName: pgText(params.DeviceName),
Os: pgText(params.OS),
CpuArch: pgText(params.CPUArch),
ClientVersion: pgText(params.ClientVersion),
Channel: pgText(params.Channel),
})
if err != nil {
return nil, err
}
return desktopClientFromGenerated(row), nil
}
func (r *desktopClientRepository) GetByTokenHash(ctx context.Context, tokenHash []byte) (*DesktopClient, error) {
row, err := r.q.GetDesktopClientByTokenHash(ctx, tokenHash)
if err != nil {
return nil, err
}
return desktopClientFromGenerated(row), nil
}
func (r *desktopClientRepository) RotateToken(ctx context.Context, params RotateDesktopClientTokenParams) (*DesktopClient, error) {
row, err := r.q.RotateDesktopClientToken(ctx, generated.RotateDesktopClientTokenParams{
ID: pgUUID(params.ID),
WorkspaceID: params.WorkspaceID,
TokenHash: params.TokenHash,
})
if err != nil {
return nil, err
}
return desktopClientFromGenerated(row), nil
}
func (r *desktopClientRepository) Heartbeat(ctx context.Context, params HeartbeatDesktopClientParams) (*DesktopClient, error) {
row, err := r.q.HeartbeatDesktopClient(ctx, generated.HeartbeatDesktopClientParams{
ID: pgUUID(params.ID),
WorkspaceID: params.WorkspaceID,
DeviceName: pgText(params.DeviceName),
Os: pgText(params.OS),
CpuArch: pgText(params.CPUArch),
ClientVersion: pgText(params.ClientVersion),
Channel: pgText(params.Channel),
})
if err != nil {
return nil, err
}
return desktopClientFromGenerated(row), nil
}
func (r *desktopClientRepository) Revoke(ctx context.Context, id uuid.UUID, workspaceID int64) (*DesktopClient, error) {
row, err := r.q.RevokeDesktopClient(ctx, generated.RevokeDesktopClientParams{
ID: pgUUID(id),
WorkspaceID: workspaceID,
})
if err != nil {
return nil, err
}
return desktopClientFromGenerated(row), nil
}
func (r *desktopClientRepository) ListByWorkspace(ctx context.Context, workspaceID int64) ([]DesktopClient, error) {
rows, err := r.q.ListDesktopClientsByWorkspace(ctx, workspaceID)
if err != nil {
return nil, err
}
items := make([]DesktopClient, 0, len(rows))
for _, row := range rows {
item := desktopClientFromGenerated(row)
if item != nil {
items = append(items, *item)
}
}
return items, nil
}
func desktopClientFromGenerated(row generated.DesktopClient) *DesktopClient {
return &DesktopClient{
ID: uuidFromPG(row.ID),
TenantID: row.TenantID,
WorkspaceID: row.WorkspaceID,
UserID: row.UserID,
TokenHash: row.TokenHash,
DeviceName: nullableText(row.DeviceName),
OS: nullableText(row.Os),
CPUArch: nullableText(row.CpuArch),
ClientVersion: nullableText(row.ClientVersion),
Channel: nullableText(row.Channel),
CreatedAt: timeFromTimestamp(row.CreatedAt),
LastSeenAt: optionalTime(row.LastSeenAt),
LastRotatedAt: optionalTime(row.LastRotatedAt),
RevokedAt: optionalTime(row.RevokedAt),
}
}
@@ -0,0 +1,381 @@
package repository
import (
"context"
"time"
"github.com/google/uuid"
"github.com/geo-platform/tenant-api/internal/tenant/repository/generated"
)
type DesktopPublishJob struct {
DesktopID uuid.UUID
TenantID int64
WorkspaceID int64
CreatedByUserID int64
Title string
ContentRef []byte
ScheduledAt *time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
type CreateDesktopPublishJobParams struct {
DesktopID uuid.UUID
TenantID int64
WorkspaceID int64
CreatedByUserID int64
Title string
ContentRef []byte
ScheduledAt *time.Time
}
type DesktopTask struct {
DesktopID uuid.UUID
JobID uuid.UUID
TenantID int64
WorkspaceID int64
TargetAccountID uuid.UUID
TargetClientID uuid.UUID
Platform string
Kind string
Payload []byte
Status string
DedupKey *string
ActiveAttemptID *uuid.UUID
LeaseExpiresAt *time.Time
Attempts int
ParkedReason *string
Result []byte
Error []byte
CreatedAt time.Time
UpdatedAt time.Time
}
type CreateDesktopTaskParams struct {
DesktopID uuid.UUID
JobID uuid.UUID
TenantID int64
WorkspaceID int64
TargetAccountID uuid.UUID
TargetClientID uuid.UUID
Platform string
Kind string
Payload []byte
Status string
DedupKey *string
ParkedReason *string
}
type DesktopTaskLeaseParams struct {
AttemptID uuid.UUID
LeaseTokenHash []byte
}
type DesktopTaskAttempt struct {
DesktopID uuid.UUID
TaskID uuid.UUID
ClientID uuid.UUID
StartedAt time.Time
EndedAt *time.Time
FinalStatus *string
Error []byte
CreatedAt time.Time
}
type CreateDesktopTaskAttemptParams struct {
DesktopID uuid.UUID
TaskID uuid.UUID
ClientID uuid.UUID
LeaseTokenHash []byte
}
type FinishDesktopTaskAttemptParams struct {
TaskID uuid.UUID
AttemptID uuid.UUID
FinalStatus *string
Error []byte
}
type DesktopTaskRepository interface {
CreatePublishJob(ctx context.Context, params CreateDesktopPublishJobParams) (*DesktopPublishJob, error)
CreateTask(ctx context.Context, params CreateDesktopTaskParams) (*DesktopTask, error)
GetByDesktopID(ctx context.Context, desktopID uuid.UUID, workspaceID int64) (*DesktopTask, error)
LeaseNextQueued(ctx context.Context, clientID uuid.UUID, kind *string, params DesktopTaskLeaseParams) (*DesktopTask, error)
LeaseQueuedByDesktopID(ctx context.Context, desktopID, clientID uuid.UUID, params DesktopTaskLeaseParams) (*DesktopTask, error)
LeaseParked(ctx context.Context, desktopID, clientID uuid.UUID, params DesktopTaskLeaseParams) (*DesktopTask, error)
ExtendLease(ctx context.Context, desktopID uuid.UUID, leaseTokenHash []byte) (*DesktopTask, error)
Park(ctx context.Context, desktopID uuid.UUID, leaseTokenHash []byte, parkedReason string) (*DesktopTask, error)
Complete(ctx context.Context, desktopID uuid.UUID, leaseTokenHash []byte, status string, resultJSON, errorJSON []byte) (*DesktopTask, error)
CancelByLease(ctx context.Context, desktopID uuid.UUID, leaseTokenHash []byte, errorJSON []byte) (*DesktopTask, error)
CancelByClient(ctx context.Context, desktopID, clientID uuid.UUID, errorJSON []byte) (*DesktopTask, error)
TenantCancel(ctx context.Context, desktopID uuid.UUID, workspaceID int64, errorJSON []byte) (*DesktopTask, error)
Reconcile(ctx context.Context, desktopID uuid.UUID, workspaceID int64, status string, resultJSON, errorJSON []byte) (*DesktopTask, error)
MarkUnknownByClient(ctx context.Context, clientID uuid.UUID, workspaceID int64, errorJSON []byte) (int64, error)
CreateAttempt(ctx context.Context, params CreateDesktopTaskAttemptParams) (*DesktopTaskAttempt, error)
FinishAttempt(ctx context.Context, params FinishDesktopTaskAttemptParams) error
}
type desktopTaskRepository struct {
q generated.Querier
}
func NewDesktopTaskRepository(db generated.DBTX) DesktopTaskRepository {
return &desktopTaskRepository{q: newQuerier(db)}
}
func (r *desktopTaskRepository) CreatePublishJob(ctx context.Context, params CreateDesktopPublishJobParams) (*DesktopPublishJob, error) {
row, err := r.q.CreateDesktopPublishJob(ctx, generated.CreateDesktopPublishJobParams{
DesktopID: pgUUID(params.DesktopID),
TenantID: params.TenantID,
WorkspaceID: params.WorkspaceID,
CreatedByUserID: params.CreatedByUserID,
Title: params.Title,
ContentRef: params.ContentRef,
ScheduledAt: pgTimestamp(params.ScheduledAt),
})
if err != nil {
return nil, err
}
return desktopPublishJobFromGenerated(row), nil
}
func (r *desktopTaskRepository) CreateTask(ctx context.Context, params CreateDesktopTaskParams) (*DesktopTask, error) {
row, err := r.q.CreateDesktopTask(ctx, generated.CreateDesktopTaskParams{
DesktopID: pgUUID(params.DesktopID),
JobID: pgUUID(params.JobID),
TenantID: params.TenantID,
WorkspaceID: params.WorkspaceID,
TargetAccountID: pgUUID(params.TargetAccountID),
TargetClientID: pgUUID(params.TargetClientID),
PlatformID: params.Platform,
Kind: params.Kind,
Payload: params.Payload,
Status: params.Status,
DedupKey: pgText(params.DedupKey),
ParkedReason: pgText(params.ParkedReason),
})
if err != nil {
return nil, err
}
return desktopTaskFromGenerated(row), nil
}
func (r *desktopTaskRepository) GetByDesktopID(ctx context.Context, desktopID uuid.UUID, workspaceID int64) (*DesktopTask, error) {
row, err := r.q.GetDesktopTaskByDesktopID(ctx, generated.GetDesktopTaskByDesktopIDParams{
DesktopID: pgUUID(desktopID),
WorkspaceID: workspaceID,
})
if err != nil {
return nil, err
}
return desktopTaskFromGenerated(row), nil
}
func (r *desktopTaskRepository) LeaseNextQueued(ctx context.Context, clientID uuid.UUID, kind *string, params DesktopTaskLeaseParams) (*DesktopTask, error) {
row, err := r.q.LeaseNextQueuedDesktopTask(ctx, generated.LeaseNextQueuedDesktopTaskParams{
AttemptID: pgUUID(params.AttemptID),
LeaseTokenHash: params.LeaseTokenHash,
ClientID: pgUUID(clientID),
Kind: pgText(kind),
})
if err != nil {
return nil, err
}
return desktopTaskFromGenerated(row), nil
}
func (r *desktopTaskRepository) LeaseQueuedByDesktopID(ctx context.Context, desktopID, clientID uuid.UUID, params DesktopTaskLeaseParams) (*DesktopTask, error) {
row, err := r.q.LeaseQueuedDesktopTaskByDesktopID(ctx, generated.LeaseQueuedDesktopTaskByDesktopIDParams{
AttemptID: pgUUID(params.AttemptID),
LeaseTokenHash: params.LeaseTokenHash,
DesktopID: pgUUID(desktopID),
ClientID: pgUUID(clientID),
})
if err != nil {
return nil, err
}
return desktopTaskFromGenerated(row), nil
}
func (r *desktopTaskRepository) LeaseParked(ctx context.Context, desktopID, clientID uuid.UUID, params DesktopTaskLeaseParams) (*DesktopTask, error) {
row, err := r.q.LeaseParkedDesktopTask(ctx, generated.LeaseParkedDesktopTaskParams{
AttemptID: pgUUID(params.AttemptID),
LeaseTokenHash: params.LeaseTokenHash,
DesktopID: pgUUID(desktopID),
ClientID: pgUUID(clientID),
})
if err != nil {
return nil, err
}
return desktopTaskFromGenerated(row), nil
}
func (r *desktopTaskRepository) ExtendLease(ctx context.Context, desktopID uuid.UUID, leaseTokenHash []byte) (*DesktopTask, error) {
row, err := r.q.ExtendDesktopTaskLease(ctx, generated.ExtendDesktopTaskLeaseParams{
DesktopID: pgUUID(desktopID),
LeaseTokenHash: leaseTokenHash,
})
if err != nil {
return nil, err
}
return desktopTaskFromGenerated(row), nil
}
func (r *desktopTaskRepository) Park(ctx context.Context, desktopID uuid.UUID, leaseTokenHash []byte, parkedReason string) (*DesktopTask, error) {
row, err := r.q.ParkDesktopTask(ctx, generated.ParkDesktopTaskParams{
ParkedReason: pgText(&parkedReason),
DesktopID: pgUUID(desktopID),
LeaseTokenHash: leaseTokenHash,
})
if err != nil {
return nil, err
}
return desktopTaskFromGenerated(row), nil
}
func (r *desktopTaskRepository) Complete(ctx context.Context, desktopID uuid.UUID, leaseTokenHash []byte, status string, resultJSON, errorJSON []byte) (*DesktopTask, error) {
row, err := r.q.CompleteDesktopTask(ctx, generated.CompleteDesktopTaskParams{
Status: status,
Result: resultJSON,
Error: errorJSON,
DesktopID: pgUUID(desktopID),
LeaseTokenHash: leaseTokenHash,
})
if err != nil {
return nil, err
}
return desktopTaskFromGenerated(row), nil
}
func (r *desktopTaskRepository) CancelByLease(ctx context.Context, desktopID uuid.UUID, leaseTokenHash []byte, errorJSON []byte) (*DesktopTask, error) {
row, err := r.q.CancelDesktopTaskByLease(ctx, generated.CancelDesktopTaskByLeaseParams{
Error: errorJSON,
DesktopID: pgUUID(desktopID),
LeaseTokenHash: leaseTokenHash,
})
if err != nil {
return nil, err
}
return desktopTaskFromGenerated(row), nil
}
func (r *desktopTaskRepository) CancelByClient(ctx context.Context, desktopID, clientID uuid.UUID, errorJSON []byte) (*DesktopTask, error) {
row, err := r.q.CancelDesktopTaskByClient(ctx, generated.CancelDesktopTaskByClientParams{
Error: errorJSON,
DesktopID: pgUUID(desktopID),
ClientID: pgUUID(clientID),
})
if err != nil {
return nil, err
}
return desktopTaskFromGenerated(row), nil
}
func (r *desktopTaskRepository) TenantCancel(ctx context.Context, desktopID uuid.UUID, workspaceID int64, errorJSON []byte) (*DesktopTask, error) {
row, err := r.q.TenantCancelDesktopTask(ctx, generated.TenantCancelDesktopTaskParams{
Error: errorJSON,
DesktopID: pgUUID(desktopID),
WorkspaceID: workspaceID,
})
if err != nil {
return nil, err
}
return desktopTaskFromGenerated(row), nil
}
func (r *desktopTaskRepository) Reconcile(ctx context.Context, desktopID uuid.UUID, workspaceID int64, status string, resultJSON, errorJSON []byte) (*DesktopTask, error) {
row, err := r.q.ReconcileDesktopTask(ctx, generated.ReconcileDesktopTaskParams{
Status: status,
Result: resultJSON,
Error: errorJSON,
DesktopID: pgUUID(desktopID),
WorkspaceID: workspaceID,
})
if err != nil {
return nil, err
}
return desktopTaskFromGenerated(row), nil
}
func (r *desktopTaskRepository) MarkUnknownByClient(ctx context.Context, clientID uuid.UUID, workspaceID int64, errorJSON []byte) (int64, error) {
return r.q.MarkDesktopTasksUnknownByClient(ctx, generated.MarkDesktopTasksUnknownByClientParams{
Error: errorJSON,
ClientID: pgUUID(clientID),
WorkspaceID: workspaceID,
})
}
func (r *desktopTaskRepository) CreateAttempt(ctx context.Context, params CreateDesktopTaskAttemptParams) (*DesktopTaskAttempt, error) {
row, err := r.q.CreateDesktopTaskAttempt(ctx, generated.CreateDesktopTaskAttemptParams{
DesktopID: pgUUID(params.DesktopID),
TaskID: pgUUID(params.TaskID),
ClientID: pgUUID(params.ClientID),
LeaseTokenHash: params.LeaseTokenHash,
})
if err != nil {
return nil, err
}
return desktopTaskAttemptFromGenerated(row), nil
}
func (r *desktopTaskRepository) FinishAttempt(ctx context.Context, params FinishDesktopTaskAttemptParams) error {
return r.q.FinishDesktopTaskAttempt(ctx, generated.FinishDesktopTaskAttemptParams{
FinalStatus: pgText(params.FinalStatus),
Error: params.Error,
TaskID: pgUUID(params.TaskID),
AttemptID: pgUUID(params.AttemptID),
})
}
func desktopPublishJobFromGenerated(row generated.DesktopPublishJob) *DesktopPublishJob {
return &DesktopPublishJob{
DesktopID: uuidFromPG(row.DesktopID),
TenantID: row.TenantID,
WorkspaceID: row.WorkspaceID,
CreatedByUserID: row.CreatedByUserID,
Title: row.Title,
ContentRef: row.ContentRef,
ScheduledAt: optionalTime(row.ScheduledAt),
CreatedAt: timeFromTimestamp(row.CreatedAt),
UpdatedAt: timeFromTimestamp(row.UpdatedAt),
}
}
func desktopTaskFromGenerated(row generated.DesktopTask) *DesktopTask {
return &DesktopTask{
DesktopID: uuidFromPG(row.DesktopID),
JobID: uuidFromPG(row.JobID),
TenantID: row.TenantID,
WorkspaceID: row.WorkspaceID,
TargetAccountID: uuidFromPG(row.TargetAccountID),
TargetClientID: uuidFromPG(row.TargetClientID),
Platform: row.PlatformID,
Kind: row.Kind,
Payload: row.Payload,
Status: row.Status,
DedupKey: nullableText(row.DedupKey),
ActiveAttemptID: nullableUUID(row.ActiveAttemptID),
LeaseExpiresAt: optionalTime(row.LeaseExpiresAt),
Attempts: int(row.Attempts),
ParkedReason: nullableText(row.ParkedReason),
Result: row.Result,
Error: row.Error,
CreatedAt: timeFromTimestamp(row.CreatedAt),
UpdatedAt: timeFromTimestamp(row.UpdatedAt),
}
}
func desktopTaskAttemptFromGenerated(row generated.DesktopTaskAttempt) *DesktopTaskAttempt {
return &DesktopTaskAttempt{
DesktopID: uuidFromPG(row.DesktopID),
TaskID: uuidFromPG(row.TaskID),
ClientID: uuidFromPG(row.ClientID),
StartedAt: timeFromTimestamp(row.StartedAt),
EndedAt: optionalTime(row.EndedAt),
FinalStatus: nullableText(row.FinalStatus),
Error: row.Error,
CreatedAt: timeFromTimestamp(row.CreatedAt),
}
}
@@ -12,18 +12,28 @@ import (
)
const getTenantMembership = `-- name: GetTenantMembership :one
SELECT id, tenant_id, user_id, tenant_role, created_at
FROM tenant_memberships
WHERE user_id = $1 AND deleted_at IS NULL
SELECT tm.id,
tm.tenant_id,
tm.user_id,
tm.tenant_role,
tm.created_at,
wm.workspace_id AS primary_workspace_id
FROM tenant_memberships tm
JOIN workspace_memberships wm
ON wm.tenant_id = tm.tenant_id
AND wm.user_id = tm.user_id
AND wm.is_primary = TRUE
WHERE tm.user_id = $1 AND tm.deleted_at IS NULL
LIMIT 1
`
type GetTenantMembershipRow struct {
ID int64 `json:"id"`
TenantID int64 `json:"tenant_id"`
UserID int64 `json:"user_id"`
TenantRole string `json:"tenant_role"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
ID int64 `json:"id"`
TenantID int64 `json:"tenant_id"`
UserID int64 `json:"user_id"`
TenantRole string `json:"tenant_role"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
PrimaryWorkspaceID int64 `json:"primary_workspace_id"`
}
func (q *Queries) GetTenantMembership(ctx context.Context, userID int64) (GetTenantMembershipRow, error) {
@@ -35,14 +45,24 @@ func (q *Queries) GetTenantMembership(ctx context.Context, userID int64) (GetTen
&i.UserID,
&i.TenantRole,
&i.CreatedAt,
&i.PrimaryWorkspaceID,
)
return i, err
}
const getTenantMembershipByTenantAndUser = `-- name: GetTenantMembershipByTenantAndUser :one
SELECT id, tenant_id, user_id, tenant_role, created_at
FROM tenant_memberships
WHERE tenant_id = $1 AND user_id = $2 AND deleted_at IS NULL
SELECT tm.id,
tm.tenant_id,
tm.user_id,
tm.tenant_role,
tm.created_at,
wm.workspace_id AS primary_workspace_id
FROM tenant_memberships tm
JOIN workspace_memberships wm
ON wm.tenant_id = tm.tenant_id
AND wm.user_id = tm.user_id
AND wm.is_primary = TRUE
WHERE tm.tenant_id = $1 AND tm.user_id = $2 AND tm.deleted_at IS NULL
`
type GetTenantMembershipByTenantAndUserParams struct {
@@ -51,11 +71,12 @@ type GetTenantMembershipByTenantAndUserParams struct {
}
type GetTenantMembershipByTenantAndUserRow struct {
ID int64 `json:"id"`
TenantID int64 `json:"tenant_id"`
UserID int64 `json:"user_id"`
TenantRole string `json:"tenant_role"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
ID int64 `json:"id"`
TenantID int64 `json:"tenant_id"`
UserID int64 `json:"user_id"`
TenantRole string `json:"tenant_role"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
PrimaryWorkspaceID int64 `json:"primary_workspace_id"`
}
func (q *Queries) GetTenantMembershipByTenantAndUser(ctx context.Context, arg GetTenantMembershipByTenantAndUserParams) (GetTenantMembershipByTenantAndUserRow, error) {
@@ -67,6 +88,7 @@ func (q *Queries) GetTenantMembershipByTenantAndUser(ctx context.Context, arg Ge
&i.UserID,
&i.TenantRole,
&i.CreatedAt,
&i.PrimaryWorkspaceID,
)
return i, err
}
@@ -0,0 +1,748 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.30.0
// source: desktop_account.sql
package generated
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const clearDesktopAccountDeleteRequested = `-- name: ClearDesktopAccountDeleteRequested :one
UPDATE platform_accounts
SET delete_requested_at = NULL,
sync_version = sync_version + 1,
updated_at = now()
WHERE desktop_id = $1
AND workspace_id = $2
AND deleted_at IS NULL
RETURNING
desktop_id,
tenant_id,
workspace_id,
user_id,
client_id,
platform_id,
platform_uid,
account_fingerprint,
display_name,
health,
verified_at,
tags,
sync_version,
deleted_at,
delete_requested_at,
created_at,
updated_at
`
type ClearDesktopAccountDeleteRequestedParams struct {
DesktopID pgtype.UUID `json:"desktop_id"`
WorkspaceID int64 `json:"workspace_id"`
}
type ClearDesktopAccountDeleteRequestedRow struct {
DesktopID pgtype.UUID `json:"desktop_id"`
TenantID int64 `json:"tenant_id"`
WorkspaceID int64 `json:"workspace_id"`
UserID int64 `json:"user_id"`
ClientID pgtype.UUID `json:"client_id"`
PlatformID string `json:"platform_id"`
PlatformUid string `json:"platform_uid"`
AccountFingerprint pgtype.Text `json:"account_fingerprint"`
DisplayName string `json:"display_name"`
Health string `json:"health"`
VerifiedAt pgtype.Timestamptz `json:"verified_at"`
Tags []byte `json:"tags"`
SyncVersion int64 `json:"sync_version"`
DeletedAt pgtype.Timestamptz `json:"deleted_at"`
DeleteRequestedAt pgtype.Timestamptz `json:"delete_requested_at"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
func (q *Queries) ClearDesktopAccountDeleteRequested(ctx context.Context, arg ClearDesktopAccountDeleteRequestedParams) (ClearDesktopAccountDeleteRequestedRow, error) {
row := q.db.QueryRow(ctx, clearDesktopAccountDeleteRequested, arg.DesktopID, arg.WorkspaceID)
var i ClearDesktopAccountDeleteRequestedRow
err := row.Scan(
&i.DesktopID,
&i.TenantID,
&i.WorkspaceID,
&i.UserID,
&i.ClientID,
&i.PlatformID,
&i.PlatformUid,
&i.AccountFingerprint,
&i.DisplayName,
&i.Health,
&i.VerifiedAt,
&i.Tags,
&i.SyncVersion,
&i.DeletedAt,
&i.DeleteRequestedAt,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const getDesktopAccountByDesktopID = `-- name: GetDesktopAccountByDesktopID :one
SELECT
desktop_id,
tenant_id,
workspace_id,
user_id,
client_id,
platform_id,
platform_uid,
account_fingerprint,
display_name,
health,
verified_at,
tags,
sync_version,
deleted_at,
delete_requested_at,
created_at,
updated_at
FROM platform_accounts
WHERE desktop_id = $1
AND workspace_id = $2
LIMIT 1
`
type GetDesktopAccountByDesktopIDParams struct {
DesktopID pgtype.UUID `json:"desktop_id"`
WorkspaceID int64 `json:"workspace_id"`
}
type GetDesktopAccountByDesktopIDRow struct {
DesktopID pgtype.UUID `json:"desktop_id"`
TenantID int64 `json:"tenant_id"`
WorkspaceID int64 `json:"workspace_id"`
UserID int64 `json:"user_id"`
ClientID pgtype.UUID `json:"client_id"`
PlatformID string `json:"platform_id"`
PlatformUid string `json:"platform_uid"`
AccountFingerprint pgtype.Text `json:"account_fingerprint"`
DisplayName string `json:"display_name"`
Health string `json:"health"`
VerifiedAt pgtype.Timestamptz `json:"verified_at"`
Tags []byte `json:"tags"`
SyncVersion int64 `json:"sync_version"`
DeletedAt pgtype.Timestamptz `json:"deleted_at"`
DeleteRequestedAt pgtype.Timestamptz `json:"delete_requested_at"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
func (q *Queries) GetDesktopAccountByDesktopID(ctx context.Context, arg GetDesktopAccountByDesktopIDParams) (GetDesktopAccountByDesktopIDRow, error) {
row := q.db.QueryRow(ctx, getDesktopAccountByDesktopID, arg.DesktopID, arg.WorkspaceID)
var i GetDesktopAccountByDesktopIDRow
err := row.Scan(
&i.DesktopID,
&i.TenantID,
&i.WorkspaceID,
&i.UserID,
&i.ClientID,
&i.PlatformID,
&i.PlatformUid,
&i.AccountFingerprint,
&i.DisplayName,
&i.Health,
&i.VerifiedAt,
&i.Tags,
&i.SyncVersion,
&i.DeletedAt,
&i.DeleteRequestedAt,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const getDesktopAccountByIdentity = `-- name: GetDesktopAccountByIdentity :one
SELECT
desktop_id,
tenant_id,
workspace_id,
user_id,
client_id,
platform_id,
platform_uid,
account_fingerprint,
display_name,
health,
verified_at,
tags,
sync_version,
deleted_at,
delete_requested_at,
created_at,
updated_at
FROM platform_accounts
WHERE workspace_id = $1
AND platform_id = $2
AND platform_uid = $3
AND deleted_at IS NULL
LIMIT 1
`
type GetDesktopAccountByIdentityParams struct {
WorkspaceID int64 `json:"workspace_id"`
PlatformID string `json:"platform_id"`
PlatformUid string `json:"platform_uid"`
}
type GetDesktopAccountByIdentityRow struct {
DesktopID pgtype.UUID `json:"desktop_id"`
TenantID int64 `json:"tenant_id"`
WorkspaceID int64 `json:"workspace_id"`
UserID int64 `json:"user_id"`
ClientID pgtype.UUID `json:"client_id"`
PlatformID string `json:"platform_id"`
PlatformUid string `json:"platform_uid"`
AccountFingerprint pgtype.Text `json:"account_fingerprint"`
DisplayName string `json:"display_name"`
Health string `json:"health"`
VerifiedAt pgtype.Timestamptz `json:"verified_at"`
Tags []byte `json:"tags"`
SyncVersion int64 `json:"sync_version"`
DeletedAt pgtype.Timestamptz `json:"deleted_at"`
DeleteRequestedAt pgtype.Timestamptz `json:"delete_requested_at"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
func (q *Queries) GetDesktopAccountByIdentity(ctx context.Context, arg GetDesktopAccountByIdentityParams) (GetDesktopAccountByIdentityRow, error) {
row := q.db.QueryRow(ctx, getDesktopAccountByIdentity, arg.WorkspaceID, arg.PlatformID, arg.PlatformUid)
var i GetDesktopAccountByIdentityRow
err := row.Scan(
&i.DesktopID,
&i.TenantID,
&i.WorkspaceID,
&i.UserID,
&i.ClientID,
&i.PlatformID,
&i.PlatformUid,
&i.AccountFingerprint,
&i.DisplayName,
&i.Health,
&i.VerifiedAt,
&i.Tags,
&i.SyncVersion,
&i.DeletedAt,
&i.DeleteRequestedAt,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const listDesktopAccountsByClient = `-- name: ListDesktopAccountsByClient :many
SELECT
desktop_id,
tenant_id,
workspace_id,
user_id,
client_id,
platform_id,
platform_uid,
account_fingerprint,
display_name,
health,
verified_at,
tags,
sync_version,
deleted_at,
delete_requested_at,
created_at,
updated_at
FROM platform_accounts
WHERE workspace_id = $1
AND client_id = $2
ORDER BY platform_id, display_name, created_at DESC
`
type ListDesktopAccountsByClientParams struct {
WorkspaceID int64 `json:"workspace_id"`
ClientID pgtype.UUID `json:"client_id"`
}
type ListDesktopAccountsByClientRow struct {
DesktopID pgtype.UUID `json:"desktop_id"`
TenantID int64 `json:"tenant_id"`
WorkspaceID int64 `json:"workspace_id"`
UserID int64 `json:"user_id"`
ClientID pgtype.UUID `json:"client_id"`
PlatformID string `json:"platform_id"`
PlatformUid string `json:"platform_uid"`
AccountFingerprint pgtype.Text `json:"account_fingerprint"`
DisplayName string `json:"display_name"`
Health string `json:"health"`
VerifiedAt pgtype.Timestamptz `json:"verified_at"`
Tags []byte `json:"tags"`
SyncVersion int64 `json:"sync_version"`
DeletedAt pgtype.Timestamptz `json:"deleted_at"`
DeleteRequestedAt pgtype.Timestamptz `json:"delete_requested_at"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
func (q *Queries) ListDesktopAccountsByClient(ctx context.Context, arg ListDesktopAccountsByClientParams) ([]ListDesktopAccountsByClientRow, error) {
rows, err := q.db.Query(ctx, listDesktopAccountsByClient, arg.WorkspaceID, arg.ClientID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListDesktopAccountsByClientRow
for rows.Next() {
var i ListDesktopAccountsByClientRow
if err := rows.Scan(
&i.DesktopID,
&i.TenantID,
&i.WorkspaceID,
&i.UserID,
&i.ClientID,
&i.PlatformID,
&i.PlatformUid,
&i.AccountFingerprint,
&i.DisplayName,
&i.Health,
&i.VerifiedAt,
&i.Tags,
&i.SyncVersion,
&i.DeletedAt,
&i.DeleteRequestedAt,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const markDesktopAccountDeleteRequested = `-- name: MarkDesktopAccountDeleteRequested :one
UPDATE platform_accounts
SET delete_requested_at = now(),
sync_version = sync_version + 1,
updated_at = now()
WHERE desktop_id = $1
AND workspace_id = $2
AND deleted_at IS NULL
RETURNING
desktop_id,
tenant_id,
workspace_id,
user_id,
client_id,
platform_id,
platform_uid,
account_fingerprint,
display_name,
health,
verified_at,
tags,
sync_version,
deleted_at,
delete_requested_at,
created_at,
updated_at
`
type MarkDesktopAccountDeleteRequestedParams struct {
DesktopID pgtype.UUID `json:"desktop_id"`
WorkspaceID int64 `json:"workspace_id"`
}
type MarkDesktopAccountDeleteRequestedRow struct {
DesktopID pgtype.UUID `json:"desktop_id"`
TenantID int64 `json:"tenant_id"`
WorkspaceID int64 `json:"workspace_id"`
UserID int64 `json:"user_id"`
ClientID pgtype.UUID `json:"client_id"`
PlatformID string `json:"platform_id"`
PlatformUid string `json:"platform_uid"`
AccountFingerprint pgtype.Text `json:"account_fingerprint"`
DisplayName string `json:"display_name"`
Health string `json:"health"`
VerifiedAt pgtype.Timestamptz `json:"verified_at"`
Tags []byte `json:"tags"`
SyncVersion int64 `json:"sync_version"`
DeletedAt pgtype.Timestamptz `json:"deleted_at"`
DeleteRequestedAt pgtype.Timestamptz `json:"delete_requested_at"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
func (q *Queries) MarkDesktopAccountDeleteRequested(ctx context.Context, arg MarkDesktopAccountDeleteRequestedParams) (MarkDesktopAccountDeleteRequestedRow, error) {
row := q.db.QueryRow(ctx, markDesktopAccountDeleteRequested, arg.DesktopID, arg.WorkspaceID)
var i MarkDesktopAccountDeleteRequestedRow
err := row.Scan(
&i.DesktopID,
&i.TenantID,
&i.WorkspaceID,
&i.UserID,
&i.ClientID,
&i.PlatformID,
&i.PlatformUid,
&i.AccountFingerprint,
&i.DisplayName,
&i.Health,
&i.VerifiedAt,
&i.Tags,
&i.SyncVersion,
&i.DeletedAt,
&i.DeleteRequestedAt,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const patchDesktopAccount = `-- name: PatchDesktopAccount :one
UPDATE platform_accounts
SET display_name = COALESCE($1::text, display_name),
nickname = COALESCE($1::text, nickname),
health = COALESCE($2, health),
status = COALESCE($3, status),
verified_at = COALESCE($4, verified_at),
last_check_at = COALESCE($4, last_check_at),
tags = COALESCE($5, tags),
sync_version = sync_version + 1,
updated_at = now()
WHERE desktop_id = $6
AND workspace_id = $7
AND sync_version = $8
AND deleted_at IS NULL
RETURNING
desktop_id,
tenant_id,
workspace_id,
user_id,
client_id,
platform_id,
platform_uid,
account_fingerprint,
display_name,
health,
verified_at,
tags,
sync_version,
deleted_at,
delete_requested_at,
created_at,
updated_at
`
type PatchDesktopAccountParams struct {
DisplayName pgtype.Text `json:"display_name"`
Health pgtype.Text `json:"health"`
LegacyStatus pgtype.Text `json:"legacy_status"`
VerifiedAt pgtype.Timestamptz `json:"verified_at"`
Tags []byte `json:"tags"`
DesktopID pgtype.UUID `json:"desktop_id"`
WorkspaceID int64 `json:"workspace_id"`
IfSyncVersion int64 `json:"if_sync_version"`
}
type PatchDesktopAccountRow struct {
DesktopID pgtype.UUID `json:"desktop_id"`
TenantID int64 `json:"tenant_id"`
WorkspaceID int64 `json:"workspace_id"`
UserID int64 `json:"user_id"`
ClientID pgtype.UUID `json:"client_id"`
PlatformID string `json:"platform_id"`
PlatformUid string `json:"platform_uid"`
AccountFingerprint pgtype.Text `json:"account_fingerprint"`
DisplayName string `json:"display_name"`
Health string `json:"health"`
VerifiedAt pgtype.Timestamptz `json:"verified_at"`
Tags []byte `json:"tags"`
SyncVersion int64 `json:"sync_version"`
DeletedAt pgtype.Timestamptz `json:"deleted_at"`
DeleteRequestedAt pgtype.Timestamptz `json:"delete_requested_at"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
func (q *Queries) PatchDesktopAccount(ctx context.Context, arg PatchDesktopAccountParams) (PatchDesktopAccountRow, error) {
row := q.db.QueryRow(ctx, patchDesktopAccount,
arg.DisplayName,
arg.Health,
arg.LegacyStatus,
arg.VerifiedAt,
arg.Tags,
arg.DesktopID,
arg.WorkspaceID,
arg.IfSyncVersion,
)
var i PatchDesktopAccountRow
err := row.Scan(
&i.DesktopID,
&i.TenantID,
&i.WorkspaceID,
&i.UserID,
&i.ClientID,
&i.PlatformID,
&i.PlatformUid,
&i.AccountFingerprint,
&i.DisplayName,
&i.Health,
&i.VerifiedAt,
&i.Tags,
&i.SyncVersion,
&i.DeletedAt,
&i.DeleteRequestedAt,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const tombstoneDesktopAccount = `-- name: TombstoneDesktopAccount :one
UPDATE platform_accounts
SET deleted_at = now(),
sync_version = sync_version + 1,
updated_at = now()
WHERE desktop_id = $1
AND workspace_id = $2
AND sync_version = $3
AND deleted_at IS NULL
RETURNING
desktop_id,
tenant_id,
workspace_id,
user_id,
client_id,
platform_id,
platform_uid,
account_fingerprint,
display_name,
health,
verified_at,
tags,
sync_version,
deleted_at,
delete_requested_at,
created_at,
updated_at
`
type TombstoneDesktopAccountParams struct {
DesktopID pgtype.UUID `json:"desktop_id"`
WorkspaceID int64 `json:"workspace_id"`
IfSyncVersion int64 `json:"if_sync_version"`
}
type TombstoneDesktopAccountRow struct {
DesktopID pgtype.UUID `json:"desktop_id"`
TenantID int64 `json:"tenant_id"`
WorkspaceID int64 `json:"workspace_id"`
UserID int64 `json:"user_id"`
ClientID pgtype.UUID `json:"client_id"`
PlatformID string `json:"platform_id"`
PlatformUid string `json:"platform_uid"`
AccountFingerprint pgtype.Text `json:"account_fingerprint"`
DisplayName string `json:"display_name"`
Health string `json:"health"`
VerifiedAt pgtype.Timestamptz `json:"verified_at"`
Tags []byte `json:"tags"`
SyncVersion int64 `json:"sync_version"`
DeletedAt pgtype.Timestamptz `json:"deleted_at"`
DeleteRequestedAt pgtype.Timestamptz `json:"delete_requested_at"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
func (q *Queries) TombstoneDesktopAccount(ctx context.Context, arg TombstoneDesktopAccountParams) (TombstoneDesktopAccountRow, error) {
row := q.db.QueryRow(ctx, tombstoneDesktopAccount, arg.DesktopID, arg.WorkspaceID, arg.IfSyncVersion)
var i TombstoneDesktopAccountRow
err := row.Scan(
&i.DesktopID,
&i.TenantID,
&i.WorkspaceID,
&i.UserID,
&i.ClientID,
&i.PlatformID,
&i.PlatformUid,
&i.AccountFingerprint,
&i.DisplayName,
&i.Health,
&i.VerifiedAt,
&i.Tags,
&i.SyncVersion,
&i.DeletedAt,
&i.DeleteRequestedAt,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const upsertDesktopAccount = `-- name: UpsertDesktopAccount :one
INSERT INTO platform_accounts (
desktop_id,
tenant_id,
workspace_id,
user_id,
client_id,
platform_id,
platform_uid,
nickname,
status,
metadata_json,
last_check_at,
account_fingerprint,
display_name,
health,
verified_at,
tags,
sync_version
)
VALUES (
$1,
$2,
$3,
$4,
$5,
$6,
$7,
$8::text,
$9,
$10,
$11,
$12,
$8::text,
$13,
$11,
$14,
1
)
ON CONFLICT (workspace_id, platform_id, platform_uid) WHERE deleted_at IS NULL
DO UPDATE SET
client_id = EXCLUDED.client_id,
user_id = EXCLUDED.user_id,
nickname = EXCLUDED.nickname,
status = EXCLUDED.status,
metadata_json = COALESCE(EXCLUDED.metadata_json, platform_accounts.metadata_json),
last_check_at = COALESCE(EXCLUDED.last_check_at, platform_accounts.last_check_at),
account_fingerprint = EXCLUDED.account_fingerprint,
display_name = EXCLUDED.display_name,
health = EXCLUDED.health,
verified_at = COALESCE(EXCLUDED.verified_at, platform_accounts.verified_at),
tags = EXCLUDED.tags,
sync_version = platform_accounts.sync_version + 1,
delete_requested_at = NULL,
updated_at = now()
WHERE platform_accounts.workspace_id = EXCLUDED.workspace_id
AND (
$15::bigint IS NULL
OR platform_accounts.sync_version = $15::bigint
)
RETURNING
desktop_id,
tenant_id,
workspace_id,
user_id,
client_id,
platform_id,
platform_uid,
account_fingerprint,
display_name,
health,
verified_at,
tags,
sync_version,
deleted_at,
delete_requested_at,
created_at,
updated_at
`
type UpsertDesktopAccountParams struct {
DesktopID pgtype.UUID `json:"desktop_id"`
TenantID int64 `json:"tenant_id"`
WorkspaceID int64 `json:"workspace_id"`
UserID int64 `json:"user_id"`
ClientID pgtype.UUID `json:"client_id"`
PlatformID string `json:"platform_id"`
PlatformUid string `json:"platform_uid"`
DisplayName string `json:"display_name"`
LegacyStatus string `json:"legacy_status"`
MetadataJson []byte `json:"metadata_json"`
VerifiedAt pgtype.Timestamptz `json:"verified_at"`
AccountFingerprint pgtype.Text `json:"account_fingerprint"`
Health string `json:"health"`
Tags []byte `json:"tags"`
IfSyncVersion pgtype.Int8 `json:"if_sync_version"`
}
type UpsertDesktopAccountRow struct {
DesktopID pgtype.UUID `json:"desktop_id"`
TenantID int64 `json:"tenant_id"`
WorkspaceID int64 `json:"workspace_id"`
UserID int64 `json:"user_id"`
ClientID pgtype.UUID `json:"client_id"`
PlatformID string `json:"platform_id"`
PlatformUid string `json:"platform_uid"`
AccountFingerprint pgtype.Text `json:"account_fingerprint"`
DisplayName string `json:"display_name"`
Health string `json:"health"`
VerifiedAt pgtype.Timestamptz `json:"verified_at"`
Tags []byte `json:"tags"`
SyncVersion int64 `json:"sync_version"`
DeletedAt pgtype.Timestamptz `json:"deleted_at"`
DeleteRequestedAt pgtype.Timestamptz `json:"delete_requested_at"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
func (q *Queries) UpsertDesktopAccount(ctx context.Context, arg UpsertDesktopAccountParams) (UpsertDesktopAccountRow, error) {
row := q.db.QueryRow(ctx, upsertDesktopAccount,
arg.DesktopID,
arg.TenantID,
arg.WorkspaceID,
arg.UserID,
arg.ClientID,
arg.PlatformID,
arg.PlatformUid,
arg.DisplayName,
arg.LegacyStatus,
arg.MetadataJson,
arg.VerifiedAt,
arg.AccountFingerprint,
arg.Health,
arg.Tags,
arg.IfSyncVersion,
)
var i UpsertDesktopAccountRow
err := row.Scan(
&i.DesktopID,
&i.TenantID,
&i.WorkspaceID,
&i.UserID,
&i.ClientID,
&i.PlatformID,
&i.PlatformUid,
&i.AccountFingerprint,
&i.DisplayName,
&i.Health,
&i.VerifiedAt,
&i.Tags,
&i.SyncVersion,
&i.DeletedAt,
&i.DeleteRequestedAt,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
@@ -0,0 +1,287 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.30.0
// source: desktop_client.sql
package generated
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const getDesktopClientByTokenHash = `-- name: GetDesktopClientByTokenHash :one
SELECT id, tenant_id, workspace_id, user_id, token_hash, device_name, os, cpu_arch, client_version, channel, created_at, last_seen_at, last_rotated_at, revoked_at
FROM desktop_clients
WHERE token_hash = $1
AND revoked_at IS NULL
LIMIT 1
`
func (q *Queries) GetDesktopClientByTokenHash(ctx context.Context, tokenHash []byte) (DesktopClient, error) {
row := q.db.QueryRow(ctx, getDesktopClientByTokenHash, tokenHash)
var i DesktopClient
err := row.Scan(
&i.ID,
&i.TenantID,
&i.WorkspaceID,
&i.UserID,
&i.TokenHash,
&i.DeviceName,
&i.Os,
&i.CpuArch,
&i.ClientVersion,
&i.Channel,
&i.CreatedAt,
&i.LastSeenAt,
&i.LastRotatedAt,
&i.RevokedAt,
)
return i, err
}
const heartbeatDesktopClient = `-- name: HeartbeatDesktopClient :one
UPDATE desktop_clients
SET device_name = COALESCE($1, device_name),
os = COALESCE($2, os),
cpu_arch = COALESCE($3, cpu_arch),
client_version = COALESCE($4, client_version),
channel = COALESCE($5, channel),
last_seen_at = now()
WHERE id = $6
AND workspace_id = $7
AND revoked_at IS NULL
RETURNING id, tenant_id, workspace_id, user_id, token_hash, device_name, os, cpu_arch, client_version, channel, created_at, last_seen_at, last_rotated_at, revoked_at
`
type HeartbeatDesktopClientParams struct {
DeviceName pgtype.Text `json:"device_name"`
Os pgtype.Text `json:"os"`
CpuArch pgtype.Text `json:"cpu_arch"`
ClientVersion pgtype.Text `json:"client_version"`
Channel pgtype.Text `json:"channel"`
ID pgtype.UUID `json:"id"`
WorkspaceID int64 `json:"workspace_id"`
}
func (q *Queries) HeartbeatDesktopClient(ctx context.Context, arg HeartbeatDesktopClientParams) (DesktopClient, error) {
row := q.db.QueryRow(ctx, heartbeatDesktopClient,
arg.DeviceName,
arg.Os,
arg.CpuArch,
arg.ClientVersion,
arg.Channel,
arg.ID,
arg.WorkspaceID,
)
var i DesktopClient
err := row.Scan(
&i.ID,
&i.TenantID,
&i.WorkspaceID,
&i.UserID,
&i.TokenHash,
&i.DeviceName,
&i.Os,
&i.CpuArch,
&i.ClientVersion,
&i.Channel,
&i.CreatedAt,
&i.LastSeenAt,
&i.LastRotatedAt,
&i.RevokedAt,
)
return i, err
}
const listDesktopClientsByWorkspace = `-- name: ListDesktopClientsByWorkspace :many
SELECT id, tenant_id, workspace_id, user_id, token_hash, device_name, os, cpu_arch, client_version, channel, created_at, last_seen_at, last_rotated_at, revoked_at
FROM desktop_clients
WHERE workspace_id = $1
AND revoked_at IS NULL
ORDER BY last_seen_at DESC NULLS LAST, created_at DESC
`
func (q *Queries) ListDesktopClientsByWorkspace(ctx context.Context, workspaceID int64) ([]DesktopClient, error) {
rows, err := q.db.Query(ctx, listDesktopClientsByWorkspace, workspaceID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []DesktopClient
for rows.Next() {
var i DesktopClient
if err := rows.Scan(
&i.ID,
&i.TenantID,
&i.WorkspaceID,
&i.UserID,
&i.TokenHash,
&i.DeviceName,
&i.Os,
&i.CpuArch,
&i.ClientVersion,
&i.Channel,
&i.CreatedAt,
&i.LastSeenAt,
&i.LastRotatedAt,
&i.RevokedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const registerDesktopClient = `-- name: RegisterDesktopClient :one
INSERT INTO desktop_clients (
id,
tenant_id,
workspace_id,
user_id,
token_hash,
device_name,
os,
cpu_arch,
client_version,
channel
)
VALUES (
$1,
$2,
$3,
$4,
$5,
$6,
$7,
$8,
$9,
$10
)
RETURNING id, tenant_id, workspace_id, user_id, token_hash, device_name, os, cpu_arch, client_version, channel, created_at, last_seen_at, last_rotated_at, revoked_at
`
type RegisterDesktopClientParams struct {
ID pgtype.UUID `json:"id"`
TenantID int64 `json:"tenant_id"`
WorkspaceID int64 `json:"workspace_id"`
UserID int64 `json:"user_id"`
TokenHash []byte `json:"token_hash"`
DeviceName pgtype.Text `json:"device_name"`
Os pgtype.Text `json:"os"`
CpuArch pgtype.Text `json:"cpu_arch"`
ClientVersion pgtype.Text `json:"client_version"`
Channel pgtype.Text `json:"channel"`
}
func (q *Queries) RegisterDesktopClient(ctx context.Context, arg RegisterDesktopClientParams) (DesktopClient, error) {
row := q.db.QueryRow(ctx, registerDesktopClient,
arg.ID,
arg.TenantID,
arg.WorkspaceID,
arg.UserID,
arg.TokenHash,
arg.DeviceName,
arg.Os,
arg.CpuArch,
arg.ClientVersion,
arg.Channel,
)
var i DesktopClient
err := row.Scan(
&i.ID,
&i.TenantID,
&i.WorkspaceID,
&i.UserID,
&i.TokenHash,
&i.DeviceName,
&i.Os,
&i.CpuArch,
&i.ClientVersion,
&i.Channel,
&i.CreatedAt,
&i.LastSeenAt,
&i.LastRotatedAt,
&i.RevokedAt,
)
return i, err
}
const revokeDesktopClient = `-- name: RevokeDesktopClient :one
UPDATE desktop_clients
SET revoked_at = now()
WHERE id = $1
AND workspace_id = $2
AND revoked_at IS NULL
RETURNING id, tenant_id, workspace_id, user_id, token_hash, device_name, os, cpu_arch, client_version, channel, created_at, last_seen_at, last_rotated_at, revoked_at
`
type RevokeDesktopClientParams struct {
ID pgtype.UUID `json:"id"`
WorkspaceID int64 `json:"workspace_id"`
}
func (q *Queries) RevokeDesktopClient(ctx context.Context, arg RevokeDesktopClientParams) (DesktopClient, error) {
row := q.db.QueryRow(ctx, revokeDesktopClient, arg.ID, arg.WorkspaceID)
var i DesktopClient
err := row.Scan(
&i.ID,
&i.TenantID,
&i.WorkspaceID,
&i.UserID,
&i.TokenHash,
&i.DeviceName,
&i.Os,
&i.CpuArch,
&i.ClientVersion,
&i.Channel,
&i.CreatedAt,
&i.LastSeenAt,
&i.LastRotatedAt,
&i.RevokedAt,
)
return i, err
}
const rotateDesktopClientToken = `-- name: RotateDesktopClientToken :one
UPDATE desktop_clients
SET token_hash = $1,
last_rotated_at = now()
WHERE id = $2
AND workspace_id = $3
AND revoked_at IS NULL
RETURNING id, tenant_id, workspace_id, user_id, token_hash, device_name, os, cpu_arch, client_version, channel, created_at, last_seen_at, last_rotated_at, revoked_at
`
type RotateDesktopClientTokenParams struct {
TokenHash []byte `json:"token_hash"`
ID pgtype.UUID `json:"id"`
WorkspaceID int64 `json:"workspace_id"`
}
func (q *Queries) RotateDesktopClientToken(ctx context.Context, arg RotateDesktopClientTokenParams) (DesktopClient, error) {
row := q.db.QueryRow(ctx, rotateDesktopClientToken, arg.TokenHash, arg.ID, arg.WorkspaceID)
var i DesktopClient
err := row.Scan(
&i.ID,
&i.TenantID,
&i.WorkspaceID,
&i.UserID,
&i.TokenHash,
&i.DeviceName,
&i.Os,
&i.CpuArch,
&i.ClientVersion,
&i.Channel,
&i.CreatedAt,
&i.LastSeenAt,
&i.LastRotatedAt,
&i.RevokedAt,
)
return i, err
}
@@ -0,0 +1,850 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.30.0
// source: desktop_task.sql
package generated
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const cancelDesktopTaskByClient = `-- name: CancelDesktopTaskByClient :one
UPDATE desktop_tasks
SET status = 'aborted',
error = $1,
active_attempt_id = NULL,
lease_token_hash = NULL,
lease_expires_at = NULL,
parked_reason = NULL,
updated_at = now()
WHERE desktop_id = $2
AND target_client_id = $3
AND status IN ('queued', 'waiting_user')
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, parked_reason, result, error, created_at, updated_at
`
type CancelDesktopTaskByClientParams struct {
Error []byte `json:"error"`
DesktopID pgtype.UUID `json:"desktop_id"`
ClientID pgtype.UUID `json:"client_id"`
}
func (q *Queries) CancelDesktopTaskByClient(ctx context.Context, arg CancelDesktopTaskByClientParams) (DesktopTask, error) {
row := q.db.QueryRow(ctx, cancelDesktopTaskByClient, arg.Error, arg.DesktopID, arg.ClientID)
var i DesktopTask
err := row.Scan(
&i.ID,
&i.DesktopID,
&i.JobID,
&i.TenantID,
&i.WorkspaceID,
&i.TargetAccountID,
&i.TargetClientID,
&i.PlatformID,
&i.Kind,
&i.Payload,
&i.Status,
&i.DedupKey,
&i.ActiveAttemptID,
&i.LeaseTokenHash,
&i.LeaseExpiresAt,
&i.Attempts,
&i.ParkedReason,
&i.Result,
&i.Error,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const cancelDesktopTaskByLease = `-- name: CancelDesktopTaskByLease :one
UPDATE desktop_tasks
SET status = 'aborted',
error = $1,
active_attempt_id = NULL,
lease_token_hash = NULL,
lease_expires_at = NULL,
parked_reason = NULL,
updated_at = now()
WHERE desktop_id = $2
AND lease_token_hash = $3
AND status = 'in_progress'
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, parked_reason, result, error, created_at, updated_at
`
type CancelDesktopTaskByLeaseParams struct {
Error []byte `json:"error"`
DesktopID pgtype.UUID `json:"desktop_id"`
LeaseTokenHash []byte `json:"lease_token_hash"`
}
func (q *Queries) CancelDesktopTaskByLease(ctx context.Context, arg CancelDesktopTaskByLeaseParams) (DesktopTask, error) {
row := q.db.QueryRow(ctx, cancelDesktopTaskByLease, arg.Error, arg.DesktopID, arg.LeaseTokenHash)
var i DesktopTask
err := row.Scan(
&i.ID,
&i.DesktopID,
&i.JobID,
&i.TenantID,
&i.WorkspaceID,
&i.TargetAccountID,
&i.TargetClientID,
&i.PlatformID,
&i.Kind,
&i.Payload,
&i.Status,
&i.DedupKey,
&i.ActiveAttemptID,
&i.LeaseTokenHash,
&i.LeaseExpiresAt,
&i.Attempts,
&i.ParkedReason,
&i.Result,
&i.Error,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const completeDesktopTask = `-- name: CompleteDesktopTask :one
UPDATE desktop_tasks
SET status = $1,
result = $2,
error = $3,
active_attempt_id = NULL,
lease_token_hash = NULL,
lease_expires_at = NULL,
parked_reason = NULL,
updated_at = now()
WHERE desktop_id = $4
AND lease_token_hash = $5
AND status = 'in_progress'
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, parked_reason, result, error, created_at, updated_at
`
type CompleteDesktopTaskParams struct {
Status string `json:"status"`
Result []byte `json:"result"`
Error []byte `json:"error"`
DesktopID pgtype.UUID `json:"desktop_id"`
LeaseTokenHash []byte `json:"lease_token_hash"`
}
func (q *Queries) CompleteDesktopTask(ctx context.Context, arg CompleteDesktopTaskParams) (DesktopTask, error) {
row := q.db.QueryRow(ctx, completeDesktopTask,
arg.Status,
arg.Result,
arg.Error,
arg.DesktopID,
arg.LeaseTokenHash,
)
var i DesktopTask
err := row.Scan(
&i.ID,
&i.DesktopID,
&i.JobID,
&i.TenantID,
&i.WorkspaceID,
&i.TargetAccountID,
&i.TargetClientID,
&i.PlatformID,
&i.Kind,
&i.Payload,
&i.Status,
&i.DedupKey,
&i.ActiveAttemptID,
&i.LeaseTokenHash,
&i.LeaseExpiresAt,
&i.Attempts,
&i.ParkedReason,
&i.Result,
&i.Error,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const createDesktopPublishJob = `-- name: CreateDesktopPublishJob :one
INSERT INTO desktop_publish_jobs (
desktop_id,
tenant_id,
workspace_id,
created_by_user_id,
title,
content_ref,
scheduled_at
)
VALUES (
$1,
$2,
$3,
$4,
$5,
$6,
$7
)
RETURNING id, desktop_id, tenant_id, workspace_id, created_by_user_id, title, content_ref, scheduled_at, created_at, updated_at
`
type CreateDesktopPublishJobParams struct {
DesktopID pgtype.UUID `json:"desktop_id"`
TenantID int64 `json:"tenant_id"`
WorkspaceID int64 `json:"workspace_id"`
CreatedByUserID int64 `json:"created_by_user_id"`
Title string `json:"title"`
ContentRef []byte `json:"content_ref"`
ScheduledAt pgtype.Timestamptz `json:"scheduled_at"`
}
func (q *Queries) CreateDesktopPublishJob(ctx context.Context, arg CreateDesktopPublishJobParams) (DesktopPublishJob, error) {
row := q.db.QueryRow(ctx, createDesktopPublishJob,
arg.DesktopID,
arg.TenantID,
arg.WorkspaceID,
arg.CreatedByUserID,
arg.Title,
arg.ContentRef,
arg.ScheduledAt,
)
var i DesktopPublishJob
err := row.Scan(
&i.ID,
&i.DesktopID,
&i.TenantID,
&i.WorkspaceID,
&i.CreatedByUserID,
&i.Title,
&i.ContentRef,
&i.ScheduledAt,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const createDesktopTask = `-- name: CreateDesktopTask :one
INSERT INTO desktop_tasks (
desktop_id,
job_id,
tenant_id,
workspace_id,
target_account_id,
target_client_id,
platform_id,
kind,
payload,
status,
dedup_key,
parked_reason
)
VALUES (
$1,
$2,
$3,
$4,
$5,
$6,
$7,
$8,
$9,
$10,
$11,
$12
)
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, parked_reason, result, error, created_at, updated_at
`
type CreateDesktopTaskParams struct {
DesktopID pgtype.UUID `json:"desktop_id"`
JobID pgtype.UUID `json:"job_id"`
TenantID int64 `json:"tenant_id"`
WorkspaceID int64 `json:"workspace_id"`
TargetAccountID pgtype.UUID `json:"target_account_id"`
TargetClientID pgtype.UUID `json:"target_client_id"`
PlatformID string `json:"platform_id"`
Kind string `json:"kind"`
Payload []byte `json:"payload"`
Status string `json:"status"`
DedupKey pgtype.Text `json:"dedup_key"`
ParkedReason pgtype.Text `json:"parked_reason"`
}
func (q *Queries) CreateDesktopTask(ctx context.Context, arg CreateDesktopTaskParams) (DesktopTask, error) {
row := q.db.QueryRow(ctx, createDesktopTask,
arg.DesktopID,
arg.JobID,
arg.TenantID,
arg.WorkspaceID,
arg.TargetAccountID,
arg.TargetClientID,
arg.PlatformID,
arg.Kind,
arg.Payload,
arg.Status,
arg.DedupKey,
arg.ParkedReason,
)
var i DesktopTask
err := row.Scan(
&i.ID,
&i.DesktopID,
&i.JobID,
&i.TenantID,
&i.WorkspaceID,
&i.TargetAccountID,
&i.TargetClientID,
&i.PlatformID,
&i.Kind,
&i.Payload,
&i.Status,
&i.DedupKey,
&i.ActiveAttemptID,
&i.LeaseTokenHash,
&i.LeaseExpiresAt,
&i.Attempts,
&i.ParkedReason,
&i.Result,
&i.Error,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const createDesktopTaskAttempt = `-- name: CreateDesktopTaskAttempt :one
INSERT INTO desktop_task_attempts (
desktop_id,
task_id,
client_id,
lease_token_hash
)
VALUES (
$1,
$2,
$3,
$4
)
RETURNING id, desktop_id, task_id, client_id, lease_token_hash, started_at, ended_at, final_status, error, created_at
`
type CreateDesktopTaskAttemptParams struct {
DesktopID pgtype.UUID `json:"desktop_id"`
TaskID pgtype.UUID `json:"task_id"`
ClientID pgtype.UUID `json:"client_id"`
LeaseTokenHash []byte `json:"lease_token_hash"`
}
func (q *Queries) CreateDesktopTaskAttempt(ctx context.Context, arg CreateDesktopTaskAttemptParams) (DesktopTaskAttempt, error) {
row := q.db.QueryRow(ctx, createDesktopTaskAttempt,
arg.DesktopID,
arg.TaskID,
arg.ClientID,
arg.LeaseTokenHash,
)
var i DesktopTaskAttempt
err := row.Scan(
&i.ID,
&i.DesktopID,
&i.TaskID,
&i.ClientID,
&i.LeaseTokenHash,
&i.StartedAt,
&i.EndedAt,
&i.FinalStatus,
&i.Error,
&i.CreatedAt,
)
return i, err
}
const extendDesktopTaskLease = `-- name: ExtendDesktopTaskLease :one
UPDATE desktop_tasks
SET lease_expires_at = now() + interval '10 minutes',
updated_at = now()
WHERE desktop_id = $1
AND lease_token_hash = $2
AND status = 'in_progress'
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, parked_reason, result, error, created_at, updated_at
`
type ExtendDesktopTaskLeaseParams struct {
DesktopID pgtype.UUID `json:"desktop_id"`
LeaseTokenHash []byte `json:"lease_token_hash"`
}
func (q *Queries) ExtendDesktopTaskLease(ctx context.Context, arg ExtendDesktopTaskLeaseParams) (DesktopTask, error) {
row := q.db.QueryRow(ctx, extendDesktopTaskLease, arg.DesktopID, arg.LeaseTokenHash)
var i DesktopTask
err := row.Scan(
&i.ID,
&i.DesktopID,
&i.JobID,
&i.TenantID,
&i.WorkspaceID,
&i.TargetAccountID,
&i.TargetClientID,
&i.PlatformID,
&i.Kind,
&i.Payload,
&i.Status,
&i.DedupKey,
&i.ActiveAttemptID,
&i.LeaseTokenHash,
&i.LeaseExpiresAt,
&i.Attempts,
&i.ParkedReason,
&i.Result,
&i.Error,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const finishDesktopTaskAttempt = `-- name: FinishDesktopTaskAttempt :exec
UPDATE desktop_task_attempts
SET ended_at = now(),
final_status = $1,
error = $2
WHERE task_id = $3
AND desktop_id = $4
`
type FinishDesktopTaskAttemptParams struct {
FinalStatus pgtype.Text `json:"final_status"`
Error []byte `json:"error"`
TaskID pgtype.UUID `json:"task_id"`
AttemptID pgtype.UUID `json:"attempt_id"`
}
func (q *Queries) FinishDesktopTaskAttempt(ctx context.Context, arg FinishDesktopTaskAttemptParams) error {
_, err := q.db.Exec(ctx, finishDesktopTaskAttempt,
arg.FinalStatus,
arg.Error,
arg.TaskID,
arg.AttemptID,
)
return err
}
const getDesktopTaskByDesktopID = `-- name: GetDesktopTaskByDesktopID :one
SELECT id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, parked_reason, result, error, created_at, updated_at
FROM desktop_tasks
WHERE desktop_id = $1
AND workspace_id = $2
LIMIT 1
`
type GetDesktopTaskByDesktopIDParams struct {
DesktopID pgtype.UUID `json:"desktop_id"`
WorkspaceID int64 `json:"workspace_id"`
}
func (q *Queries) GetDesktopTaskByDesktopID(ctx context.Context, arg GetDesktopTaskByDesktopIDParams) (DesktopTask, error) {
row := q.db.QueryRow(ctx, getDesktopTaskByDesktopID, arg.DesktopID, arg.WorkspaceID)
var i DesktopTask
err := row.Scan(
&i.ID,
&i.DesktopID,
&i.JobID,
&i.TenantID,
&i.WorkspaceID,
&i.TargetAccountID,
&i.TargetClientID,
&i.PlatformID,
&i.Kind,
&i.Payload,
&i.Status,
&i.DedupKey,
&i.ActiveAttemptID,
&i.LeaseTokenHash,
&i.LeaseExpiresAt,
&i.Attempts,
&i.ParkedReason,
&i.Result,
&i.Error,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const leaseNextQueuedDesktopTask = `-- name: LeaseNextQueuedDesktopTask :one
WITH candidate AS (
SELECT dt.desktop_id
FROM desktop_tasks AS dt
WHERE dt.target_client_id = $3
AND dt.status = 'queued'
AND (
$4::text IS NULL
OR dt.kind = $4::text
)
ORDER BY dt.created_at ASC, dt.desktop_id ASC
LIMIT 1
FOR UPDATE SKIP LOCKED
)
UPDATE desktop_tasks AS t
SET active_attempt_id = $1,
lease_token_hash = $2,
lease_expires_at = now() + interval '10 minutes',
status = 'in_progress',
attempts = t.attempts + 1,
parked_reason = NULL,
updated_at = now()
FROM candidate
WHERE t.desktop_id = candidate.desktop_id
RETURNING t.id, t.desktop_id, t.job_id, t.tenant_id, t.workspace_id, t.target_account_id, t.target_client_id, t.platform_id, t.kind, t.payload, t.status, t.dedup_key, t.active_attempt_id, t.lease_token_hash, t.lease_expires_at, t.attempts, t.parked_reason, t.result, t.error, t.created_at, t.updated_at
`
type LeaseNextQueuedDesktopTaskParams struct {
AttemptID pgtype.UUID `json:"attempt_id"`
LeaseTokenHash []byte `json:"lease_token_hash"`
ClientID pgtype.UUID `json:"client_id"`
Kind pgtype.Text `json:"kind"`
}
func (q *Queries) LeaseNextQueuedDesktopTask(ctx context.Context, arg LeaseNextQueuedDesktopTaskParams) (DesktopTask, error) {
row := q.db.QueryRow(ctx, leaseNextQueuedDesktopTask,
arg.AttemptID,
arg.LeaseTokenHash,
arg.ClientID,
arg.Kind,
)
var i DesktopTask
err := row.Scan(
&i.ID,
&i.DesktopID,
&i.JobID,
&i.TenantID,
&i.WorkspaceID,
&i.TargetAccountID,
&i.TargetClientID,
&i.PlatformID,
&i.Kind,
&i.Payload,
&i.Status,
&i.DedupKey,
&i.ActiveAttemptID,
&i.LeaseTokenHash,
&i.LeaseExpiresAt,
&i.Attempts,
&i.ParkedReason,
&i.Result,
&i.Error,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const leaseParkedDesktopTask = `-- name: LeaseParkedDesktopTask :one
UPDATE desktop_tasks
SET active_attempt_id = $1,
lease_token_hash = $2,
lease_expires_at = now() + interval '10 minutes',
status = 'in_progress',
attempts = attempts + 1,
parked_reason = NULL,
updated_at = now()
WHERE desktop_id = $3
AND target_client_id = $4
AND status = 'waiting_user'
AND active_attempt_id IS NULL
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, parked_reason, result, error, created_at, updated_at
`
type LeaseParkedDesktopTaskParams struct {
AttemptID pgtype.UUID `json:"attempt_id"`
LeaseTokenHash []byte `json:"lease_token_hash"`
DesktopID pgtype.UUID `json:"desktop_id"`
ClientID pgtype.UUID `json:"client_id"`
}
func (q *Queries) LeaseParkedDesktopTask(ctx context.Context, arg LeaseParkedDesktopTaskParams) (DesktopTask, error) {
row := q.db.QueryRow(ctx, leaseParkedDesktopTask,
arg.AttemptID,
arg.LeaseTokenHash,
arg.DesktopID,
arg.ClientID,
)
var i DesktopTask
err := row.Scan(
&i.ID,
&i.DesktopID,
&i.JobID,
&i.TenantID,
&i.WorkspaceID,
&i.TargetAccountID,
&i.TargetClientID,
&i.PlatformID,
&i.Kind,
&i.Payload,
&i.Status,
&i.DedupKey,
&i.ActiveAttemptID,
&i.LeaseTokenHash,
&i.LeaseExpiresAt,
&i.Attempts,
&i.ParkedReason,
&i.Result,
&i.Error,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const leaseQueuedDesktopTaskByDesktopID = `-- name: LeaseQueuedDesktopTaskByDesktopID :one
UPDATE desktop_tasks
SET active_attempt_id = $1,
lease_token_hash = $2,
lease_expires_at = now() + interval '10 minutes',
status = 'in_progress',
attempts = attempts + 1,
parked_reason = NULL,
updated_at = now()
WHERE desktop_id = $3
AND target_client_id = $4
AND status = 'queued'
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, parked_reason, result, error, created_at, updated_at
`
type LeaseQueuedDesktopTaskByDesktopIDParams struct {
AttemptID pgtype.UUID `json:"attempt_id"`
LeaseTokenHash []byte `json:"lease_token_hash"`
DesktopID pgtype.UUID `json:"desktop_id"`
ClientID pgtype.UUID `json:"client_id"`
}
func (q *Queries) LeaseQueuedDesktopTaskByDesktopID(ctx context.Context, arg LeaseQueuedDesktopTaskByDesktopIDParams) (DesktopTask, error) {
row := q.db.QueryRow(ctx, leaseQueuedDesktopTaskByDesktopID,
arg.AttemptID,
arg.LeaseTokenHash,
arg.DesktopID,
arg.ClientID,
)
var i DesktopTask
err := row.Scan(
&i.ID,
&i.DesktopID,
&i.JobID,
&i.TenantID,
&i.WorkspaceID,
&i.TargetAccountID,
&i.TargetClientID,
&i.PlatformID,
&i.Kind,
&i.Payload,
&i.Status,
&i.DedupKey,
&i.ActiveAttemptID,
&i.LeaseTokenHash,
&i.LeaseExpiresAt,
&i.Attempts,
&i.ParkedReason,
&i.Result,
&i.Error,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const markDesktopTasksUnknownByClient = `-- name: MarkDesktopTasksUnknownByClient :execrows
UPDATE desktop_tasks
SET status = 'unknown',
error = $1,
active_attempt_id = NULL,
lease_token_hash = NULL,
lease_expires_at = NULL,
parked_reason = NULL,
updated_at = now()
WHERE target_client_id = $2
AND workspace_id = $3
AND status IN ('waiting_user', 'in_progress')
`
type MarkDesktopTasksUnknownByClientParams struct {
Error []byte `json:"error"`
ClientID pgtype.UUID `json:"client_id"`
WorkspaceID int64 `json:"workspace_id"`
}
func (q *Queries) MarkDesktopTasksUnknownByClient(ctx context.Context, arg MarkDesktopTasksUnknownByClientParams) (int64, error) {
result, err := q.db.Exec(ctx, markDesktopTasksUnknownByClient, arg.Error, arg.ClientID, arg.WorkspaceID)
if err != nil {
return 0, err
}
return result.RowsAffected(), nil
}
const parkDesktopTask = `-- name: ParkDesktopTask :one
UPDATE desktop_tasks
SET status = 'waiting_user',
active_attempt_id = NULL,
lease_token_hash = NULL,
lease_expires_at = NULL,
parked_reason = $1,
updated_at = now()
WHERE desktop_id = $2
AND lease_token_hash = $3
AND status = 'in_progress'
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, parked_reason, result, error, created_at, updated_at
`
type ParkDesktopTaskParams struct {
ParkedReason pgtype.Text `json:"parked_reason"`
DesktopID pgtype.UUID `json:"desktop_id"`
LeaseTokenHash []byte `json:"lease_token_hash"`
}
func (q *Queries) ParkDesktopTask(ctx context.Context, arg ParkDesktopTaskParams) (DesktopTask, error) {
row := q.db.QueryRow(ctx, parkDesktopTask, arg.ParkedReason, arg.DesktopID, arg.LeaseTokenHash)
var i DesktopTask
err := row.Scan(
&i.ID,
&i.DesktopID,
&i.JobID,
&i.TenantID,
&i.WorkspaceID,
&i.TargetAccountID,
&i.TargetClientID,
&i.PlatformID,
&i.Kind,
&i.Payload,
&i.Status,
&i.DedupKey,
&i.ActiveAttemptID,
&i.LeaseTokenHash,
&i.LeaseExpiresAt,
&i.Attempts,
&i.ParkedReason,
&i.Result,
&i.Error,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const reconcileDesktopTask = `-- name: ReconcileDesktopTask :one
UPDATE desktop_tasks
SET status = CASE
WHEN $1::text = 'retry' THEN 'queued'
ELSE $1::text
END,
result = CASE
WHEN $1::text = 'retry' THEN NULL
ELSE $2
END,
error = $3,
active_attempt_id = NULL,
lease_token_hash = NULL,
lease_expires_at = NULL,
parked_reason = NULL,
attempts = attempts + CASE WHEN $1::text = 'retry' THEN 1 ELSE 0 END,
updated_at = now()
WHERE desktop_id = $4
AND workspace_id = $5
AND status = 'unknown'
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, parked_reason, result, error, created_at, updated_at
`
type ReconcileDesktopTaskParams struct {
Status string `json:"status"`
Result []byte `json:"result"`
Error []byte `json:"error"`
DesktopID pgtype.UUID `json:"desktop_id"`
WorkspaceID int64 `json:"workspace_id"`
}
func (q *Queries) ReconcileDesktopTask(ctx context.Context, arg ReconcileDesktopTaskParams) (DesktopTask, error) {
row := q.db.QueryRow(ctx, reconcileDesktopTask,
arg.Status,
arg.Result,
arg.Error,
arg.DesktopID,
arg.WorkspaceID,
)
var i DesktopTask
err := row.Scan(
&i.ID,
&i.DesktopID,
&i.JobID,
&i.TenantID,
&i.WorkspaceID,
&i.TargetAccountID,
&i.TargetClientID,
&i.PlatformID,
&i.Kind,
&i.Payload,
&i.Status,
&i.DedupKey,
&i.ActiveAttemptID,
&i.LeaseTokenHash,
&i.LeaseExpiresAt,
&i.Attempts,
&i.ParkedReason,
&i.Result,
&i.Error,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const tenantCancelDesktopTask = `-- name: TenantCancelDesktopTask :one
UPDATE desktop_tasks
SET status = 'aborted',
error = $1,
active_attempt_id = NULL,
lease_token_hash = NULL,
lease_expires_at = NULL,
parked_reason = NULL,
updated_at = now()
WHERE desktop_id = $2
AND workspace_id = $3
AND status IN ('queued', 'waiting_user')
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, parked_reason, result, error, created_at, updated_at
`
type TenantCancelDesktopTaskParams struct {
Error []byte `json:"error"`
DesktopID pgtype.UUID `json:"desktop_id"`
WorkspaceID int64 `json:"workspace_id"`
}
func (q *Queries) TenantCancelDesktopTask(ctx context.Context, arg TenantCancelDesktopTaskParams) (DesktopTask, error) {
row := q.db.QueryRow(ctx, tenantCancelDesktopTask, arg.Error, arg.DesktopID, arg.WorkspaceID)
var i DesktopTask
err := row.Scan(
&i.ID,
&i.DesktopID,
&i.JobID,
&i.TenantID,
&i.WorkspaceID,
&i.TargetAccountID,
&i.TargetClientID,
&i.PlatformID,
&i.Kind,
&i.Payload,
&i.Status,
&i.DedupKey,
&i.ActiveAttemptID,
&i.LeaseTokenHash,
&i.LeaseExpiresAt,
&i.Attempts,
&i.ParkedReason,
&i.Result,
&i.Error,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
@@ -119,6 +119,81 @@ type Competitor struct {
DeletedAt pgtype.Timestamptz `json:"deleted_at"`
}
type DesktopClient struct {
ID pgtype.UUID `json:"id"`
TenantID int64 `json:"tenant_id"`
WorkspaceID int64 `json:"workspace_id"`
UserID int64 `json:"user_id"`
TokenHash []byte `json:"token_hash"`
DeviceName pgtype.Text `json:"device_name"`
Os pgtype.Text `json:"os"`
CpuArch pgtype.Text `json:"cpu_arch"`
ClientVersion pgtype.Text `json:"client_version"`
Channel pgtype.Text `json:"channel"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
LastSeenAt pgtype.Timestamptz `json:"last_seen_at"`
LastRotatedAt pgtype.Timestamptz `json:"last_rotated_at"`
RevokedAt pgtype.Timestamptz `json:"revoked_at"`
}
type DesktopPublishJob struct {
ID int64 `json:"id"`
DesktopID pgtype.UUID `json:"desktop_id"`
TenantID int64 `json:"tenant_id"`
WorkspaceID int64 `json:"workspace_id"`
CreatedByUserID int64 `json:"created_by_user_id"`
Title string `json:"title"`
ContentRef []byte `json:"content_ref"`
ScheduledAt pgtype.Timestamptz `json:"scheduled_at"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type DesktopTask struct {
ID int64 `json:"id"`
DesktopID pgtype.UUID `json:"desktop_id"`
JobID pgtype.UUID `json:"job_id"`
TenantID int64 `json:"tenant_id"`
WorkspaceID int64 `json:"workspace_id"`
TargetAccountID pgtype.UUID `json:"target_account_id"`
TargetClientID pgtype.UUID `json:"target_client_id"`
PlatformID string `json:"platform_id"`
Kind string `json:"kind"`
Payload []byte `json:"payload"`
Status string `json:"status"`
DedupKey pgtype.Text `json:"dedup_key"`
ActiveAttemptID pgtype.UUID `json:"active_attempt_id"`
LeaseTokenHash []byte `json:"lease_token_hash"`
LeaseExpiresAt pgtype.Timestamptz `json:"lease_expires_at"`
Attempts int32 `json:"attempts"`
ParkedReason pgtype.Text `json:"parked_reason"`
Result []byte `json:"result"`
Error []byte `json:"error"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type DesktopTaskAttempt struct {
ID int64 `json:"id"`
DesktopID pgtype.UUID `json:"desktop_id"`
TaskID pgtype.UUID `json:"task_id"`
ClientID pgtype.UUID `json:"client_id"`
LeaseTokenHash []byte `json:"lease_token_hash"`
StartedAt pgtype.Timestamptz `json:"started_at"`
EndedAt pgtype.Timestamptz `json:"ended_at"`
FinalStatus pgtype.Text `json:"final_status"`
Error []byte `json:"error"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
type DesktopTaskTrace struct {
TaskID pgtype.UUID `json:"task_id"`
AttemptID pgtype.UUID `json:"attempt_id"`
Size pgtype.Int8 `json:"size"`
UploadedAt pgtype.Timestamptz `json:"uploaded_at"`
ObjectKey pgtype.Text `json:"object_key"`
}
type GenerationTask struct {
ID int64 `json:"id"`
TenantID int64 `json:"tenant_id"`
@@ -376,19 +451,29 @@ type Plan struct {
}
type PlatformAccount struct {
ID int64 `json:"id"`
TenantID int64 `json:"tenant_id"`
UserID int64 `json:"user_id"`
PlatformID string `json:"platform_id"`
PlatformUid string `json:"platform_uid"`
Nickname string `json:"nickname"`
AvatarUrl pgtype.Text `json:"avatar_url"`
Status string `json:"status"`
MetadataJson []byte `json:"metadata_json"`
LastCheckAt pgtype.Timestamptz `json:"last_check_at"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
DeletedAt pgtype.Timestamptz `json:"deleted_at"`
ID int64 `json:"id"`
TenantID int64 `json:"tenant_id"`
UserID int64 `json:"user_id"`
PlatformID string `json:"platform_id"`
PlatformUid string `json:"platform_uid"`
Nickname string `json:"nickname"`
AvatarUrl pgtype.Text `json:"avatar_url"`
Status string `json:"status"`
MetadataJson []byte `json:"metadata_json"`
LastCheckAt pgtype.Timestamptz `json:"last_check_at"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
DeletedAt pgtype.Timestamptz `json:"deleted_at"`
WorkspaceID int64 `json:"workspace_id"`
DesktopID pgtype.UUID `json:"desktop_id"`
ClientID pgtype.UUID `json:"client_id"`
AccountFingerprint pgtype.Text `json:"account_fingerprint"`
DisplayName string `json:"display_name"`
Health string `json:"health"`
VerifiedAt pgtype.Timestamptz `json:"verified_at"`
Tags []byte `json:"tags"`
SyncVersion int64 `json:"sync_version"`
DeleteRequestedAt pgtype.Timestamptz `json:"delete_requested_at"`
}
type PlatformUserRole struct {
@@ -602,6 +687,7 @@ type TenantMonitoringQuota struct {
PlanTier string `json:"plan_tier"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
WorkspaceID int64 `json:"workspace_id"`
}
type TenantPlanSubscription struct {
@@ -641,3 +727,23 @@ type User struct {
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
DeletedAt pgtype.Timestamptz `json:"deleted_at"`
}
type Workspace struct {
ID int64 `json:"id"`
TenantID int64 `json:"tenant_id"`
Name string `json:"name"`
Slug string `json:"slug"`
IsDefault bool `json:"is_default"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type WorkspaceMembership struct {
ID int64 `json:"id"`
WorkspaceID int64 `json:"workspace_id"`
UserID int64 `json:"user_id"`
TenantID int64 `json:"tenant_id"`
Role string `json:"role"`
IsPrimary bool `json:"is_primary"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
@@ -10,6 +10,10 @@ import (
type Querier interface {
ApproveKolSubscription(ctx context.Context, arg ApproveKolSubscriptionParams) error
CancelDesktopTaskByClient(ctx context.Context, arg CancelDesktopTaskByClientParams) (DesktopTask, error)
CancelDesktopTaskByLease(ctx context.Context, arg CancelDesktopTaskByLeaseParams) (DesktopTask, error)
ClearDesktopAccountDeleteRequested(ctx context.Context, arg ClearDesktopAccountDeleteRequestedParams) (ClearDesktopAccountDeleteRequestedRow, error)
CompleteDesktopTask(ctx context.Context, arg CompleteDesktopTaskParams) (DesktopTask, error)
ConfirmReservation(ctx context.Context, arg ConfirmReservationParams) error
CountActiveImagesInFolder(ctx context.Context, arg CountActiveImagesInFolderParams) (int32, error)
CountArticles(ctx context.Context, arg CountArticlesParams) (int64, error)
@@ -27,6 +31,9 @@ type Querier interface {
CreateAuditLog(ctx context.Context, arg CreateAuditLogParams) error
CreateBrand(ctx context.Context, arg CreateBrandParams) (CreateBrandRow, error)
CreateCompetitor(ctx context.Context, arg CreateCompetitorParams) (CreateCompetitorRow, error)
CreateDesktopPublishJob(ctx context.Context, arg CreateDesktopPublishJobParams) (DesktopPublishJob, error)
CreateDesktopTask(ctx context.Context, arg CreateDesktopTaskParams) (DesktopTask, error)
CreateDesktopTaskAttempt(ctx context.Context, arg CreateDesktopTaskAttemptParams) (DesktopTaskAttempt, error)
CreateGenerationTask(ctx context.Context, arg CreateGenerationTaskParams) (int64, error)
CreateImageFolder(ctx context.Context, arg CreateImageFolderParams) (int64, error)
CreateKeyword(ctx context.Context, arg CreateKeywordParams) (CreateKeywordRow, error)
@@ -47,12 +54,18 @@ type Querier interface {
DeleteImageReferencesByArticle(ctx context.Context, arg DeleteImageReferencesByArticleParams) error
DeleteImageReferencesByArticleScope(ctx context.Context, arg DeleteImageReferencesByArticleScopeParams) error
EnsureImageStorageUsageRow(ctx context.Context, tenantID int64) error
ExtendDesktopTaskLease(ctx context.Context, arg ExtendDesktopTaskLeaseParams) (DesktopTask, error)
FinishDesktopTaskAttempt(ctx context.Context, arg FinishDesktopTaskAttemptParams) error
GetActiveKolSubscription(ctx context.Context, arg GetActiveKolSubscriptionParams) (KolSubscription, error)
GetActivePlanForTenant(ctx context.Context, tenantID int64) (GetActivePlanForTenantRow, error)
GetArticleByID(ctx context.Context, arg GetArticleByIDParams) (GetArticleByIDRow, error)
GetArticleVersions(ctx context.Context, articleID int64) ([]GetArticleVersionsRow, error)
GetBrandByID(ctx context.Context, arg GetBrandByIDParams) (GetBrandByIDRow, error)
GetCurrentBalance(ctx context.Context, arg GetCurrentBalanceParams) (int32, error)
GetDesktopAccountByDesktopID(ctx context.Context, arg GetDesktopAccountByDesktopIDParams) (GetDesktopAccountByDesktopIDRow, error)
GetDesktopAccountByIdentity(ctx context.Context, arg GetDesktopAccountByIdentityParams) (GetDesktopAccountByIdentityRow, error)
GetDesktopClientByTokenHash(ctx context.Context, tokenHash []byte) (DesktopClient, error)
GetDesktopTaskByDesktopID(ctx context.Context, arg GetDesktopTaskByDesktopIDParams) (DesktopTask, error)
GetImageAsset(ctx context.Context, arg GetImageAssetParams) (GetImageAssetRow, error)
GetImageFolder(ctx context.Context, arg GetImageFolderParams) (GetImageFolderRow, error)
GetImageStorageUsage(ctx context.Context, tenantID int64) (GetImageStorageUsageRow, error)
@@ -78,6 +91,7 @@ type Querier interface {
GetTenantMembershipByTenantAndUser(ctx context.Context, arg GetTenantMembershipByTenantAndUserParams) (GetTenantMembershipByTenantAndUserRow, error)
GetUserByEmail(ctx context.Context, email string) (GetUserByEmailRow, error)
GetUserByID(ctx context.Context, id int64) (GetUserByIDRow, error)
HeartbeatDesktopClient(ctx context.Context, arg HeartbeatDesktopClientParams) (DesktopClient, error)
InsertImageAsset(ctx context.Context, arg InsertImageAssetParams) (int64, error)
InsertQuotaLedger(ctx context.Context, arg InsertQuotaLedgerParams) (int64, error)
// Cross-tenant aggregation: KOL owns packages across subscriber tenants.
@@ -86,6 +100,9 @@ type Querier interface {
KolDashboardTrend(ctx context.Context, arg KolDashboardTrendParams) ([]KolDashboardTrendRow, error)
// Cross-tenant aggregation for KOL dashboard.
KolUsageCountByPackage(ctx context.Context, packageIds []int64) ([]KolUsageCountByPackageRow, error)
LeaseNextQueuedDesktopTask(ctx context.Context, arg LeaseNextQueuedDesktopTaskParams) (DesktopTask, error)
LeaseParkedDesktopTask(ctx context.Context, arg LeaseParkedDesktopTaskParams) (DesktopTask, error)
LeaseQueuedDesktopTaskByDesktopID(ctx context.Context, arg LeaseQueuedDesktopTaskByDesktopIDParams) (DesktopTask, error)
ListActiveImagesByFolder(ctx context.Context, arg ListActiveImagesByFolderParams) ([]ListActiveImagesByFolderRow, error)
ListActiveKolPromptsByPackage(ctx context.Context, arg ListActiveKolPromptsByPackageParams) ([]ListActiveKolPromptsByPackageRow, error)
// Cross-tenant read: used by platform admin for subscription fan-out.
@@ -95,6 +112,8 @@ type Querier interface {
ListArticles(ctx context.Context, arg ListArticlesParams) ([]ListArticlesRow, error)
ListBrands(ctx context.Context, tenantID int64) ([]ListBrandsRow, error)
ListCompetitors(ctx context.Context, arg ListCompetitorsParams) ([]ListCompetitorsRow, error)
ListDesktopAccountsByClient(ctx context.Context, arg ListDesktopAccountsByClientParams) ([]ListDesktopAccountsByClientRow, error)
ListDesktopClientsByWorkspace(ctx context.Context, workspaceID int64) ([]DesktopClient, error)
ListImageAssets(ctx context.Context, arg ListImageAssetsParams) ([]ListImageAssetsRow, error)
ListImageFolders(ctx context.Context, tenantID int64) ([]ListImageFoldersRow, error)
ListImageReferenceArticles(ctx context.Context, arg ListImageReferenceArticlesParams) ([]ListImageReferenceArticlesRow, error)
@@ -122,6 +141,8 @@ type Querier interface {
ListScheduleTasks(ctx context.Context, arg ListScheduleTasksParams) ([]ListScheduleTasksRow, error)
ListSubscriptionPromptsByTenant(ctx context.Context, tenantID int64) ([]ListSubscriptionPromptsByTenantRow, error)
ListTemplates(ctx context.Context, tenantID int64) ([]ListTemplatesRow, error)
MarkDesktopAccountDeleteRequested(ctx context.Context, arg MarkDesktopAccountDeleteRequestedParams) (MarkDesktopAccountDeleteRequestedRow, error)
MarkDesktopTasksUnknownByClient(ctx context.Context, arg MarkDesktopTasksUnknownByClientParams) (int64, error)
MarkImagesInFolderPendingDelete(ctx context.Context, arg MarkImagesInFolderPendingDeleteParams) error
MarkKolAssistCompleted(ctx context.Context, arg MarkKolAssistCompletedParams) error
MarkKolAssistFailed(ctx context.Context, arg MarkKolAssistFailedParams) error
@@ -131,11 +152,17 @@ type Querier interface {
MarkKolUsageFailed(ctx context.Context, arg MarkKolUsageFailedParams) error
MarkKolUsageFailedByTask(ctx context.Context, arg MarkKolUsageFailedByTaskParams) error
NextKolPromptRevisionNo(ctx context.Context, arg NextKolPromptRevisionNoParams) (int32, error)
ParkDesktopTask(ctx context.Context, arg ParkDesktopTaskParams) (DesktopTask, error)
PatchDesktopAccount(ctx context.Context, arg PatchDesktopAccountParams) (PatchDesktopAccountRow, error)
ReconcileDesktopTask(ctx context.Context, arg ReconcileDesktopTaskParams) (DesktopTask, error)
RefundReservation(ctx context.Context, arg RefundReservationParams) error
RegisterDesktopClient(ctx context.Context, arg RegisterDesktopClientParams) (DesktopClient, error)
ReleaseImageStorageQuota(ctx context.Context, arg ReleaseImageStorageQuotaParams) error
RevokeDesktopClient(ctx context.Context, arg RevokeDesktopClientParams) (DesktopClient, error)
RevokeKolSubscription(ctx context.Context, arg RevokeKolSubscriptionParams) error
RevokeSubscriptionPromptsByPrompt(ctx context.Context, arg RevokeSubscriptionPromptsByPromptParams) error
RevokeSubscriptionPromptsBySubscription(ctx context.Context, arg RevokeSubscriptionPromptsBySubscriptionParams) error
RotateDesktopClientToken(ctx context.Context, arg RotateDesktopClientTokenParams) (DesktopClient, error)
SoftDeleteArticle(ctx context.Context, arg SoftDeleteArticleParams) error
SoftDeleteBrand(ctx context.Context, arg SoftDeleteBrandParams) error
SoftDeleteCompetitor(ctx context.Context, arg SoftDeleteCompetitorParams) error
@@ -149,6 +176,8 @@ type Querier interface {
SoftDeleteQuestion(ctx context.Context, arg SoftDeleteQuestionParams) error
SoftDeleteQuestionsByBrand(ctx context.Context, arg SoftDeleteQuestionsByBrandParams) error
SoftDeleteScheduleTask(ctx context.Context, arg SoftDeleteScheduleTaskParams) error
TenantCancelDesktopTask(ctx context.Context, arg TenantCancelDesktopTaskParams) (DesktopTask, error)
TombstoneDesktopAccount(ctx context.Context, arg TombstoneDesktopAccountParams) (TombstoneDesktopAccountRow, error)
UpdateArticleCurrentVersion(ctx context.Context, arg UpdateArticleCurrentVersionParams) error
UpdateArticleGenerateStatus(ctx context.Context, arg UpdateArticleGenerateStatusParams) error
UpdateBrand(ctx context.Context, arg UpdateBrandParams) error
@@ -175,6 +204,7 @@ type Querier interface {
UpdateScheduleTask(ctx context.Context, arg UpdateScheduleTaskParams) error
UpdateScheduleTaskStatus(ctx context.Context, arg UpdateScheduleTaskStatusParams) error
UpdateTaskRecordStatus(ctx context.Context, arg UpdateTaskRecordStatusParams) error
UpsertDesktopAccount(ctx context.Context, arg UpsertDesktopAccountParams) (UpsertDesktopAccountRow, error)
UpsertImageReference(ctx context.Context, arg UpsertImageReferenceParams) error
}
@@ -9,12 +9,30 @@ FROM users
WHERE id = sqlc.arg(id) AND deleted_at IS NULL;
-- name: GetTenantMembership :one
SELECT id, tenant_id, user_id, tenant_role, created_at
FROM tenant_memberships
WHERE user_id = sqlc.arg(user_id) AND deleted_at IS NULL
SELECT tm.id,
tm.tenant_id,
tm.user_id,
tm.tenant_role,
tm.created_at,
wm.workspace_id AS primary_workspace_id
FROM tenant_memberships tm
JOIN workspace_memberships wm
ON wm.tenant_id = tm.tenant_id
AND wm.user_id = tm.user_id
AND wm.is_primary = TRUE
WHERE tm.user_id = sqlc.arg(user_id) AND tm.deleted_at IS NULL
LIMIT 1;
-- name: GetTenantMembershipByTenantAndUser :one
SELECT id, tenant_id, user_id, tenant_role, created_at
FROM tenant_memberships
WHERE tenant_id = sqlc.arg(tenant_id) AND user_id = sqlc.arg(user_id) AND deleted_at IS NULL;
SELECT tm.id,
tm.tenant_id,
tm.user_id,
tm.tenant_role,
tm.created_at,
wm.workspace_id AS primary_workspace_id
FROM tenant_memberships tm
JOIN workspace_memberships wm
ON wm.tenant_id = tm.tenant_id
AND wm.user_id = tm.user_id
AND wm.is_primary = TRUE
WHERE tm.tenant_id = sqlc.arg(tenant_id) AND tm.user_id = sqlc.arg(user_id) AND tm.deleted_at IS NULL;
@@ -0,0 +1,268 @@
-- name: ListDesktopAccountsByClient :many
SELECT
desktop_id,
tenant_id,
workspace_id,
user_id,
client_id,
platform_id,
platform_uid,
account_fingerprint,
display_name,
health,
verified_at,
tags,
sync_version,
deleted_at,
delete_requested_at,
created_at,
updated_at
FROM platform_accounts
WHERE workspace_id = sqlc.arg(workspace_id)
AND client_id = sqlc.arg(client_id)
ORDER BY platform_id, display_name, created_at DESC;
-- name: GetDesktopAccountByDesktopID :one
SELECT
desktop_id,
tenant_id,
workspace_id,
user_id,
client_id,
platform_id,
platform_uid,
account_fingerprint,
display_name,
health,
verified_at,
tags,
sync_version,
deleted_at,
delete_requested_at,
created_at,
updated_at
FROM platform_accounts
WHERE desktop_id = sqlc.arg(desktop_id)
AND workspace_id = sqlc.arg(workspace_id)
LIMIT 1;
-- name: GetDesktopAccountByIdentity :one
SELECT
desktop_id,
tenant_id,
workspace_id,
user_id,
client_id,
platform_id,
platform_uid,
account_fingerprint,
display_name,
health,
verified_at,
tags,
sync_version,
deleted_at,
delete_requested_at,
created_at,
updated_at
FROM platform_accounts
WHERE workspace_id = sqlc.arg(workspace_id)
AND platform_id = sqlc.arg(platform_id)
AND platform_uid = sqlc.arg(platform_uid)
AND deleted_at IS NULL
LIMIT 1;
-- name: UpsertDesktopAccount :one
INSERT INTO platform_accounts (
desktop_id,
tenant_id,
workspace_id,
user_id,
client_id,
platform_id,
platform_uid,
nickname,
status,
metadata_json,
last_check_at,
account_fingerprint,
display_name,
health,
verified_at,
tags,
sync_version
)
VALUES (
sqlc.arg(desktop_id),
sqlc.arg(tenant_id),
sqlc.arg(workspace_id),
sqlc.arg(user_id),
sqlc.arg(client_id),
sqlc.arg(platform_id),
sqlc.arg(platform_uid),
sqlc.arg(display_name)::text,
sqlc.arg(legacy_status),
sqlc.narg(metadata_json),
sqlc.narg(verified_at),
sqlc.narg(account_fingerprint),
sqlc.arg(display_name)::text,
sqlc.arg(health),
sqlc.narg(verified_at),
sqlc.narg(tags),
1
)
ON CONFLICT (workspace_id, platform_id, platform_uid) WHERE deleted_at IS NULL
DO UPDATE SET
client_id = EXCLUDED.client_id,
user_id = EXCLUDED.user_id,
nickname = EXCLUDED.nickname,
status = EXCLUDED.status,
metadata_json = COALESCE(EXCLUDED.metadata_json, platform_accounts.metadata_json),
last_check_at = COALESCE(EXCLUDED.last_check_at, platform_accounts.last_check_at),
account_fingerprint = EXCLUDED.account_fingerprint,
display_name = EXCLUDED.display_name,
health = EXCLUDED.health,
verified_at = COALESCE(EXCLUDED.verified_at, platform_accounts.verified_at),
tags = EXCLUDED.tags,
sync_version = platform_accounts.sync_version + 1,
delete_requested_at = NULL,
updated_at = now()
WHERE platform_accounts.workspace_id = EXCLUDED.workspace_id
AND (
sqlc.narg(if_sync_version)::bigint IS NULL
OR platform_accounts.sync_version = sqlc.narg(if_sync_version)::bigint
)
RETURNING
desktop_id,
tenant_id,
workspace_id,
user_id,
client_id,
platform_id,
platform_uid,
account_fingerprint,
display_name,
health,
verified_at,
tags,
sync_version,
deleted_at,
delete_requested_at,
created_at,
updated_at;
-- name: PatchDesktopAccount :one
UPDATE platform_accounts
SET display_name = COALESCE(sqlc.narg(display_name)::text, display_name),
nickname = COALESCE(sqlc.narg(display_name)::text, nickname),
health = COALESCE(sqlc.narg(health), health),
status = COALESCE(sqlc.narg(legacy_status), status),
verified_at = COALESCE(sqlc.narg(verified_at), verified_at),
last_check_at = COALESCE(sqlc.narg(verified_at), last_check_at),
tags = COALESCE(sqlc.narg(tags), tags),
sync_version = sync_version + 1,
updated_at = now()
WHERE desktop_id = sqlc.arg(desktop_id)
AND workspace_id = sqlc.arg(workspace_id)
AND sync_version = sqlc.arg(if_sync_version)
AND deleted_at IS NULL
RETURNING
desktop_id,
tenant_id,
workspace_id,
user_id,
client_id,
platform_id,
platform_uid,
account_fingerprint,
display_name,
health,
verified_at,
tags,
sync_version,
deleted_at,
delete_requested_at,
created_at,
updated_at;
-- name: TombstoneDesktopAccount :one
UPDATE platform_accounts
SET deleted_at = now(),
sync_version = sync_version + 1,
updated_at = now()
WHERE desktop_id = sqlc.arg(desktop_id)
AND workspace_id = sqlc.arg(workspace_id)
AND sync_version = sqlc.arg(if_sync_version)
AND deleted_at IS NULL
RETURNING
desktop_id,
tenant_id,
workspace_id,
user_id,
client_id,
platform_id,
platform_uid,
account_fingerprint,
display_name,
health,
verified_at,
tags,
sync_version,
deleted_at,
delete_requested_at,
created_at,
updated_at;
-- name: MarkDesktopAccountDeleteRequested :one
UPDATE platform_accounts
SET delete_requested_at = now(),
sync_version = sync_version + 1,
updated_at = now()
WHERE desktop_id = sqlc.arg(desktop_id)
AND workspace_id = sqlc.arg(workspace_id)
AND deleted_at IS NULL
RETURNING
desktop_id,
tenant_id,
workspace_id,
user_id,
client_id,
platform_id,
platform_uid,
account_fingerprint,
display_name,
health,
verified_at,
tags,
sync_version,
deleted_at,
delete_requested_at,
created_at,
updated_at;
-- name: ClearDesktopAccountDeleteRequested :one
UPDATE platform_accounts
SET delete_requested_at = NULL,
sync_version = sync_version + 1,
updated_at = now()
WHERE desktop_id = sqlc.arg(desktop_id)
AND workspace_id = sqlc.arg(workspace_id)
AND deleted_at IS NULL
RETURNING
desktop_id,
tenant_id,
workspace_id,
user_id,
client_id,
platform_id,
platform_uid,
account_fingerprint,
display_name,
health,
verified_at,
tags,
sync_version,
deleted_at,
delete_requested_at,
created_at,
updated_at;
@@ -0,0 +1,70 @@
-- name: RegisterDesktopClient :one
INSERT INTO desktop_clients (
id,
tenant_id,
workspace_id,
user_id,
token_hash,
device_name,
os,
cpu_arch,
client_version,
channel
)
VALUES (
sqlc.arg(id),
sqlc.arg(tenant_id),
sqlc.arg(workspace_id),
sqlc.arg(user_id),
sqlc.arg(token_hash),
sqlc.narg(device_name),
sqlc.narg(os),
sqlc.narg(cpu_arch),
sqlc.narg(client_version),
sqlc.narg(channel)
)
RETURNING *;
-- name: GetDesktopClientByTokenHash :one
SELECT *
FROM desktop_clients
WHERE token_hash = sqlc.arg(token_hash)
AND revoked_at IS NULL
LIMIT 1;
-- name: RotateDesktopClientToken :one
UPDATE desktop_clients
SET token_hash = sqlc.arg(token_hash),
last_rotated_at = now()
WHERE id = sqlc.arg(id)
AND workspace_id = sqlc.arg(workspace_id)
AND revoked_at IS NULL
RETURNING *;
-- name: HeartbeatDesktopClient :one
UPDATE desktop_clients
SET device_name = COALESCE(sqlc.narg(device_name), device_name),
os = COALESCE(sqlc.narg(os), os),
cpu_arch = COALESCE(sqlc.narg(cpu_arch), cpu_arch),
client_version = COALESCE(sqlc.narg(client_version), client_version),
channel = COALESCE(sqlc.narg(channel), channel),
last_seen_at = now()
WHERE id = sqlc.arg(id)
AND workspace_id = sqlc.arg(workspace_id)
AND revoked_at IS NULL
RETURNING *;
-- name: RevokeDesktopClient :one
UPDATE desktop_clients
SET revoked_at = now()
WHERE id = sqlc.arg(id)
AND workspace_id = sqlc.arg(workspace_id)
AND revoked_at IS NULL
RETURNING *;
-- name: ListDesktopClientsByWorkspace :many
SELECT *
FROM desktop_clients
WHERE workspace_id = sqlc.arg(workspace_id)
AND revoked_at IS NULL
ORDER BY last_seen_at DESC NULLS LAST, created_at DESC;
@@ -0,0 +1,250 @@
-- name: CreateDesktopPublishJob :one
INSERT INTO desktop_publish_jobs (
desktop_id,
tenant_id,
workspace_id,
created_by_user_id,
title,
content_ref,
scheduled_at
)
VALUES (
sqlc.arg(desktop_id),
sqlc.arg(tenant_id),
sqlc.arg(workspace_id),
sqlc.arg(created_by_user_id),
sqlc.arg(title),
sqlc.arg(content_ref),
sqlc.narg(scheduled_at)
)
RETURNING *;
-- name: CreateDesktopTask :one
INSERT INTO desktop_tasks (
desktop_id,
job_id,
tenant_id,
workspace_id,
target_account_id,
target_client_id,
platform_id,
kind,
payload,
status,
dedup_key,
parked_reason
)
VALUES (
sqlc.arg(desktop_id),
sqlc.arg(job_id),
sqlc.arg(tenant_id),
sqlc.arg(workspace_id),
sqlc.arg(target_account_id),
sqlc.arg(target_client_id),
sqlc.arg(platform_id),
sqlc.arg(kind),
sqlc.arg(payload),
sqlc.arg(status),
sqlc.narg(dedup_key),
sqlc.narg(parked_reason)
)
RETURNING *;
-- name: GetDesktopTaskByDesktopID :one
SELECT *
FROM desktop_tasks
WHERE desktop_id = sqlc.arg(desktop_id)
AND workspace_id = sqlc.arg(workspace_id)
LIMIT 1;
-- name: LeaseNextQueuedDesktopTask :one
WITH candidate AS (
SELECT dt.desktop_id
FROM desktop_tasks AS dt
WHERE dt.target_client_id = sqlc.arg(client_id)
AND dt.status = 'queued'
AND (
sqlc.narg(kind)::text IS NULL
OR dt.kind = sqlc.narg(kind)::text
)
ORDER BY dt.created_at ASC, dt.desktop_id ASC
LIMIT 1
FOR UPDATE SKIP LOCKED
)
UPDATE desktop_tasks AS t
SET active_attempt_id = sqlc.arg(attempt_id),
lease_token_hash = sqlc.arg(lease_token_hash),
lease_expires_at = now() + interval '10 minutes',
status = 'in_progress',
attempts = t.attempts + 1,
parked_reason = NULL,
updated_at = now()
FROM candidate
WHERE t.desktop_id = candidate.desktop_id
RETURNING t.*;
-- name: LeaseQueuedDesktopTaskByDesktopID :one
UPDATE desktop_tasks
SET active_attempt_id = sqlc.arg(attempt_id),
lease_token_hash = sqlc.arg(lease_token_hash),
lease_expires_at = now() + interval '10 minutes',
status = 'in_progress',
attempts = attempts + 1,
parked_reason = NULL,
updated_at = now()
WHERE desktop_id = sqlc.arg(desktop_id)
AND target_client_id = sqlc.arg(client_id)
AND status = 'queued'
RETURNING *;
-- name: LeaseParkedDesktopTask :one
UPDATE desktop_tasks
SET active_attempt_id = sqlc.arg(attempt_id),
lease_token_hash = sqlc.arg(lease_token_hash),
lease_expires_at = now() + interval '10 minutes',
status = 'in_progress',
attempts = attempts + 1,
parked_reason = NULL,
updated_at = now()
WHERE desktop_id = sqlc.arg(desktop_id)
AND target_client_id = sqlc.arg(client_id)
AND status = 'waiting_user'
AND active_attempt_id IS NULL
RETURNING *;
-- name: ExtendDesktopTaskLease :one
UPDATE desktop_tasks
SET lease_expires_at = now() + interval '10 minutes',
updated_at = now()
WHERE desktop_id = sqlc.arg(desktop_id)
AND lease_token_hash = sqlc.arg(lease_token_hash)
AND status = 'in_progress'
RETURNING *;
-- name: ParkDesktopTask :one
UPDATE desktop_tasks
SET status = 'waiting_user',
active_attempt_id = NULL,
lease_token_hash = NULL,
lease_expires_at = NULL,
parked_reason = sqlc.arg(parked_reason),
updated_at = now()
WHERE desktop_id = sqlc.arg(desktop_id)
AND lease_token_hash = sqlc.arg(lease_token_hash)
AND status = 'in_progress'
RETURNING *;
-- name: CompleteDesktopTask :one
UPDATE desktop_tasks
SET status = sqlc.arg(status),
result = sqlc.narg(result),
error = sqlc.narg(error),
active_attempt_id = NULL,
lease_token_hash = NULL,
lease_expires_at = NULL,
parked_reason = NULL,
updated_at = now()
WHERE desktop_id = sqlc.arg(desktop_id)
AND lease_token_hash = sqlc.arg(lease_token_hash)
AND status = 'in_progress'
RETURNING *;
-- name: CancelDesktopTaskByLease :one
UPDATE desktop_tasks
SET status = 'aborted',
error = sqlc.narg(error),
active_attempt_id = NULL,
lease_token_hash = NULL,
lease_expires_at = NULL,
parked_reason = NULL,
updated_at = now()
WHERE desktop_id = sqlc.arg(desktop_id)
AND lease_token_hash = sqlc.arg(lease_token_hash)
AND status = 'in_progress'
RETURNING *;
-- name: CancelDesktopTaskByClient :one
UPDATE desktop_tasks
SET status = 'aborted',
error = sqlc.narg(error),
active_attempt_id = NULL,
lease_token_hash = NULL,
lease_expires_at = NULL,
parked_reason = NULL,
updated_at = now()
WHERE desktop_id = sqlc.arg(desktop_id)
AND target_client_id = sqlc.arg(client_id)
AND status IN ('queued', 'waiting_user')
RETURNING *;
-- name: TenantCancelDesktopTask :one
UPDATE desktop_tasks
SET status = 'aborted',
error = sqlc.narg(error),
active_attempt_id = NULL,
lease_token_hash = NULL,
lease_expires_at = NULL,
parked_reason = NULL,
updated_at = now()
WHERE desktop_id = sqlc.arg(desktop_id)
AND workspace_id = sqlc.arg(workspace_id)
AND status IN ('queued', 'waiting_user')
RETURNING *;
-- name: ReconcileDesktopTask :one
UPDATE desktop_tasks
SET status = CASE
WHEN sqlc.arg(status)::text = 'retry' THEN 'queued'
ELSE sqlc.arg(status)::text
END,
result = CASE
WHEN sqlc.arg(status)::text = 'retry' THEN NULL
ELSE sqlc.narg(result)
END,
error = sqlc.narg(error),
active_attempt_id = NULL,
lease_token_hash = NULL,
lease_expires_at = NULL,
parked_reason = NULL,
attempts = attempts + CASE WHEN sqlc.arg(status)::text = 'retry' THEN 1 ELSE 0 END,
updated_at = now()
WHERE desktop_id = sqlc.arg(desktop_id)
AND workspace_id = sqlc.arg(workspace_id)
AND status = 'unknown'
RETURNING *;
-- name: MarkDesktopTasksUnknownByClient :execrows
UPDATE desktop_tasks
SET status = 'unknown',
error = sqlc.narg(error),
active_attempt_id = NULL,
lease_token_hash = NULL,
lease_expires_at = NULL,
parked_reason = NULL,
updated_at = now()
WHERE target_client_id = sqlc.arg(client_id)
AND workspace_id = sqlc.arg(workspace_id)
AND status IN ('waiting_user', 'in_progress');
-- name: CreateDesktopTaskAttempt :one
INSERT INTO desktop_task_attempts (
desktop_id,
task_id,
client_id,
lease_token_hash
)
VALUES (
sqlc.arg(desktop_id),
sqlc.arg(task_id),
sqlc.arg(client_id),
sqlc.arg(lease_token_hash)
)
RETURNING *;
-- name: FinishDesktopTaskAttempt :exec
UPDATE desktop_task_attempts
SET ended_at = now(),
final_status = sqlc.narg(final_status),
error = sqlc.narg(error)
WHERE task_id = sqlc.arg(task_id)
AND desktop_id = sqlc.arg(attempt_id);