diff --git a/src/components/status-updates/StatusUpdateDialog.jsx b/src/components/status-updates/StatusUpdateDialog.jsx
index dcac93c..7379230 100644
--- a/src/components/status-updates/StatusUpdateDialog.jsx
+++ b/src/components/status-updates/StatusUpdateDialog.jsx
@@ -19,6 +19,7 @@ function StatusUpdateDialog({ open, onOpenChange, update, onSuccess, currentUser
const [associationId, setAssociationId] = useState('');
const [requestedAction, setRequestedAction] = useState('');
const [imageUrls, setImageUrls] = useState([]);
+ const [hiddenFromBoard, setHiddenFromBoard] = useState(false);
const [associations, setAssociations] = useState([]);
const [isSubmitting, setIsSubmitting] = useState(false);
const [createdAt, setCreatedAt] = useState('');
@@ -30,9 +31,11 @@ function StatusUpdateDialog({ open, onOpenChange, update, onSuccess, currentUser
setAssociationId(update.association_id);
setRequestedAction(update.requested_action || '');
setImageUrls(update.image_urls || []);
+ setHiddenFromBoard(!!update.hidden_from_board);
setCreatedAt(update.created_at ? new Date(update.created_at).toISOString().slice(0, 16) : new Date().toISOString().slice(0, 16));
} else {
setTitle(''); setContent(''); setAssociationId(''); setRequestedAction(''); setImageUrls([]);
+ setHiddenFromBoard(false);
setCreatedAt(new Date().toISOString().slice(0, 16));
}
}, [update, open]);
@@ -61,6 +64,7 @@ function StatusUpdateDialog({ open, onOpenChange, update, onSuccess, currentUser
created_by: currentUserId,
updated_at: new Date().toISOString(),
image_urls: imageUrls || [],
+ hidden_from_board: hiddenFromBoard,
created_at: new Date(createdAt).toISOString(),
};
@@ -177,14 +181,30 @@ function StatusUpdateDialog({ open, onOpenChange, update, onSuccess, currentUser
-
+
+ setHiddenFromBoard(e.target.checked)}
+ className="mt-0.5 h-4 w-4 rounded border-border"
+ />
+
+
+
diff --git a/src/integrations/supabase/types.ts b/src/integrations/supabase/types.ts
index fe925f3..972d785 100644
--- a/src/integrations/supabase/types.ts
+++ b/src/integrations/supabase/types.ts
@@ -8404,6 +8404,7 @@ export type Database = {
content: string | null
created_at: string
created_by: string | null
+ hidden_from_board: boolean
id: string
image_urls: Json | null
requested_action: string | null
@@ -8417,6 +8418,7 @@ export type Database = {
content?: string | null
created_at?: string
created_by?: string | null
+ hidden_from_board?: boolean
id?: string
image_urls?: Json | null
requested_action?: string | null
@@ -8430,6 +8432,7 @@ export type Database = {
content?: string | null
created_at?: string
created_by?: string | null
+ hidden_from_board?: boolean
id?: string
image_urls?: Json | null
requested_action?: string | null
diff --git a/src/pages/StatusUpdatesPage.tsx b/src/pages/StatusUpdatesPage.tsx
index a9b532f..f290924 100644
--- a/src/pages/StatusUpdatesPage.tsx
+++ b/src/pages/StatusUpdatesPage.tsx
@@ -46,7 +46,7 @@ export default function StatusUpdatesPage({ boardAssociationIds }: { boardAssoci
.from("status_updates")
.select("*, associations(name), status_update_votes(*), profiles:created_by(full_name)")
.order("created_at", { ascending: false });
- if (isBoardView) query = query.in("association_id", boardAssociationIds!);
+ if (isBoardView) query = query.in("association_id", boardAssociationIds!).eq("hidden_from_board", false);
if (!isBoardView && filterAssocId !== "all") query = query.eq("association_id", filterAssocId);
const { data } = await query;
setUpdates(data || []);
diff --git a/supabase/migrations/20260616200000_status_updates_hidden_from_board.sql b/supabase/migrations/20260616200000_status_updates_hidden_from_board.sql
new file mode 100644
index 0000000..c989185
--- /dev/null
+++ b/supabase/migrations/20260616200000_status_updates_hidden_from_board.sql
@@ -0,0 +1,19 @@
+-- Allow management to post status updates that are hidden from the board portal.
+alter table public.status_updates
+ add column if not exists hidden_from_board boolean not null default false;
+
+-- Board members can only read status_updates via association membership. Re-create
+-- that SELECT policy so association-only readers (board members) do NOT see updates
+-- flagged hidden_from_board. Staff roles (admin/manager/employee) and admins still
+-- see everything (the separate "Admins can view all status_updates" policy is unchanged).
+drop policy if exists "Authenticated users can read status updates for their associati" on public.status_updates;
+create policy "Authenticated users can read status updates for their associati"
+on public.status_updates
+for select
+to authenticated
+using (
+ ((association_id in (select get_user_association_ids())) and hidden_from_board = false)
+ or has_role(auth.uid(), 'admin'::app_role)
+ or has_role(auth.uid(), 'manager'::app_role)
+ or has_role(auth.uid(), 'employee'::app_role)
+);