+
{#each renderContent(msg.content) as seg (msg.id + ':' + seg.text)}
{#if seg.mention}
insertMention(seg.text.slice(1))}
@@ -274,8 +285,6 @@
position: relative;
}
.msg-row.own .bubble {
- background: #6366f1;
- color: #fff;
border-bottom-left-radius: 14px;
border-bottom-right-radius: 4px;
}
@@ -288,7 +297,7 @@
text-transform: capitalize;
}
.msg-row.own .msg-time {
- color: rgba(255, 255, 255, 0.7);
+ color: rgba(17, 24, 39, 0.45);
}
.mention {
background: #ede9fe;
diff --git a/frontend/src/lib/server/migrate.ts b/frontend/src/lib/server/migrate.ts
index 4ae8943..b5c9511 100644
--- a/frontend/src/lib/server/migrate.ts
+++ b/frontend/src/lib/server/migrate.ts
@@ -106,27 +106,30 @@ async function ensureUsers(ids: Record): Promise {
changed = true;
}
- const listRule = "famId = @request.auth.famId";
- const parentWrite = "famId = @request.auth.famId && @request.auth.role = 'parent'";
- if (usersCol.listRule !== listRule || usersCol.viewRule !== listRule ||
- usersCol.updateRule !== parentWrite || usersCol.deleteRule !== parentWrite) {
- changed = true;
- }
+ const listRule = "famId = @request.auth.famId";
+ const parentWrite = "famId = @request.auth.famId && @request.auth.role = 'parent'";
+ // Members can edit their own record (name/colour); parents can edit any
+ // family member. Delete stays parent-only.
+ const selfOrParentWrite = "@request.auth.id = id || (famId = @request.auth.famId && @request.auth.role = 'parent')";
+ if (usersCol.listRule !== listRule || usersCol.viewRule !== listRule ||
+ usersCol.updateRule !== selfOrParentWrite || usersCol.deleteRule !== parentWrite) {
+ changed = true;
+ }
- if (changed) {
- await updateCollection(usersCol.id, {
- name: "users",
- type: "auth",
- listRule,
- viewRule: listRule,
- createRule: usersCol.createRule || "",
- updateRule: parentWrite,
- deleteRule: parentWrite,
- fields: usersCol.fields,
- indexes,
- passwordAuth: { enabled: true, identityFields },
- });
- }
+ if (changed) {
+ await updateCollection(usersCol.id, {
+ name: "users",
+ type: "auth",
+ listRule,
+ viewRule: listRule,
+ createRule: usersCol.createRule || "",
+ updateRule: selfOrParentWrite,
+ deleteRule: parentWrite,
+ fields: usersCol.fields,
+ indexes,
+ passwordAuth: { enabled: true, identityFields },
+ });
+ }
}
// Superuser-only OTP store for the child join gate. Holds the rotating code and
diff --git a/frontend/src/lib/stores/chat.svelte.ts b/frontend/src/lib/stores/chat.svelte.ts
index e4b8de4..3b12b67 100644
--- a/frontend/src/lib/stores/chat.svelte.ts
+++ b/frontend/src/lib/stores/chat.svelte.ts
@@ -50,21 +50,38 @@ class ChatStore {
});
async init(opts: ChatInit) {
+ // Re-initialize whenever the family OR the actor changes (e.g. switching
+ // between parent and child in the same browser session). The store is a
+ // module singleton — keeping the previous actor's identity/subscription
+ // would make one direction's realtime silently dead.
+ const sameIdentity =
+ this.initialized &&
+ this.famId === opts.famId &&
+ this.actorId === opts.actorId &&
+ this.actorType === opts.actorType;
+ if (sameIdentity) return;
+ if (this.initPromise) {
+ await this.initPromise;
+ if (
+ this.initialized &&
+ this.famId === opts.famId &&
+ this.actorId === opts.actorId &&
+ this.actorType === opts.actorType
+ )
+ return;
+ }
+
+ this.cleanup();
+ this.destroyed = false;
this.famId = opts.famId;
this.actorId = opts.actorId;
this.actorType = opts.actorType;
this.actorName = opts.actorName;
this.actorColor = opts.actorColor;
this.pbToken = opts.pbToken || '';
-
- if (this.initialized && this.famId === opts.famId) return;
- if (this.initPromise) {
- await this.initPromise;
- if (this.initialized && this.famId === opts.famId) return;
- }
-
- this.cleanup();
- this.destroyed = false;
+ this.messages = [];
+ this.typing = {};
+ this.unread = 0;
this.lastSeenAt = Date.now();
this.initPromise = (async () => {
diff --git a/frontend/src/routes/[fam]/[username]/preferences/+page.svelte b/frontend/src/routes/[fam]/[username]/preferences/+page.svelte
index 3db86ef..1954046 100644
--- a/frontend/src/routes/[fam]/[username]/preferences/+page.svelte
+++ b/frontend/src/routes/[fam]/[username]/preferences/+page.svelte
@@ -1,5 +1,5 @@