Merge branch 'feature/search-emoji-demo' into dev

Gemini: full emoji picker (desktop + mobile bottom sheet), global search
with SQLite FTS5 and Cmd+K palette (access-checked), demo mode resets the
database on every start.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
sandrodachandClaude Opus 5.5 committed 2026-10-28 23:27:22 +01:00
commit a044620cec
22 files changed
+1518 -203

No files matched your search

+11 -40
View File
@@ -70,6 +70,11 @@ func (s *Store) resetOutdatedSchema() error {
if version >= schemaVersion {
return nil
}
slog.Warn("Veraltetes Datenbankschema: alle Daten werden gelöscht und neu angelegt", "version", version, "neu", schemaVersion)
return s.dropAllTables()
}
func (s *Store) dropAllTables() error {
conn, err := s.db.Conn(context.Background())
if err != nil {
return err
@@ -88,9 +93,7 @@ func (s *Store) resetOutdatedSchema() error {
}
}
_ = rows.Close()
if len(tables) > 0 {
slog.Warn("Veraltetes Datenbankschema: alle Daten werden gelöscht und neu angelegt", "version", version, "neu", schemaVersion)
}
if _, err := conn.ExecContext(ctx, `PRAGMA foreign_keys = OFF`); err != nil {
return err
}
@@ -514,6 +517,7 @@ func (s *Store) migrate() error {
_ = s.reindexAllDocBlockTags()
}
s.migrateAnchorTags()
s.migrateSearchFTS()
_, err := s.db.Exec(fmt.Sprintf(`PRAGMA user_version = %d`, schemaVersion))
return err
@@ -4124,44 +4128,11 @@ func (s *Store) GetDashboardStats(userID string) (*domain.DashboardStats, error)
}
func (s *Store) SearchAll(userID, query string) ([]domain.Thought, []domain.Document, error) {
q := "%" + strings.ToLower(strings.TrimSpace(query)) + "%"
tRows, err := s.db.Query(
`SELECT id, user_id, content, tags, priority, source, status, is_completed, converted_type, converted_ref_id, due_date, task_list_id, kanban_status, notes, alarm_sent, created_at, triaged_at, subtasks, sort_order
FROM thoughts WHERE user_id = ? AND LOWER(content) LIKE ? ORDER BY created_at DESC LIMIT 30`,
userID, q,
)
thoughts := make([]domain.Thought, 0)
if err == nil {
for tRows.Next() {
if t, err := scanThought(tRows); err == nil {
thoughts = append(thoughts, *t)
}
}
_ = tRows.Close()
res, err := s.SearchGlobal(userID, query)
if err != nil {
return nil, nil, err
}
dRows, err := s.db.Query(
`SELECT d.id, d.user_id, d.space_id, d.title, d.icon, d.content, d.blocks_json, d.tags, d.folder_path,
CASE WHEN p.doc_id IS NOT NULL THEN 1 ELSE 0 END AS is_pinned,
d.is_archived, d.created_at, d.updated_at,
d.shared_folder_id, d.sub_folder_path
FROM documents d
LEFT JOIN doc_pins p ON p.doc_id = d.id AND p.user_id = ?
WHERE d.user_id = ? AND (LOWER(d.title) LIKE ? OR LOWER(d.content) LIKE ?) ORDER BY is_pinned DESC, d.updated_at DESC LIMIT 20`,
userID, userID, q, q,
)
docs := make([]domain.Document, 0)
if err == nil {
for dRows.Next() {
if d, err := scanDocument(dRows); err == nil {
docs = append(docs, *d)
}
}
_ = dRows.Close()
}
return thoughts, docs, nil
return res.Thoughts, res.Documents, nil
}
func (s *Store) ExportUserData(userID string) (*domain.FullExport, error) {