feat: subscription tiers, branch-with-manager flow, platform command center

This commit is contained in:
EOH Developer
2026-10-05 10:20:04 -07:00
parent 04e3051eb6
commit fa375bde91
19 changed files with 958 additions and 75 deletions
+19 -13
View File
@@ -1,21 +1,15 @@
import { Schema, model, models, Model, Types, Document } from "mongoose";
import { DEFAULT_TIER, type TierId, type SubscriptionStatus } from "@/lib/tiers";
/**
* A Business is the top-level tenant in the system. Every other record
* (users, branches, products, sales, inventory, expenses, purchases)
* belongs to exactly one Business via a required `businessId`, and every
* query is scoped by it. This is what lets many independent companies use
* the same deployment without ever seeing each other's data.
*
* The owner is the first user created at sign-up: a SUPER_ADMIN with no
* branch assignment (branchId = null) who can see and manage ALL branches
* within their own business.
*/
export interface IBusiness extends Document {
_id: Types.ObjectId;
name: string;
ownerId: Types.ObjectId; // the SUPER_ADMIN who created the business
ownerId: Types.ObjectId;
isActive: boolean;
tier: TierId;
subscriptionStatus: SubscriptionStatus;
trialEndsAt: Date | null;
currentPeriodEnd: Date | null;
createdAt: Date;
updatedAt: Date;
}
@@ -25,9 +19,21 @@ const businessSchema = new Schema<IBusiness>(
name: { type: String, required: true, trim: true },
ownerId: { type: Schema.Types.ObjectId, ref: "User", required: true },
isActive: { type: Boolean, default: true },
tier: {
type: String,
enum: ["STARTER", "GROWTH", "ENTERPRISE"],
default: DEFAULT_TIER,
},
subscriptionStatus: {
type: String,
enum: ["TRIALING", "ACTIVE", "PAST_DUE", "SUSPENDED"],
default: "TRIALING",
},
trialEndsAt: { type: Date, default: null },
currentPeriodEnd: { type: Date, default: null },
},
{ timestamps: true }
);
export const Business =
(models.Business as Model<IBusiness>) || model<IBusiness>("Business", businessSchema);
(models.Business as Model<IBusiness>) || model<IBusiness>("Business", businessSchema);