Skip to content

Develop#31

Merged
NodeByteLTD merged 2 commits into
mainfrom
develop
Jun 24, 2026
Merged

Develop#31
NodeByteLTD merged 2 commits into
mainfrom
develop

Conversation

@NodeByteLTD

@NodeByteLTD NodeByteLTD commented Jun 24, 2026

Copy link
Copy Markdown
Owner

Summary

Describe what changed and why.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Chore / maintenance

Testing

List what you ran:

  • pnpm lint
  • pnpm build
  • Relevant tests for changed area

Commands/results:

Paste test output or brief notes here.

Screenshots / Evidence (if applicable)

Add screenshots, recordings, or logs.

Checklist

  • I linked related issue(s)
  • I updated docs where needed
  • I updated changelog for user-facing changes
  • I removed secrets from code, logs, and screenshots

Summary by CodeRabbit

Release Notes

  • New Features

    • Ban enforcement: Suspended admins are redirected to a dedicated account suspension page with limited access.
    • Email reputation enforcement: Automatic blocking when bounce or complaint rates exceed configured thresholds.
    • RFC 8058 one-click unsubscribe: Improved email compliance with header and endpoint support.
    • Admin panel: Force domain verification, delete domains and teams, manage extra slots for teams.
    • Team-scoped notifications with optional Discord webhook for bounce and complaint alerts.
  • Bug Fixes

    • Extended limit-reason messages in upgrade modal for additional scenarios.
  • Documentation

    • Added AGENTS.md with repository guidelines for AI coding agents.

@NodeByteLTD NodeByteLTD merged commit 757dbfa into main Jun 24, 2026
14 of 16 checks passed
@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d8e31fa5-0f65-40c3-8fd7-d09c44575a19

📥 Commits

Reviewing files that changed from the base of the PR and between 3546c35 and 043d04e.

📒 Files selected for processing (20)
  • AGENTS.md
  • CHANGELOG.md
  • apps/web/middleware.ts
  • apps/web/src/app/(dashboard)/admin/domains/page.tsx
  • apps/web/src/app/(dashboard)/admin/teams/page.tsx
  • apps/web/src/app/api/unsubscribe-oneclick/route.ts
  • apps/web/src/app/banned/page.tsx
  • apps/web/src/components/payments/UpgradeModal.tsx
  • apps/web/src/env.js
  • apps/web/src/lib/constants/plans.ts
  • apps/web/src/server/api/routers/admin.ts
  • apps/web/src/server/api/trpc.ts
  • apps/web/src/server/auth.ts
  • apps/web/src/server/aws/ses.ts
  • apps/web/src/server/public-api/auth.ts
  • apps/web/src/server/service/email-queue-service.ts
  • apps/web/src/server/service/limit-service.ts
  • apps/web/src/server/service/notification-provider-service.ts
  • apps/web/src/server/service/ses-hook-parser.ts
  • apps/web/src/server/utils/email-headers.ts

Walkthrough

This PR implements three independent feature sets for ByteSend 0.3.2: end-to-end account ban enforcement (auth callbacks, JWT, middleware redirect, tRPC middleware, public REST API, and a new /banned page); email deliverability enforcement (bounce/complaint rate blocking via LimitService, RFC 8058 one-click unsubscribe header threading, and SES hook alert routing through NotificationProviderService); and admin panel additions (domain force-verify/delete, team extra-slot fields, team deletion, and plan assignment UI).

Changes

Ban Enforcement

Layer / File(s) Summary
Auth types, callbacks, and isBanned propagation
apps/web/src/server/auth.ts
Augments Session.user, User, and JWT with isBanned; credentials authorize selects isBanned and throws "BANNED"; signIn callback blocks banned users with a /login?error=banned redirect; jwt callback writes token.isBanned; session callback surfaces isBanned; OAuth update normalizes id via parseInt.
tRPC authedProcedure and public REST API ban guard
apps/web/src/server/api/trpc.ts, apps/web/src/server/public-api/auth.ts
authedProcedure becomes async and queries db.user.isBanned, throwing FORBIDDEN when true. getTeamFromToken queries for a banned ADMIN team user and throws ByteSendApiError FORBIDDEN when found.
Middleware redirect and /banned page
apps/web/middleware.ts, apps/web/src/app/banned/page.tsx
Adds /banned to publicPaths; post-authentication check redirects users with token.isBanned to /banned before 2FA validation. New BannedPage renders a suspension message with a Discord invite link and footer.

Email Deliverability: Bounce/Complaint Enforcement, RFC 8058 Unsubscribe, and Notification Routing

Layer / File(s) Summary
LimitReason enum and UpgradeModal messages
apps/web/src/lib/constants/plans.ts, apps/web/src/components/payments/UpgradeModal.tsx
LimitReason gains BOUNCE_RATE_EXCEEDED and COMPLAINT_RATE_EXCEEDED. UpgradeModal messages map extended for CONTACTS, BOUNCE_RATE_EXCEEDED, and COMPLAINT_RATE_EXCEEDED.
Bounce/complaint rate enforcement in LimitService
apps/web/src/server/service/limit-service.ts
Defines hard-block and warn threshold constants with a minimum delivered-volume gate. Adds getRecentBounceStats aggregating 7-day dailyEmailUsage. checkEmailLimit blocks sending with the new LimitReason values when thresholds are exceeded and emits Discord/log warnings at warn thresholds.
RFC 8058 one-click unsubscribe pipeline
apps/web/src/server/utils/email-headers.ts, apps/web/src/server/aws/ses.ts, apps/web/src/server/service/email-queue-service.ts, apps/web/src/app/api/unsubscribe-oneclick/route.ts
buildHeaders gains unsubOneClickUrl; List-Unsubscribe prefers the one-click URL; List-Unsubscribe-Post gated on unsubOneClickUrl. sendRawEmail threads unsubOneClickUrl through. executeEmail derives unsubOneClickUrl via createOneClickUnsubUrl. New GET handler at /api/unsubscribe-oneclick issues a 302 redirect to /unsubscribe with preserved query params.
Admin observer webhook and notification routing
apps/web/src/env.js, apps/web/src/server/service/notification-provider-service.ts, apps/web/src/server/service/ses-hook-parser.ts
ADMIN_DISCORD_WEBHOOK_URL added as optional env var. broadcastNotification removes early-return when provider list is empty; adds fan-out to admin observer webhook with Team ID field, deduplicating against existing team provider URLs. assertNotAdminWebhook blocks that URL from use as a team provider. ses-hook-parser replaces direct Discord send with NotificationProviderService.broadcastNotification.

Admin Panel Enhancements

Layer / File(s) Summary
Admin router: new procedures and updated permissions
apps/web/src/server/api/routers/admin.ts
teamAdminSelection gains isActive, billingEmail, extraDomainSlots, extraMemberSlots. updateTeamSettings accepts the new slot fields and drops isEnvAdmin gating. adminAssignPlan drops its isEnvAdmin guard. Three new procedures: adminForceVerifyDomain, adminDeleteDomain, adminDeleteTeam.
Admin domains page: force-verify and delete
apps/web/src/app/(dashboard)/admin/domains/page.tsx
Wires adminForceVerifyDomain and adminDeleteDomain mutations with toast feedback and query refetch. Table gains an Actions column with conditional force-verify and delete buttons.
Admin teams page: extra slots, plan assignment, team deletion
apps/web/src/app/(dashboard)/admin/teams/page.tsx
Schema and form defaults gain extraDomainSlots/extraMemberSlots. canAssignPlans gates on isAdmin. Plan assignment split into two button handlers. deleteTeam mutation added with a Danger Zone UI block.
AGENTS.md and CHANGELOG 0.3.2
AGENTS.md, CHANGELOG.md
AGENTS.md added as a full repository/architecture/conventions reference for AI agents. CHANGELOG 0.3.2 section documents all changes in this release.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant middleware as Next.js Middleware
  participant authedProcedure as tRPC authedProcedure
  participant getTeamFromToken as REST getTeamFromToken
  participant db as Database

  User->>middleware: Request to dashboard route
  middleware->>middleware: Verify JWT token
  middleware->>middleware: Check token.isBanned
  alt isBanned = true
    middleware-->>User: 302 redirect to /banned
  else isBanned = false
    middleware-->>User: Continue to route

    User->>authedProcedure: tRPC mutation/query
    authedProcedure->>db: SELECT isBanned FROM user WHERE id = session.user.id
    db-->>authedProcedure: isBanned
    alt isBanned = true
      authedProcedure-->>User: FORBIDDEN (account suspended)
    else isBanned = false
      authedProcedure-->>User: Proceed to resolver
    end

    User->>getTeamFromToken: REST API request with API key
    getTeamFromToken->>db: Find teamUser with role=ADMIN and user.isBanned=true
    db-->>getTeamFromToken: banned admin found?
    alt banned admin found
      getTeamFromToken-->>User: FORBIDDEN (account suspended)
    else no banned admin
      getTeamFromToken-->>User: Return team data
    end
  end
Loading
sequenceDiagram
  participant LimitService
  participant db as dailyEmailUsage (DB)
  participant Discord
  participant NotificationProviderService
  participant SESHookParser

  LimitService->>LimitService: checkEmailLimit(teamId)
  LimitService->>db: aggregate 7-day hardBounced/complained/delivered
  db-->>LimitService: stats
  alt delivered >= MIN_DELIVERED
    LimitService->>LimitService: compute bounceRate, complaintRate
    alt bounceRate >= HARD_LIMIT
      LimitService->>Discord: sendToDiscord (bounce block alert)
      LimitService-->>LimitService: return BOUNCE_RATE_EXCEEDED
    else complaintRate >= HARD_LIMIT
      LimitService->>Discord: sendToDiscord (complaint block alert)
      LimitService-->>LimitService: return COMPLAINT_RATE_EXCEEDED
    else rate >= WARN_LIMIT
      LimitService->>Discord: sendToDiscord (reputation warning)
    end
  end

  SESHookParser->>NotificationProviderService: broadcastNotification(teamId, EMAIL_BOUNCED/EMAIL_COMPLAINED)
  NotificationProviderService->>NotificationProviderService: fan-out to team providers
  NotificationProviderService->>Discord: admin observer webhook (ADMIN_DISCORD_WEBHOOK_URL)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • NodeByteLTD/ByteSend#18: Modifies the same updateTeamSettings and adminAssignPlan procedures in apps/web/src/server/api/routers/admin.ts that this PR further changes with extra slot fields and authorization guard removals.
  • NodeByteLTD/ByteSend#28: Both PRs modify the authenticated dashboard-route flow in apps/web/middleware.ts; the retrieved PR adds 2FA-cookie validation at the same location where this PR inserts the token.isBanned redirect check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch develop

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.

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.

2 participants