feat(backend): add domain store, learning services, and seed data

Persist LMS entities and implement hearts/watch rules plus curriculum bootstrap.
This commit is contained in:
ahp
2026-10-07 19:40:26 +03:30
parent f76c7a110b
commit 3ee609337c
15 changed files with 4076 additions and 0 deletions
+61
View File
@@ -0,0 +1,61 @@
package service
import (
"context"
"pargar/backend/internal/models"
"pargar/backend/internal/store"
)
// Pusher delivers realtime messages to a user's connected websockets.
type Pusher interface {
Push(userID int64, msg any)
}
// Notifier persists in-app notifications and pushes them live.
type Notifier struct {
store *store.Store
pusher Pusher
}
func NewNotifier(st *store.Store, pusher Pusher) *Notifier {
return &Notifier{store: st, pusher: pusher}
}
func (n *Notifier) Notify(ctx context.Context, userID int64, category, typ, title, body, route string, data any) error {
enabled, err := n.store.PrefEnabled(ctx, userID, category)
if err != nil || !enabled {
return nil
}
notif := &models.Notification{
UserID: userID,
Category: category,
Type: typ,
Title: title,
Body: body,
Route: route,
}
if data != nil {
notif.Data = mustJSON(data)
}
if err := n.store.CreateNotification(ctx, notif); err != nil {
return err
}
if n.pusher != nil {
n.pusher.Push(userID, map[string]any{
"type": "notification",
"unread": true,
"item": notif,
})
}
return nil
}
func (n *Notifier) NotifyMany(ctx context.Context, userIDs []int64, category, typ, title, body, route string, data any) error {
for _, uid := range userIDs {
if err := n.Notify(ctx, uid, category, typ, title, body, route, data); err != nil {
return err
}
}
return nil
}