Documentation
¶
Overview ¶
Package social owns S26's stars / watches / events surface. The package is read-mostly from the rest of the runtime: notifications fan-out (S29) reads `watches` for routing, the activity feed (post-MVP) reads `domain_events` for public timelines, and the repo profile reads cached counts. Mutations come through the orchestrator entrypoints below.
Index ¶
- Variables
- func AutoWatchOnCollab(ctx context.Context, deps Deps, userID, repoID int64) error
- func AutoWatchOnInvolvement(ctx context.Context, deps Deps, userID, repoID int64) error
- func Emit(ctx context.Context, deps Deps, p EmitParams) error
- func HasStar(ctx context.Context, deps Deps, userID, repoID int64) (bool, error)
- func SetWatch(ctx context.Context, deps Deps, actorUserID, repoID int64, level WatchLevel) error
- func Star(ctx context.Context, deps Deps, actorUserID, repoID int64, repoIsPublic bool) error
- func UnsetWatch(ctx context.Context, deps Deps, actorUserID, repoID int64) error
- func Unstar(ctx context.Context, deps Deps, actorUserID, repoID int64, repoIsPublic bool) error
- type Deps
- type EmitParams
- type WatchLevel
Constants ¶
This section is empty.
Variables ¶
var ( ErrNotLoggedIn = errors.New("social: login required") ErrInvalidWatchLevel = errors.New("social: watch level must be all, participating, or ignore") ErrStarRateLimit = errors.New("social: star/unstar rate limit exceeded") )
Errors surfaced to handlers.
Functions ¶
func AutoWatchOnCollab ¶
AutoWatchOnCollab inserts a `level='all'` row when no preference exists. Triggered by S15's collaborator-add path. Non-destructive: if the user has already chosen a level (including `ignore`), their choice is preserved.
Matches GitHub: collaborators get full notifications by default; they can opt down to `participating` or `ignore` later.
func AutoWatchOnInvolvement ¶
AutoWatchOnInvolvement inserts a `level='participating'` row when no preference exists. Triggered by issues.AddComment, mention resolution, assignment, review-requested. Non-destructive.
Matches GitHub: any first-touch involvement (commenting, getting mentioned, getting assigned) auto-subscribes the user to that thread's notifications, but only at the participating level so a drive-by mention doesn't flood them with future events.
func Emit ¶
func Emit(ctx context.Context, deps Deps, p EmitParams) error
Emit writes one row to domain_events. Non-fatal at the caller's discretion; orchestrators typically log on error rather than failing the whole transaction (the in-band action is more important than the event log).
func HasStar ¶
HasStar reports whether the user has starred the repo. Used by the star button on the repo page to render the toggled state.
func SetWatch ¶
SetWatch upserts an explicit watch level. The handler authorizes via policy.Can(ActionWatchSet, repo) before calling.
func Star ¶
Star idempotently records a star. Re-starring an already-starred repo is a no-op (the underlying INSERT … ON CONFLICT DO NOTHING + AFTER INSERT trigger combination keeps star_count consistent).
The handler MUST authorize via policy.Can(ActionStarCreate, repo) before calling — this orchestrator trusts that the actor has read access to the repo and is logged in.
Emits a `star` event into domain_events with `public = repoIsPublic`.
func UnsetWatch ¶
UnsetWatch removes the explicit row, returning the user to the implicit `participating` default.
Types ¶
type Deps ¶
type Deps struct {
Pool *pgxpool.Pool
Limiter *throttle.Limiter
Logger *slog.Logger
Audit *audit.Recorder
}
Deps wires the package against the rest of the runtime. Pool is required. Limiter governs the per-user star/unstar rate cap (spec pitfall: trending-manipulation abuse vector). Logger is optional (falls back to discarding when nil). Audit is optional; when set, state-changing operations record an audit row.
type EmitParams ¶
type EmitParams struct {
ActorUserID int64
Kind string
RepoID int64 // 0 for user-scoped
SourceKind string
SourceID int64
Public bool
Payload []byte // already-marshaled JSON; pass `[]byte("{}")` for empty
}
EmitEvent is the canonical seam for inserting a row into `domain_events`. Other packages (issues, pulls, repos lifecycle) will call this rather than reaching into the sqlc query directly, so the event-shape contract has one place to evolve as S29 and S33 wire up their consumers.
Pass repoID = 0 for user-scoped events (where there's no repo involved). The handler / orchestrator owns the public-flag decision: public-repo events should set true; private-repo events must set false.
type WatchLevel ¶
type WatchLevel string
WatchLevel mirrors the DB enum so handlers can pass typed values without importing socialdb.
const ( WatchAll WatchLevel = "all" WatchParticipating WatchLevel = "participating" WatchIgnore WatchLevel = "ignore" )
func CurrentLevel ¶
CurrentLevel returns the actor's current watch level for the repo, resolving the implicit `participating` default when no row exists.