Repository navigation
Expand file tree
/
Copy pathProject.js
More file actions
executable file
·192 lines (172 loc) · 5.39 KB
/
Copy pathProject.js
File metadata and controls
executable file
·192 lines (172 loc) · 5.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
const mongoose = require("mongoose");
// Encryption schema ko reuse karne ke liye alag se define kiya
const resourceConfigSchema = new mongoose.Schema(
{
encrypted: { type: String, select: false },
iv: { type: String, select: false },
tag: { type: String, select: false },
},
{ _id: false },
);
const fieldSchema = new mongoose.Schema({
key: { type: String, required: true },
type: {
type: String,
required: true,
enum: ["String", "Number", "Boolean", "Date", "Object", "Array", "Ref"],
},
required: { type: Boolean, default: false },
unique: { type: Boolean, default: false },
// For type: 'Ref' — target collection name within the same project
ref: { type: String },
// For type: 'Array' — describes each array item { type, fields? }
items: { type: mongoose.Schema.Types.Mixed },
default: { type: mongoose.Schema.Types.Mixed, default: undefined },
});
// For type: 'Object' — recursive sub-fields
fieldSchema.add({ fields: [fieldSchema] });
const collectionSchema = new mongoose.Schema({
name: { type: String, required: true },
model: [fieldSchema],
rls: {
enabled: { type: Boolean, default: false },
mode: {
type: String,
enum: ["public-read", "private", "owner-write-only"],
default: "public-read",
},
ownerField: { type: String, default: "userId" },
requireAuthForWrite: { type: Boolean, default: true },
},
});
/**
* Schema for OAuth providers like GitHub and Google.
* Sensitive data like clientSecret is stored in an encrypted format.
*/
const authProviderSchema = new mongoose.Schema(
{
enabled: { type: Boolean, default: false },
clientId: { type: String, default: "" },
clientSecret: { type: resourceConfigSchema, default: null },
redirectUri: { type: String, default: "" },
},
{ _id: false },
);
/**
* Legacy/compatibility schema for mail templates stored on the project
* document as an embedded fallback/migration path; templates are rendered
* server-side. Keep select:false to avoid accidentally returning large
* template payloads in standard project responses.
*/
const mailTemplateSchema = new mongoose.Schema(
{
name: { type: String, required: true },
subject: { type: String, default: "" },
html: { type: String, default: "" },
text: { type: String, default: "" },
updatedAt: { type: Date, default: Date.now },
},
{ _id: true },
);
const projectSchema = new mongoose.Schema(
{
name: { type: String, required: true },
description: String,
owner: {
type: mongoose.Schema.Types.ObjectId,
ref: "Developer",
},
publishableKey: {
type: String,
required: true,
unique: true,
},
secretKey: {
type: String,
required: true,
unique: true,
},
secretKeyEncrypted: {
type: resourceConfigSchema,
default: null,
},
secretKeyRevealed: {
type: Boolean,
default: false,
},
jwtSecret: {
type: String,
required: true,
},
isAuthEnabled: { type: Boolean, default: false },
allowPublicSignup: { type: Boolean, default: true },
siteUrl: { type: String, default: "" },
/**
* Managed OAuth providers for project user authentication.
*/
authProviders: {
github: { type: authProviderSchema, default: () => ({}) },
google: { type: authProviderSchema, default: () => ({}) },
},
resendApiKey: { type: resourceConfigSchema, default: null },
resendFromEmail: { type: String, default: "" },
mailTemplates: {
type: [mailTemplateSchema],
default: [],
select: false,
},
collections: [collectionSchema],
allowedDomains: {
type: [String],
default: ["*"],
},
// STORAGE LIMITS (Files)
storageUsed: { type: Number, default: 0 },
storageLimit: { type: Number, default: 20 * 1024 * 1024 },
// DATABASE LIMITS (JSON Docs)
databaseUsed: { type: Number, default: 0 },
databaseLimit: { type: Number, default: 20 * 1024 * 1024 },
// Internal write-lock version for atomic webhook quota reservations.
webhookQuotaVersion: { type: Number, default: 0, select: false },
// Granular Resources Structure
resources: {
db: {
isExternal: { type: Boolean, default: false },
config: { type: resourceConfigSchema, default: null },
},
storage: {
isExternal: { type: Boolean, default: false },
config: { type: resourceConfigSchema, default: null },
},
},
// CUSTOM OVERRIDES (Enterprise/Exceptions)
customLimits: {
reqPerDay: { type: Number, default: null },
storageBytes: { type: Number, default: null },
mailPerMonth: { type: Number, default: null },
maxCollections: { type: Number, default: null }
},
// BYOK — Bring Your Own Key for AI
byok: {
groqKey: { type: resourceConfigSchema, default: null },
},
// Team Members
members: {
type: [
new mongoose.Schema(
{
user: { type: mongoose.Schema.Types.ObjectId, ref: "Developer", required: true },
role: { type: String, enum: ["admin", "viewer"], default: "admin" },
addedAt: { type: Date, default: Date.now },
},
{ _id: false },
),
],
default: [],
},
},
{ timestamps: true },
);
projectSchema.index({ owner: 1 });
projectSchema.index({ "members.user": 1 });
module.exports = mongoose.model("Project", projectSchema);