Skip to content

System announcements and email verfication#185

Merged
acarlson33 merged 1 commit into
mainfrom
04-17-system_announcements_and_email_verfication
May 5, 2026
Merged

System announcements and email verfication#185
acarlson33 merged 1 commit into
mainfrom
04-17-system_announcements_and_email_verfication

Conversation

@acarlson33

@acarlson33 acarlson33 commented Apr 19, 2026

Copy link
Copy Markdown
Owner

This pull request introduces support for instance-wide system DM announcements, adds new feature flags, and enhances the Appwrite schema to support announcement delivery and improved login security. It also includes minor dependency updates and improved test coverage for new features.

Instance Announcements Support:

  • Added new environment variables in .env.local.example for announcements collections, system sender user ID, and announcement dispatcher secret. [1] [2]
  • Extended the Appwrite setup script (scripts/setup-appwrite.ts) to create new collections and attributes for announcements and announcement_deliveries, including relevant indexes and fields for managing announcement delivery and status. [1] [2] [3]

Feature Flags:

  • Added enable_instance_announcements and enable_email_verification feature flags to the setup script and tests, and updated the FEATURE_FLAGS object accordingly. [1] [2]

Appwrite Schema Enhancements:

  • Updated conversations and direct_messages collections with new attributes and indexes to support system announcement threads, read-only reasons, announcement references, and priority tags. [1] [2]

Login Security and Testing:

  • Improved test coverage for login security and feature flag handling, including mocks for email verification and feature flags, and added tests for system sender user session handling. [1] [2] [3] [4] [5] [6]

Dependency Updates:

  • Bumped versions for next, posthog-js, @next/bundle-analyzer, and eslint-config-next in package.json. [1] [2] [3]

@appwrite

appwrite Bot commented Apr 19, 2026

Copy link
Copy Markdown

Firepit

Project ID: 68b230a0002245833242

Sites (1)
Site Status Logs Preview QR
 firepit
68eed9c6001f50d8f260
Ready Ready View Logs Preview URL QR Code

Tip

HTTPS and SSL certificates are handled automatically for all your Sites

@coderabbitai

coderabbitai Bot commented Apr 19, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@acarlson33 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 21 minutes and 51 seconds before requesting another review.

To continue reviewing without waiting, purchase usage credits in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 69f08b12-4eae-4708-90af-6f2ee1df7208

📥 Commits

Reviewing files that changed from the base of the PR and between 100a506 and 6cfd7a9.

⛔ Files ignored due to path filters (2)
  • .env.local.example is excluded by none and included by none
  • bun.lock is excluded by !**/*.lock and included by bun.lock
📒 Files selected for processing (22)
  • package.json
  • scripts/setup-appwrite.ts
  • src/__tests__/auth-server.test.ts
  • src/__tests__/feature-flags.test.ts
  • src/__tests__/login-security.test.ts
  • src/app/(auth)/login/actions.ts
  • src/app/(auth)/login/page.tsx
  • src/app/(auth)/register/page.tsx
  • src/app/admin/actions.ts
  • src/app/admin/announcement-panel.tsx
  • src/app/admin/page.tsx
  • src/app/api/announcements/dispatch/route.ts
  • src/app/api/announcements/route.ts
  • src/app/api/auth/verify-email/route.ts
  • src/app/api/direct-messages/route.ts
  • src/app/chat/components/ConversationList.tsx
  • src/app/chat/components/DirectMessageView.tsx
  • src/lib/appwrite-announcements.ts
  • src/lib/auth-server.ts
  • src/lib/feature-flags-definitions.ts
  • src/lib/feature-flags.ts
  • src/lib/types.ts
📝 Walkthrough

Walkthrough

This PR adds a comprehensive instance announcements system and email verification feature to the application. It introduces new Appwrite collections and database schemas for announcements and deliveries, adds two feature flags (ENABLE_INSTANCE_ANNOUNCEMENTS, ENABLE_EMAIL_VERIFICATION), implements announcement creation/listing/dispatch logic with delivery tracking and retry mechanisms, adds email verification gates to the authentication flow, creates admin UI for managing announcements, and includes corresponding API routes, server actions, and test coverage.

Changes

Announcement & Email Verification Feature Implementation

Layer / File(s) Summary
Type Definitions & Feature Flags
src/lib/types.ts, src/lib/feature-flags-definitions.ts, src/lib/feature-flags.ts
New announcement domain types (Announcement, AnnouncementDelivery, priority/status enums) and email-verification types are defined. Feature flags ENABLE_INSTANCE_ANNOUNCEMENTS and ENABLE_EMAIL_VERIFICATION are registered with defaults to false.
Database Schema & Bootstrap
scripts/setup-appwrite.ts
Appwrite collections announcements and announcement_deliveries are created with full attribute/index schemas. Conversation and DirectMessage schemas are extended with system-announcement thread fields. Feature flag setup includes the new announcement and email-verification flags.
Core Announcement Logic
src/lib/appwrite-announcements.ts
Complete announcement lifecycle: creation with idempotency and scheduling, paginated listing with status filters, and dispatch of scheduled announcements with per-recipient delivery tracking, retry scheduling, and exponential backoff up to configurable attempt limits. Delivery rollup and status finalization are included.
Authentication & Verification
src/lib/auth-server.ts, src/app/(auth)/login/actions.ts
getServerSession blocks reserved system-sender users. loginAction and new resendVerificationAction enforce email verification when the feature flag is enabled, sending verification emails and returning structured results. registerAction propagates verification-required responses.
API Routes & Server Actions
src/app/api/announcements/route.ts, src/app/api/announcements/dispatch/route.ts, src/app/api/auth/verify-email/route.ts, src/app/admin/actions.ts, src/app/api/direct-messages/route.ts
GET/POST /announcements endpoints with admin authorization and feature-flag gating. POST /announcements/dispatch with secret-based authentication for scheduled dispatch. GET /auth/verify-email updates user verification status. Admin server actions for announcement CRUD and dispatch. Direct-messages API enforces read-only for system-announcement threads.
Admin UI
src/app/admin/announcement-panel.tsx, src/app/admin/page.tsx
New AnnouncementPanel component for admins: create announcements (immediate send, schedule, or draft), filter/paginate through prior announcements, and dispatch scheduled items. Admin page integrates the panel.
Login & Registration UI
src/app/(auth)/login/page.tsx, src/app/(auth)/register/page.tsx
Login page adds email-verification flow with success/error toast notifications and a "Resend verification email" button. Register page conditionally redirects on verification-required responses.
Chat UI Updates
src/app/chat/components/ConversationList.tsx, src/app/chat/components/DirectMessageView.tsx
Conversation list includes system-announcement threads in filtering. DirectMessageView uses div instead of p for message text wrapping.
Dependencies & Configuration
package.json
Minor version bumps for next, posthog-js, @next/bundle-analyzer, and eslint-config-next.
Tests & Validation
src/__tests__/auth-server.test.ts, src/__tests__/feature-flags.test.ts, src/__tests__/login-security.test.ts
New test cases for system-sender blocking, email-verification feature flag enforcement, resend-verification logic, and feature-flag definitions. Test mocks are extended to support feature-flag and user verification checks.

Sequence Diagram

sequenceDiagram
    participant User as User / Admin
    participant UI as Login / Announcement UI
    participant Server as Next.js Server
    participant Auth as Appwrite Auth
    participant DB as Appwrite DB
    participant Email as Email Service

    rect rgba(100, 150, 255, 0.5)
    Note over User,Email: Email Verification Flow
    User->>UI: Enter email & password, submit login
    UI->>Server: loginAction(formData)
    Server->>Auth: createEmailPasswordSession()
    Auth-->>Server: session ($id, userId)
    Server->>DB: Users.get(userId) → emailVerification
    alt Email Verification Enabled & Not Verified
        Server->>Auth: account.createEmailVerification()
        Auth->>Email: Send verification email
        Email-->>User: Verification email with secret link
        Server->>Auth: Delete session
        Server-->>UI: {verificationRequired: true}
        UI->>User: Show "Check your email" toast
        User->>Email: Click verification link
        Email->>Server: GET /api/auth/verify-email?userId=X&secret=Y
        Server->>Auth: account.updateVerification({userId, secret})
        Auth-->>Server: success
        Server-->>User: Redirect to /login?verified=1
        User->>UI: See success toast
    else Verified or Feature Disabled
        Server-->>UI: {success: true}
        UI->>User: Redirect to home
    end
    end

    rect rgba(150, 200, 100, 0.5)
    Note over User,Email: Announcement Dispatch Flow
    User->>UI: Admin creates & schedules announcement
    UI->>Server: createAnnouncementAction(announcement)
    Server->>DB: Create announcement document
    DB-->>Server: {id, status: "scheduled"}
    Server-->>UI: {announcement, ...}
    UI->>User: Show success toast
    
    Note over Server,DB: Later: Scheduled time arrives
    Server->>Server: dispatchScheduledAnnouncements()
    Server->>DB: Query announcements where scheduledFor ≤ now
    DB-->>Server: [announcement1, announcement2, ...]
    
    Server->>DB: Update announcement to "dispatching"
    Server->>DB: List all profile users (recipients)
    DB-->>Server: [userId1, userId2, ...]
    
    loop For each recipient
        Server->>DB: Check delivery record (announcement+recipient)
        alt Not delivered yet
            Server->>DB: Ensure conversation exists
            Server->>DB: Create/insert direct message
            Server->>DB: Mark delivery as "delivered"
        else Already delivered
            Note over Server: Skip
        end
    end
    
    Server->>DB: Aggregate delivery statuses
    Server->>DB: Update announcement {status: "sent", deliverySummary: {...}}
    Server-->>User: Announcements sent to all recipients
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Poem

🐰 Announcements hop into the fold,
Email verified, stories told,
Admins craft messages with care,
Dispatch them forth with retry flair!
System sender keeps the peace,
Feature flags bring sweet release. 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.09% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main changes: system announcements and email verification features are the primary focus of the changeset.
Description check ✅ Passed The description comprehensively covers the key changes including instance announcements support, feature flags, schema enhancements, login security improvements, and dependency updates, all of which align with the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 04-17-system_announcements_and_email_verfication
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch 04-17-system_announcements_and_email_verfication

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

acarlson33 commented Apr 19, 2026

Copy link
Copy Markdown
Owner Author

@acarlson33

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 3, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/lib/auth-server.ts (1)

30-62: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't collapse the system sender into an unauthenticated session.

getServerSession() is also used by routes that intentionally special-case the reserved account. In particular, src/app/api/direct-messages/route.ts:436-442 checks session.$id === SYSTEM_SENDER_USER_ID to make announcement threads writable for the system sender, and src/app/api/direct-messages/route.ts:1227-1233 uses the same identity to allow sends into those threads. Returning null here makes both branches unreachable, so the configured system sender can no longer read or post in its own announcement conversations.

Suggested direction
-    const systemSenderUserId = process.env.SYSTEM_SENDER_USER_ID?.trim() || null;
@@
-        if (systemSenderUserId && user.$id === systemSenderUserId) {
-            return null;
-        }
-
         return {
             $id: user.$id,
             name: user.name,
             email: user.email,

Keep getServerSession() as the raw session lookup, and enforce the reserved-account block in higher-level interactive auth paths such as requireAuth() or the login actions instead.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/auth-server.ts` around lines 30 - 62, getServerSession currently
treats the configured SYSTEM_SENDER_USER_ID as unauthenticated and returns null
when user.$id === systemSenderUserId; instead preserve and return the session
for that reserved account (do not collapse it to null) and move the “deny or
special-case” logic into higher-level auth gates (e.g., requireAuth(), login
action handlers, or other interactive paths) so those functions explicitly
enforce or special-case systemSenderUserId where needed; update the code paths
that previously relied on getServerSession() returning null to check for
systemSenderUserId themselves.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/setup-appwrite.ts`:
- Around line 1283-1286: Change the conversations index created via
ensureIndex("conversations", "idx_announcement_thread", "key",
["isSystemAnnouncementThread","announcementThreadKey"]) to use a "unique" index
type instead of "key"; update the ensureIndex call for "idx_announcement_thread"
to pass "unique" so the DB enforces uniqueness on (isSystemAnnouncementThread,
announcementThreadKey) and prevents duplicate system announcement threads
created by the read-then-create flow in src/lib/appwrite-announcements.ts.

In `@src/app/`(auth)/login/actions.ts:
- Around line 344-467: resendVerificationAction duplicates client/session/setup
and auth-error logic found in loginAction; extract shared pieces into small
helpers (e.g., a function to build Appwrite client/account like
createAppwriteClient(endpoint, project, apiKey), a function to create and return
an email/password session like createEmailPasswordSession(account, email,
password) that also handles systemSenderUserId check and optional
reserved-account cleanup, and a helper parseAuthError(error) to centralize the
error-to-user-message mapping) and call those from both resendVerificationAction
and loginAction; ensure helpers return enough context (session, accountUser, or
structured error) so resendVerificationAction can still perform its unique flow
(checking emailVerification and calling sendVerificationEmailForSession) and
always perform the best-effort session deletion via a shared cleanup helper
(deleteSessionBestEffort) to avoid duplicating try/catch cleanup code.

In `@src/app/`(auth)/login/page.tsx:
- Around line 25-43: The page keeps the verified query param in the URL so the
same toast reappears on refresh/navigation; after handling the verified value in
the useEffect (where you read searchParams.get("verified") and update
notifiedVerificationStatusRef.current), remove/consume that query param from the
URL so it no longer triggers again — use the Next.js client router (useRouter)
and call router.replace to navigate to the same path without the "verified"
param (do this after showing toast and after setting
notifiedVerificationStatusRef.current in the useEffect).

In `@src/app/`(auth)/register/page.tsx:
- Around line 68-70: When result.verificationRequired is true we currently call
toast.success(result.error) and router.push("/login") which drops the
previously-computed destination; instead preserve the pending post-signup
redirect by passing the existing destination through to the login flow (e.g.,
include destination as a query param or state when calling router.push) so after
verification and sign-in the user is redirected to the original
invite/deep-link. Update the branch that checks result.verificationRequired to
forward the destination variable (from the earlier lines) to router.push rather
than hardcoding "/login".

In `@src/app/admin/announcement-panel.tsx`:
- Around line 107-149: When starting a fresh fetch in loadAnnouncements (i.e.,
when cursorAfter is falsy), clear the first-page state before making the request
by resetting announcements and nextCursor so previous results cannot be mixed
with the new query; specifically, inside loadAnnouncements where you check if
(cursorAfter) { ... } else { ... }, call setAnnouncements([]) and
setNextCursor(undefined) (or null) before awaiting getAnnouncementsAction, then
proceed to setAnnouncements(result.items) and setNextCursor(result.nextCursor)
as you already do. Ensure you still set the appropriate loading flags
(setIsLoading / setIsLoadingMore) and preserve the existing error handling path.

In `@src/app/api/announcements/route.ts`:
- Around line 229-234: The error handling block using "if (error instanceof
Error) { return NextResponse.json({ success: false, error: error.message }, {
status: 400 }) }" can leak internal details; update the handler (the route
function) to map known error types (e.g., validation errors, Appwrite errors,
database errors) to specific safe messages and status codes, and for all other
unexpected errors return a generic message like "An unexpected error occurred"
(do not include error.message) while still logging the original error
server-side; keep the NextResponse.json shape { success: false, error: "<safe
message>" } and adjust status codes accordingly.

In `@src/app/api/direct-messages/route.ts`:
- Around line 1228-1236: The current guard only blocks replies when
isSystemAnnouncementThread is true, allowing conversations to be created with
SYSTEM_SENDER_USER_ID and bypassing read-only intent; update the logic so either
conversation creation or reply handling enforces the reserved account rule: in
the conversation creation branch (the handler for type=conversation) reject or
mark the thread as system-only if SYSTEM_SENDER_USER_ID is included unless
isSystemAnnouncementThread is explicitly set, or alternatively augment the POST
guard to also check whether the conversation's participants include
SYSTEM_SENDER_USER_ID and treat it as read-only (the functions/variables to
touch: the type=conversation request handling, getRelationshipStatus(),
isSystemAnnouncementThread, and SYSTEM_SENDER_USER_ID). Ensure the fix prevents
creating writable conversations with the reserved system sender and/or always
blocks POSTs to any thread involving SYSTEM_SENDER_USER_ID.

In `@src/app/chat/components/ConversationList.tsx`:
- Around line 194-196: The current early return on
conversation.isSystemAnnouncementThread prevents removal from
filteredConversations but later logic switches to unreadConversations and hides
read announcement threads when any other DM is unread; update the selection
logic that chooses between filteredConversations and unreadConversations (the
code that builds/uses unreadConversations and filteredConversations and the
place where the rendered list is chosen) so that system announcement threads are
always included: either add conversations with
conversation.isSystemAnnouncementThread into unreadConversations (or the unread
set) or take the union of unreadConversations and filteredConversations where
isSystemAnnouncementThread is true before rendering. Ensure you reference
conversation.isSystemAnnouncementThread, filteredConversations, and
unreadConversations when making the change.

In `@src/lib/appwrite-announcements.ts`:
- Around line 425-469: listAllProfileUserIds currently accumulates all user IDs
in memory (recipientIds) which can cause memory pressure for large user bases;
change the function to stream or process results in batches instead of returning
a full array—either convert it to an async generator that yields IDs as they are
retrieved or add a callback/handler parameter (e.g., onId or onBatch) that is
invoked per document or per page inside the while loop where
databases.listDocuments is called; keep the existing cursor handling
(cursorAfter, lastDocument) and filtering logic (excludeUserId, trimming userId)
but remove the final Array.from(new Set(...)) aggregation or de-duplicate
incrementally to avoid storing all IDs at once.
- Around line 856-928: The recipient dispatch loop in
dispatchScheduledAnnouncements currently awaits each dispatchToRecipient
sequentially which is slow for large recipient lists; change the loop to perform
batched parallel dispatch with a configurable concurrency limit: fetch
recipientIds via listAllProfileUserIds(systemSenderUserId), chunk recipientIds
into batches (size from a new DISPATCH_CONCURRENCY env/config value), and for
each chunk call Promise.all on dispatchToRecipient calls for that chunk (catch
per-recipient errors so one failure doesn't abort the batch); optionally add a
short delay between batches to avoid DB overload and keep rollup/finalize logic
unchanged (use function names dispatchScheduledAnnouncements,
dispatchToRecipient, listAllProfileUserIds, rollupDeliveryStatus,
finalizeAnnouncementDispatch to locate where to implement).

---

Outside diff comments:
In `@src/lib/auth-server.ts`:
- Around line 30-62: getServerSession currently treats the configured
SYSTEM_SENDER_USER_ID as unauthenticated and returns null when user.$id ===
systemSenderUserId; instead preserve and return the session for that reserved
account (do not collapse it to null) and move the “deny or special-case” logic
into higher-level auth gates (e.g., requireAuth(), login action handlers, or
other interactive paths) so those functions explicitly enforce or special-case
systemSenderUserId where needed; update the code paths that previously relied on
getServerSession() returning null to check for systemSenderUserId themselves.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f666dab5-cc16-4f6d-a54e-0497f0a40fb8

📥 Commits

Reviewing files that changed from the base of the PR and between f0efe51 and 100a506.

⛔ Files ignored due to path filters (2)
  • .env.local.example is excluded by none and included by none
  • bun.lock is excluded by !**/*.lock and included by bun.lock
📒 Files selected for processing (22)
  • package.json
  • scripts/setup-appwrite.ts
  • src/__tests__/auth-server.test.ts
  • src/__tests__/feature-flags.test.ts
  • src/__tests__/login-security.test.ts
  • src/app/(auth)/login/actions.ts
  • src/app/(auth)/login/page.tsx
  • src/app/(auth)/register/page.tsx
  • src/app/admin/actions.ts
  • src/app/admin/announcement-panel.tsx
  • src/app/admin/page.tsx
  • src/app/api/announcements/dispatch/route.ts
  • src/app/api/announcements/route.ts
  • src/app/api/auth/verify-email/route.ts
  • src/app/api/direct-messages/route.ts
  • src/app/chat/components/ConversationList.tsx
  • src/app/chat/components/DirectMessageView.tsx
  • src/lib/appwrite-announcements.ts
  • src/lib/auth-server.ts
  • src/lib/feature-flags-definitions.ts
  • src/lib/feature-flags.ts
  • src/lib/types.ts

Comment thread scripts/setup-appwrite.ts
Comment thread src/app/(auth)/login/actions.ts
Comment thread src/app/(auth)/login/page.tsx
Comment thread src/app/(auth)/register/page.tsx
Comment thread src/app/admin/announcement-panel.tsx
Comment thread src/app/api/announcements/route.ts
Comment thread src/app/api/direct-messages/route.ts
Comment thread src/app/chat/components/ConversationList.tsx
Comment thread src/lib/appwrite-announcements.ts
Comment thread src/lib/appwrite-announcements.ts
@acarlson33

Copy link
Copy Markdown
Owner Author

@coderabbitai resolve

@coderabbitai

coderabbitai Bot commented May 3, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Comments resolved and changes approved.

acarlson33 commented May 5, 2026

Copy link
Copy Markdown
Owner Author

Merge activity

  • May 5, 11:21 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • May 5, 11:26 PM UTC: Graphite rebased this pull request as part of a merge.
  • May 5, 11:27 PM UTC: @acarlson33 merged this pull request with Graphite.

@acarlson33 acarlson33 changed the base branch from 04-15-polls_in_messages_and_server_discovery_customization_updates to graphite-base/185 May 5, 2026 23:24
@acarlson33 acarlson33 changed the base branch from graphite-base/185 to main May 5, 2026 23:25
@acarlson33 acarlson33 force-pushed the 04-17-system_announcements_and_email_verfication branch from 100a506 to 6cfd7a9 Compare May 5, 2026 23:26
@acarlson33 acarlson33 merged commit fb9a23d into main May 5, 2026
2 of 4 checks passed
@acarlson33 acarlson33 deleted the 04-17-system_announcements_and_email_verfication branch May 5, 2026 23:27
This was referenced May 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant