feat(demo): reset the demo instance every 20 minutes with a countdown
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m34s

DEMO_RESET_MINUTES (default 20, 0 = off) resets the database to the
sample data. Demo accounts get fixed IDs so sessions survive; requests
hold a read lock so the reset never runs under a half-finished request
(streams excluded). DEMO_RESET goes to every connection, /auth/status
announces the next reset. The app shows "✨ Demo · Reset in MM:SS" in
place of the version, then clears cached answers, remounts the views,
reloads in the background and shows a short notice; if no event
arrives (long polling) it asks the server after the countdown.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
sandrodachandClaude Opus 5.5 committed 2026-10-29 14:22:06 +01:00
1 parent afd3b0347c
commit 6b9eb62caf
12 files changed
+348 -9

No files matched your search

+14 -3
View File
@@ -67,6 +67,10 @@ func (s *Store) CreateUser(email, passwordHash, displayName, role string) (*doma
}
func (s *Store) CreateUserWithUsername(email, username, passwordHash, displayName, role string) (*domain.User, error) {
return s.createUserWithID(domain.NewID("usr"), email, username, passwordHash, displayName, role)
}
func (s *Store) createUserWithID(id, email, username, passwordHash, displayName, role string) (*domain.User, error) {
if role != "admin" && role != "member" {
role = "member"
}
@@ -76,7 +80,7 @@ func (s *Store) CreateUserWithUsername(email, username, passwordHash, displayNam
cleanUsername = strings.Split(cleanEmail, "@")[0]
}
u := &domain.User{
ID: domain.NewID("usr"),
ID: id,
Email: cleanEmail,
Username: cleanUsername,
PasswordHash: passwordHash,
@@ -125,6 +129,13 @@ func (s *Store) GetUserByLogin(login string) (*domain.User, error) {
}
// EnsureDemoAccounts seeds admin/admin and user/user accounts for demo evaluation
// Demo accounts keep the same IDs across resets, so the sessions of people trying the demo stay valid
// when the database is reset underneath them.
const (
DemoAdminID = "usr_demo_admin"
DemoUserID = "usr_demo_user"
)
func (s *Store) EnsureDemoAccounts() error {
s.initMu.Lock()
defer s.initMu.Unlock()
@@ -142,7 +153,7 @@ func (s *Store) EnsureDemoAccounts() error {
adminCreated := false
adminUser, err := s.GetUserByLogin("admin")
if err != nil || adminUser == nil {
adminUser, err = s.CreateUserWithUsername("admin@mindsift.local", "admin", adminHash, "Admin", "admin")
adminUser, err = s.createUserWithID(DemoAdminID, "admin@mindsift.local", "admin", adminHash, "Admin", "admin")
if err != nil {
return fmt.Errorf("failed to create demo admin: %w", err)
}
@@ -155,7 +166,7 @@ func (s *Store) EnsureDemoAccounts() error {
// 2. Regular user (user / user)
normalUser, err := s.GetUserByLogin("user")
if err != nil || normalUser == nil {
normalUser, err = s.CreateUserWithUsername("user@mindsift.local", "user", userHash, "User", "member")
normalUser, err = s.createUserWithID(DemoUserID, "user@mindsift.local", "user", userHash, "User", "member")
if err != nil {
return fmt.Errorf("failed to create demo user: %w", err)
}