AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Mongodb Partner Portal

skill-mrlynn-claude-skills-mongodb-partner-portal · by mrlynn

Add sponsor/partner management with 5-tier system, multiple contacts, engagement tracking, access request workflows, and partner-specific RBAC

No reviews yet
0 installs
17 views
0.0% view→install

Install

$ agentstack add skill-mrlynn-claude-skills-mongodb-partner-portal

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-mrlynn-claude-skills-mongodb-partner-portal)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
4mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Mongodb Partner Portal? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

mongodb-partner-portal

Trigger

Use this skill when adding sponsor/partner management to a platform: partner CRUD with tier system, contact management, engagement tracking, access request workflows, and partner-specific RBAC.

> Sponsor management is the feature nobody thinks about until a VP asks "how many Gold partners renewed?" and you're querying raw JSON. — ML

Overview

Every hackathon, conference, and community program has sponsors. This skill provides a complete partner management system with 5-tier sponsorship levels, multiple contacts per organization, engagement tracking across events, and a partner portal with role-gated access. It integrates with the RBAC system (partner role) and email system (partner invite/approval/denial templates).

How to Use

Quick Start

Invoke with /mongodb-partner-portal or let Claude auto-activate when adding sponsor/partner management.

Python Tools

  • scripts/tier_report_generator.py — Generate partner engagement summary from JSON data

Reference Docs

  • references/tier-system.md — 5-tier sponsorship: perks, colors, sort order

Templates & Samples

  • assets/sample_partner.json — Example Partner document
  • assets/tier-badge-colors.json — Tier-to-color mapping for UI

Architecture Decisions

  • 5-tier system (platinum → community): Tiers control visibility, placement, and perks. The tier name maps to UI styling (badge colors, sort order).
  • Multiple contacts per partner: Organizations have multiple representatives. One is marked isPrimary for default communication.
  • Bidirectional engagement sync: When an event adds a partner, $addToSet updates the partner's engagement.eventsParticipated array. This maintains a denormalized view for partner dashboards.
  • Access request workflow: External users can request partner access. Admins approve/deny, triggering email notifications. Approved users get the partner role and partnerId on their user record.
  • Compound indexes: tier + status is the most common query pattern (e.g., "show all active gold partners").

Code Patterns

Pattern 1: Partner Model

// src/lib/db/models/Partner.ts
import mongoose, { Schema, Document, Types } from "mongoose";

export interface IPartner extends Document {
  name: string;
  description: string;
  logo?: string;
  website?: string;
  industry: string;
  tier: "platinum" | "gold" | "silver" | "bronze" | "community";
  status: "active" | "inactive" | "pending";
  companyInfo: {
    size?: "startup" | "small" | "medium" | "large" | "enterprise";
    headquarters?: string;
    foundedYear?: number;
    employeeCount?: string;
  };
  contacts: Array;
  engagement: {
    eventsParticipated: Types.ObjectId[];
    prizesOffered: Types.ObjectId[];
    totalContribution?: number;
    engagementLevel?: "low" | "medium" | "high";
    lastEngagementDate?: Date;
  };
  social?: { linkedin?: string; twitter?: string; github?: string; youtube?: string };
  tags: string[];
  notes?: string;
}

const PartnerSchema = new Schema({
  name: { type: String, required: true, unique: true },
  description: { type: String, required: true },
  logo: { type: String },
  website: { type: String },
  industry: { type: String, required: true },
  tier: { type: String, enum: ["platinum", "gold", "silver", "bronze", "community"], default: "bronze" },
  status: { type: String, enum: ["active", "inactive", "pending"], default: "pending" },
  companyInfo: {
    size: { type: String, enum: ["startup", "small", "medium", "large", "enterprise"] },
    headquarters: String, foundedYear: Number, employeeCount: String,
  },
  contacts: [{
    name: { type: String, required: true },
    email: { type: String, required: true },
    phone: String,
    role: { type: String, required: true },
    isPrimary: { type: Boolean, default: false },
  }],
  engagement: {
    eventsParticipated: [{ type: Schema.Types.ObjectId, ref: "Event" }],
    prizesOffered: [{ type: Schema.Types.ObjectId, ref: "Prize" }],
    totalContribution: Number,
    engagementLevel: { type: String, enum: ["low", "medium", "high"] },
    lastEngagementDate: Date,
  },
  social: { linkedin: String, twitter: String, github: String, youtube: String },
  tags: [{ type: String }],
  notes: { type: String },
}, { timestamps: true });

PartnerSchema.index({ tier: 1, status: 1 });
PartnerSchema.index({ industry: 1 });
PartnerSchema.index({ status: 1 });
PartnerSchema.index({ "engagement.engagementLevel": 1 });
PartnerSchema.index({ "contacts.email": 1 });
PartnerSchema.index({ tags: 1 });

export const PartnerModel = mongoose.models.Partner || mongoose.model("Partner", PartnerSchema);

Pattern 2: Partner Zod Schema

export const createPartnerSchema = z.object({
  name: z.string().min(2).max(200),
  description: z.string().min(10).max(2000),
  logo: z.string().url().optional(),
  website: z.string().url().optional(),
  industry: z.string().min(2).max(100),
  tier: z.enum(["platinum", "gold", "silver", "bronze", "community"]).default("bronze"),
  status: z.enum(["active", "inactive", "pending"]).default("pending"),
  companyInfo: z.object({
    size: z.enum(["startup", "small", "medium", "large", "enterprise"]).optional(),
    headquarters: z.string().max(200).optional(),
    foundedYear: z.number().int().min(1800).max(new Date().getFullYear()).optional(),
    employeeCount: z.string().max(50).optional(),
  }).optional(),
  contacts: z.array(z.object({
    name: z.string().min(2).max(100),
    email: z.string().email(),
    phone: z.string().max(30).optional(),
    role: z.string().min(2).max(100),
    isPrimary: z.boolean().default(false),
  })).min(1).max(10),
  social: z.object({
    linkedin: z.string().url().optional(),
    twitter: z.string().url().optional(),
    github: z.string().url().optional(),
    youtube: z.string().url().optional(),
  }).optional(),
  tags: z.array(z.string()).max(20).default([]),
  notes: z.string().max(5000).optional(),
});

export const updatePartnerSchema = createPartnerSchema.partial();

Pattern 3: Partner RBAC Integration

From the mongodb-rbac-middleware skill:

// Role group for partner portal access
export const PARTNER_PORTAL_ROLES: UserRole[] = ["super_admin", "admin", "partner"];

// Server-side guard
export async function requirePartner() {
  const session = await auth();
  if (!session?.user) redirect("/login");
  const role = effectiveRole(session.user);
  if (!PARTNER_PORTAL_ROLES.includes(role) && !(await isImpersonationActive())) redirect("/dashboard");
  return session;
}

// Edge middleware route protection
if (pathname.startsWith("/partner") && !pathname.startsWith("/partner/register")) {
  // Require partner, admin, or super_admin role
}

Pattern 4: Partner Email Templates

Three built-in email templates for the partner workflow:

| Template Key | When Sent | Variables | |-------------|-----------|-----------| | partner_invite | Admin invites a new partner contact | userName, companyName, url | | partner_access_approved | Admin approves a partner access request | userName, companyName, portalUrl | | partner_access_denied | Admin denies a partner access request | userName, notes (optional reviewer feedback) |

Pattern 5: Event-Partner Bidirectional Sync

// When creating an event with partners:
if (eventData.partners?.length) {
  await PartnerModel.updateMany(
    { _id: { $in: eventData.partners } },
    {
      $addToSet: { "engagement.eventsParticipated": event._id },
      $set: { "engagement.lastEngagementDate": new Date() },
    }
  );
}

Pattern 6: Tier Badge Colors

For UI rendering, map tiers to display colors:

const TIER_COLORS: Record = {
  platinum: "#B0B0B0",  // Silver-gray
  gold: "#FFD700",      // Gold
  silver: "#C0C0C0",    // Silver
  bronze: "#CD7F32",    // Bronze
  community: "#00ED64", // MongoDB Spring Green
};

Dependencies

No additional dependencies beyond the scaffold.

Common Pitfalls

  • Use $addToSet not $push for engagement arrays to prevent duplicate entries.
  • Require at least 1 contact in the Zod schema (.min(1)). A partner without a contact is useless.
  • Exclude /partner/register from auth middleware. New partners need to access the registration page before they have an account.
  • Use unique: true on partner name to prevent duplicate organizations. Handle the duplicate key error (E11000) gracefully.
  • Set isPrimary: true on exactly one contact. The UI should enforce this, and the API should validate it.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.