Documentation
¶
Index ¶
- type ApiToken
- type ConsumeInviteByHashParams
- type CreateProjectForUserParams
- type CreateSessionParams
- type CreateSessionRow
- type CreateTeamInviteForUserParams
- type CreateTeamMembershipIfMissingParams
- type CreateTeamMembershipParams
- type CreateTeamParams
- type CreateUserParams
- type DBTX
- type FailedEvent
- type GetActiveIngestTokenByHashRow
- type GetActiveInviteByHashRow
- type GetProjectForUserParams
- type GetPublicTokenForProjectForUserParams
- type GetSessionWithUserRow
- type GetTeamForUserParams
- type IncrementFailedEventAttemptParams
- type InsertFailedEventParams
- type InsertOAuthAccessTokenParams
- type InsertOAuthClientParams
- type InsertOAuthCodeParams
- type InsertPublicAPITokenParams
- type IsMemberOfTeamParams
- type ListActiveAccessTokensForUserRow
- type ListMembersForTeamForUserParams
- type ListMembersForTeamForUserRow
- type ListProjectsForTeamForUserParams
- type ListProjectsForTeamsForUserParams
- type OauthAccessToken
- type OauthClient
- type OauthCode
- type Project
- type Queries
- func (q *Queries) ConsumeInviteByHash(ctx context.Context, arg ConsumeInviteByHashParams) (TeamInvite, error)
- func (q *Queries) CountActiveFailedEvents(ctx context.Context) (int64, error)
- func (q *Queries) CreateProjectForUser(ctx context.Context, arg CreateProjectForUserParams) (Project, error)
- func (q *Queries) CreateSession(ctx context.Context, arg CreateSessionParams) (CreateSessionRow, error)
- func (q *Queries) CreateTeam(ctx context.Context, arg CreateTeamParams) (Team, error)
- func (q *Queries) CreateTeamInviteForUser(ctx context.Context, arg CreateTeamInviteForUserParams) (TeamInvite, error)
- func (q *Queries) CreateTeamMembership(ctx context.Context, arg CreateTeamMembershipParams) error
- func (q *Queries) CreateTeamMembershipIfMissing(ctx context.Context, arg CreateTeamMembershipIfMissingParams) error
- func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, error)
- func (q *Queries) DeleteExpiredOAuthAccessTokens(ctx context.Context) (int64, error)
- func (q *Queries) DeleteExpiredOAuthCodes(ctx context.Context) (int64, error)
- func (q *Queries) DeleteExpiredSessions(ctx context.Context) (int64, error)
- func (q *Queries) DeleteFailedEvent(ctx context.Context, id string) error
- func (q *Queries) DeleteSession(ctx context.Context, id string) error
- func (q *Queries) GetActiveIngestTokenByHash(ctx context.Context, tokenHash string) (GetActiveIngestTokenByHashRow, error)
- func (q *Queries) GetActiveInviteByHash(ctx context.Context, tokenHash string) (GetActiveInviteByHashRow, error)
- func (q *Queries) GetActiveOAuthAccessTokenByHash(ctx context.Context, tokenHash string) (OauthAccessToken, error)
- func (q *Queries) GetActiveOAuthCodeByHash(ctx context.Context, codeHash string) (OauthCode, error)
- func (q *Queries) GetOAuthClientByID(ctx context.Context, id string) (OauthClient, error)
- func (q *Queries) GetProjectForUser(ctx context.Context, arg GetProjectForUserParams) (Project, error)
- func (q *Queries) GetPublicTokenForProjectForUser(ctx context.Context, arg GetPublicTokenForProjectForUserParams) (ApiToken, error)
- func (q *Queries) GetSessionWithUser(ctx context.Context, id string) (GetSessionWithUserRow, error)
- func (q *Queries) GetTeamByID(ctx context.Context, id string) (Team, error)
- func (q *Queries) GetTeamForUser(ctx context.Context, arg GetTeamForUserParams) (Team, error)
- func (q *Queries) GetUserByEmail(ctx context.Context, lower string) (User, error)
- func (q *Queries) GetUserByID(ctx context.Context, id string) (User, error)
- func (q *Queries) IncrementFailedEventAttempt(ctx context.Context, arg IncrementFailedEventAttemptParams) error
- func (q *Queries) InsertFailedEvent(ctx context.Context, arg InsertFailedEventParams) error
- func (q *Queries) InsertOAuthAccessToken(ctx context.Context, arg InsertOAuthAccessTokenParams) error
- func (q *Queries) InsertOAuthClient(ctx context.Context, arg InsertOAuthClientParams) (OauthClient, error)
- func (q *Queries) InsertOAuthCode(ctx context.Context, arg InsertOAuthCodeParams) error
- func (q *Queries) InsertPublicAPIToken(ctx context.Context, arg InsertPublicAPITokenParams) error
- func (q *Queries) IsMemberOfTeam(ctx context.Context, arg IsMemberOfTeamParams) (bool, error)
- func (q *Queries) ListActiveAccessTokensForUser(ctx context.Context, userID string) ([]ListActiveAccessTokensForUserRow, error)
- func (q *Queries) ListFailedEventsForDrain(ctx context.Context, limit int32) ([]FailedEvent, error)
- func (q *Queries) ListMembersForTeamForUser(ctx context.Context, arg ListMembersForTeamForUserParams) ([]ListMembersForTeamForUserRow, error)
- func (q *Queries) ListProjectsForTeamForUser(ctx context.Context, arg ListProjectsForTeamForUserParams) ([]Project, error)
- func (q *Queries) ListProjectsForTeamsForUser(ctx context.Context, arg ListProjectsForTeamsForUserParams) ([]Project, error)
- func (q *Queries) ListTeamsForUser(ctx context.Context, userID string) ([]Team, error)
- func (q *Queries) MarkOAuthCodeUsed(ctx context.Context, id string) (int64, error)
- func (q *Queries) QuarantineFailedEvent(ctx context.Context, id string) error
- func (q *Queries) RevokeOAuthAccessToken(ctx context.Context, tokenHash string) (int64, error)
- func (q *Queries) SoftDeleteProjectForUser(ctx context.Context, arg SoftDeleteProjectForUserParams) (int64, error)
- func (q *Queries) TouchSession(ctx context.Context, arg TouchSessionParams) error
- func (q *Queries) UpdateOAuthAccessTokenLastUsed(ctx context.Context, id string) error
- func (q *Queries) UpdateUserPassword(ctx context.Context, arg UpdateUserPasswordParams) error
- func (q *Queries) WithTx(tx pgx.Tx) *Queries
- type Session
- type SoftDeleteProjectForUserParams
- type Team
- type TeamInvite
- type TeamMembership
- type TouchSessionParams
- type UpdateUserPasswordParams
- type User
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ApiToken ¶
type ApiToken struct {
ID string
ProjectID string
Name string
TokenHash string
CreatedAt pgtype.Timestamptz
RevokedAt pgtype.Timestamptz
TokenPlaintext string
}
type CreateSessionParams ¶
type CreateSessionParams struct {
ID string
UserID string
ExpiresAt pgtype.Timestamptz
CsrfToken string
}
type CreateSessionRow ¶
type CreateSessionRow struct {
ID string
UserID string
ExpiresAt pgtype.Timestamptz
CsrfToken string
CreatedAt pgtype.Timestamptz
}
type CreateTeamParams ¶
type CreateUserParams ¶
type FailedEvent ¶
type FailedEvent struct {
ID string
BatchPayload []byte
LastError string
AttemptCount int32
CreatedAt pgtype.Timestamptz
LastAttemptAt pgtype.Timestamptz
QuarantinedAt pgtype.Timestamptz
}
type GetActiveInviteByHashRow ¶
type GetActiveInviteByHashRow struct {
ID string
TeamID string
CreatedBy string
TokenHash string
ExpiresAt pgtype.Timestamptz
ConsumedAt pgtype.Timestamptz
ConsumedBy *string
CreatedAt pgtype.Timestamptz
TeamName string
}
type GetProjectForUserParams ¶
type GetSessionWithUserRow ¶
type GetSessionWithUserRow struct {
SessionID string
UserID string
ExpiresAt pgtype.Timestamptz
CsrfToken string
CreatedAt pgtype.Timestamptz
UserEmail string
MustChangePassword bool
}
type GetTeamForUserParams ¶
type InsertFailedEventParams ¶
type InsertOAuthClientParams ¶
type InsertOAuthCodeParams ¶
type IsMemberOfTeamParams ¶
type ListActiveAccessTokensForUserRow ¶
type ListActiveAccessTokensForUserRow struct {
ID string
TokenHash string
ClientID string
UserID string
ProjectID string
Scope string
ExpiresAt pgtype.Timestamptz
RevokedAt pgtype.Timestamptz
CreatedAt pgtype.Timestamptz
LastUsedAt pgtype.Timestamptz
ClientName string
}
type ListMembersForTeamForUserRow ¶
type ListMembersForTeamForUserRow struct {
ID string
Email string
CreatedAt pgtype.Timestamptz
JoinedAt pgtype.Timestamptz
}
type OauthAccessToken ¶
type OauthAccessToken struct {
ID string
TokenHash string
ClientID string
UserID string
ProjectID string
Scope string
ExpiresAt pgtype.Timestamptz
RevokedAt pgtype.Timestamptz
CreatedAt pgtype.Timestamptz
LastUsedAt pgtype.Timestamptz
}
type OauthClient ¶
type OauthClient struct {
ID string
Name string
RedirectUris []string
CreatedAt pgtype.Timestamptz
}
type OauthCode ¶
type OauthCode struct {
ID string
CodeHash string
ClientID string
UserID string
ProjectID string
RedirectUri string
Scope string
CodeChallenge string
CodeChallengeMethod string
ExpiresAt pgtype.Timestamptz
UsedAt pgtype.Timestamptz
CreatedAt pgtype.Timestamptz
}
type Project ¶
type Project struct {
ID string
TeamID string
Name string
CreatedAt pgtype.Timestamptz
DeletedAt pgtype.Timestamptz
}
type Queries ¶
type Queries struct {
// contains filtered or unexported fields
}
func (*Queries) ConsumeInviteByHash ¶
func (q *Queries) ConsumeInviteByHash(ctx context.Context, arg ConsumeInviteByHashParams) (TeamInvite, error)
Atomic burn. RowsAffected via RETURNING — if 0 rows, the invite was consumed, expired, or never existed; caller maps all three to 404.
func (*Queries) CountActiveFailedEvents ¶
Refreshes the in-process DLQ depth gauge after each drain pass.
func (*Queries) CreateProjectForUser ¶
func (q *Queries) CreateProjectForUser(ctx context.Context, arg CreateProjectForUserParams) (Project, error)
The WHERE EXISTS guard makes the INSERT a no-op when the caller is not a member of the target team. RowsAffected == 0 → auth.ErrNotVisible.
func (*Queries) CreateSession ¶
func (q *Queries) CreateSession(ctx context.Context, arg CreateSessionParams) (CreateSessionRow, error)
func (*Queries) CreateTeam ¶
func (*Queries) CreateTeamInviteForUser ¶
func (q *Queries) CreateTeamInviteForUser(ctx context.Context, arg CreateTeamInviteForUserParams) (TeamInvite, error)
Invite tokens follow the same shape as api_tokens: plaintext shared via the URL only, sha256 hex persisted. Consume is a single atomic UPDATE so two concurrent claimants can never both succeed (Issue 14 race test). Membership-gated: caller must be in the team they're inviting into.
func (*Queries) CreateTeamMembership ¶
func (q *Queries) CreateTeamMembership(ctx context.Context, arg CreateTeamMembershipParams) error
func (*Queries) CreateTeamMembershipIfMissing ¶
func (q *Queries) CreateTeamMembershipIfMissing(ctx context.Context, arg CreateTeamMembershipIfMissingParams) error
Used by invite-consume and signup-with-invite where "user already in this team" must be silently tolerated (Issue 10). Avoids the 25P02 abort that a raw PK-violation would cause inside a transaction.
func (*Queries) CreateUser ¶
func (*Queries) DeleteExpiredOAuthAccessTokens ¶
Called by cmd/maintenance. Sweeps tokens past their expires_at. Revoked- but-not-yet-expired rows are deliberately left alone: the 1h TTL means they vanish on the next sweep anyway, and keeping them preserves the option to surface a revoked-tokens audit view without a schema change.
func (*Queries) DeleteExpiredOAuthCodes ¶
Called by cmd/maintenance. Codes have a 10-min TTL and are one-shot, so any row past expires_at is unreachable (an active /oauth/token call would have already failed the GetActiveOAuthCodeByHash predicate). Used-but-not-yet- expired codes are kept until the same predicate sweeps them — keeps this query a single, unambiguous filter.
func (*Queries) DeleteExpiredSessions ¶
Called by cmd/maintenance. The sliding-expiry/hard-cap math runs at touch time, so a row whose expires_at has passed is permanently inert and safe to delete.
func (*Queries) DeleteFailedEvent ¶
Removes a row after a successful drain replay.
func (*Queries) DeleteSession ¶
func (*Queries) GetActiveIngestTokenByHash ¶
func (q *Queries) GetActiveIngestTokenByHash(ctx context.Context, tokenHash string) (GetActiveIngestTokenByHashRow, error)
Resolves a mere_pub_* token hash to its project. Excludes soft-deleted projects so a deleted project can't keep accepting writes. Used by the ingest path's requirePublicToken middleware; the caller has already verified the PublicTokenPrefix so a non-prefix bearer never reaches here.
func (*Queries) GetActiveInviteByHash ¶
func (q *Queries) GetActiveInviteByHash(ctx context.Context, tokenHash string) (GetActiveInviteByHashRow, error)
Used by the GET /invites/:t confirmation page; expired or consumed → no row.
func (*Queries) GetActiveOAuthAccessTokenByHash ¶
func (q *Queries) GetActiveOAuthAccessTokenByHash(ctx context.Context, tokenHash string) (OauthAccessToken, error)
Active = not revoked AND not expired. The unique partial index on (token_hash) WHERE revoked_at IS NULL keeps this on a single index probe.
func (*Queries) GetActiveOAuthCodeByHash ¶
Read-side of the lookup-then-update. Returns the live row (not used, not expired) so the caller can validate client_id / redirect_uri / PKCE before committing the consume. pgx.ErrNoRows means unknown / expired / already used — all collapse to invalid_grant at the handler.
func (*Queries) GetOAuthClientByID ¶
func (*Queries) GetProjectForUser ¶
func (q *Queries) GetProjectForUser(ctx context.Context, arg GetProjectForUserParams) (Project, error)
All project queries are membership-gated via a JOIN on team_memberships. A row that doesn't belong to a team the viewer is in returns zero rows, which the viewer translates to auth.ErrNotVisible (Issue 6). Soft-deleted rows (deleted_at IS NOT NULL) are excluded from every read.
func (*Queries) GetPublicTokenForProjectForUser ¶
func (q *Queries) GetPublicTokenForProjectForUser(ctx context.Context, arg GetPublicTokenForProjectForUserParams) (ApiToken, error)
Public ingest token storage. Only one flavour left: the `mere_pub_…` snippet token that lives in client HTML. token_plaintext is intentionally persisted because the project page re-displays it on every visit; the partial unique index api_tokens_one_active_per_project_idx (migration 0007) enforces at most one active token per project so rotation = insert new + revoke old in one tx.
/v1/* + /mcp bearer auth has moved to oauth_access_tokens (migration 0006); secret_api tokens were retired with the api_tokens.kind column. Membership-gated read: only succeeds when the viewer is a member of the project's team and the project is not soft-deleted. Plaintext is returned because this token is public by design.
func (*Queries) GetSessionWithUser ¶
func (*Queries) GetTeamByID ¶
func (*Queries) GetTeamForUser ¶
Membership-gated read used by viewer.Teams().ByID(). Zero rows → ErrNotVisible.
func (*Queries) GetUserByEmail ¶
func (*Queries) GetUserByID ¶
func (*Queries) IncrementFailedEventAttempt ¶
func (q *Queries) IncrementFailedEventAttempt(ctx context.Context, arg IncrementFailedEventAttemptParams) error
Recorded after a drain CH-insert attempt fails. The fresh last_error displaces the previous one — only the most recent failure matters for triage.
func (*Queries) InsertFailedEvent ¶
func (q *Queries) InsertFailedEvent(ctx context.Context, arg InsertFailedEventParams) error
Dead-letter queue for events the flusher couldn't deliver to ClickHouse. One row per failed flush, storing the entire validated batch as JSONB so the drain goroutine can retry without losing event boundaries.
Drain progress: oldest-first via failed_events_drain_idx (partial WHERE quarantined_at IS NULL). After 20 attempts OR 24h age the row quarantines and is left alone; a future cmd/maintenance sweep reaps quarantined rows. Called by the flusher after a CH insert fails. id is a UUID v7 from idgen.New(); batch_payload carries the validated Event slice as JSON; the last_error column records the CH error string for forensics.
func (*Queries) InsertOAuthAccessToken ¶
func (q *Queries) InsertOAuthAccessToken(ctx context.Context, arg InsertOAuthAccessTokenParams) error
Access tokens: opaque random bytes, only sha256 stored. RequireBearer looks the token up by hash and applies the expiry + revocation filters in SQL so the index does the work.
func (*Queries) InsertOAuthClient ¶
func (q *Queries) InsertOAuthClient(ctx context.Context, arg InsertOAuthClientParams) (OauthClient, error)
OAuth client registry: minimal RFC 7591 surface. Public clients only (no client_secret), so the row carries only the identity + the redirect-URI allowlist. Redirect URIs are matched exactly at /oauth/authorize; the application layer applies the additional scheme/host rules (HTTPS or localhost) at registration time.
func (*Queries) InsertOAuthCode ¶
func (q *Queries) InsertOAuthCode(ctx context.Context, arg InsertOAuthCodeParams) error
Authorization codes: short-lived (10 min), one-shot. Consumption is a two-step lookup-then-update so the application layer can validate the bound (client_id, redirect_uri, PKCE) tuple BEFORE the row is burnt — a failed PKCE check leaves the code intact for a legitimate retry rather than forcing the user back through /oauth/authorize. One-shot is still enforced by MarkOAuthCodeUsed's `WHERE used_at IS NULL`: a concurrent /oauth/token call racing on the same row produces RowsAffected == 0 on the loser, which the handler maps to invalid_grant.
expires_at filtering happens in SQL on the lookup so the partial index continues to do the work; the application never sees expired rows.
This file pairs with internal/oauth/codes.go.
func (*Queries) InsertPublicAPIToken ¶
func (q *Queries) InsertPublicAPIToken(ctx context.Context, arg InsertPublicAPITokenParams) error
Bootstraps the project's public_ingest token. Called from inside the project-create transaction (auth.Service.createProjectWithPublicToken), so no membership EXISTS guard is needed — the project row was just inserted in the same tx by a query that already enforced membership.
func (*Queries) IsMemberOfTeam ¶
Cheap predicate for the invite-confirm page ("you are already a member").
func (*Queries) ListActiveAccessTokensForUser ¶
func (q *Queries) ListActiveAccessTokensForUser(ctx context.Context, userID string) ([]ListActiveAccessTokensForUserRow, error)
Future "connected apps" page. Returns the joinable surface (client name + project id + scope + lifecycle timestamps) for the viewer's active grants.
func (*Queries) ListFailedEventsForDrain ¶
Oldest-first slice for the drain goroutine. The LIMIT is bounded by INGEST_DLQ_DRAIN_BATCH_LIMIT so a deep DLQ doesn't starve other work.
func (*Queries) ListMembersForTeamForUser ¶
func (q *Queries) ListMembersForTeamForUser(ctx context.Context, arg ListMembersForTeamForUserParams) ([]ListMembersForTeamForUserRow, error)
Returns members of $1 if the caller ($2) is themselves a member; otherwise zero rows (which surfaces as ErrNotVisible at the viewer).
func (*Queries) ListProjectsForTeamForUser ¶
func (*Queries) ListProjectsForTeamsForUser ¶
func (q *Queries) ListProjectsForTeamsForUser(ctx context.Context, arg ListProjectsForTeamsForUserParams) ([]Project, error)
Used by the rebuilt home page (Issue 15): bounded 2-query pattern.
func (*Queries) ListTeamsForUser ¶
func (*Queries) MarkOAuthCodeUsed ¶
Write-side of the lookup-then-update. The `used_at IS NULL` predicate is the one-shot guard: a parallel /oauth/token call that also validated the same code races on this UPDATE; exactly one row is touched and the loser sees RowsAffected == 0.
func (*Queries) QuarantineFailedEvent ¶
Marks a row as accepted-data-loss after the retry budget is exhausted (>=20 attempts OR >24h age). The drain index excludes quarantined rows.
func (*Queries) RevokeOAuthAccessToken ¶
func (*Queries) SoftDeleteProjectForUser ¶
func (q *Queries) SoftDeleteProjectForUser(ctx context.Context, arg SoftDeleteProjectForUserParams) (int64, error)
Returns RowsAffected; 0 means either not-a-member or already-deleted, both of which collapse to ErrNotVisible at the viewer.
func (*Queries) TouchSession ¶
func (q *Queries) TouchSession(ctx context.Context, arg TouchSessionParams) error
func (*Queries) UpdateOAuthAccessTokenLastUsed ¶
Stamped fire-and-forget by RequireBearer after every successful bearer lookup. The 60s predicate is the entire throttle: bounds WAL + lock contention once /v1/query and /mcp are hot paths without an extra round trip. Granularity is intentional — the connected-apps UI shows "minutes ago" precision.
func (*Queries) UpdateUserPassword ¶
func (q *Queries) UpdateUserPassword(ctx context.Context, arg UpdateUserPasswordParams) error
type Session ¶
type Session struct {
ID string
UserID string
ExpiresAt pgtype.Timestamptz
CreatedAt pgtype.Timestamptz
CsrfToken string
}
type TeamInvite ¶
type TeamInvite struct {
ID string
TeamID string
CreatedBy string
TokenHash string
ExpiresAt pgtype.Timestamptz
ConsumedAt pgtype.Timestamptz
ConsumedBy *string
CreatedAt pgtype.Timestamptz
}
type TeamMembership ¶
type TeamMembership struct {
TeamID string
UserID string
JoinedAt pgtype.Timestamptz
}
type TouchSessionParams ¶
type TouchSessionParams struct {
ID string
ExpiresAt pgtype.Timestamptz
}
type User ¶
type User struct {
ID string
Email string
PasswordHash string
MustChangePassword bool
CreatedAt pgtype.Timestamptz
UpdatedAt pgtype.Timestamptz
}