|
| 1 | +# urBackend — Architecture Diagram |
| 2 | + |
| 3 | +## 1. System Overview |
| 4 | + |
| 5 | +```mermaid |
| 6 | +graph TB |
| 7 | + subgraph Clients["👤 Clients"] |
| 8 | + DEV["Developer\n(Dashboard User)"] |
| 9 | + EXTAPP["External App\n(API Consumer)"] |
| 10 | + end |
| 11 | +
|
| 12 | + subgraph Frontend["🖥️ Frontend — Vite + React\nurbackend.bitbros.in"] |
| 13 | + PAGES["Pages\nLogin / Register / Dashboard\nProject Detail / Storage / Analytics"] |
| 14 | + CTX["AuthContext"] |
| 15 | + COMPS["Components\nNavbar / Modals / Tables / Charts"] |
| 16 | + end |
| 17 | +
|
| 18 | + subgraph Backend["⚙️ Backend — Express.js\nRender / Railway"] |
| 19 | + APP["app.js\nEntry Point"] |
| 20 | +
|
| 21 | + subgraph Middleware["🛡️ Middleware"] |
| 22 | + RL_DASH["dashboardLimiter\n1000 req / 15 min"] |
| 23 | + RL_API["apiLimiter\n(limiter)"] |
| 24 | + CORS_ADMIN["adminCorsOptions\nWhitelist CORS"] |
| 25 | + AUTH_MW["authMiddleware\nJWT (Developer)"] |
| 26 | + API_MW["verifyApiKey\nHashed API Key + Redis Cache"] |
| 27 | + VERIFY_EMAIL["verifyEmail\nOwner isVerified check"] |
| 28 | + LOGGER["logger\nAPI usage logger"] |
| 29 | + end |
| 30 | +
|
| 31 | + subgraph Routes["📡 Routes"] |
| 32 | + R_AUTH["/api/auth"] |
| 33 | + R_PROJ["/api/projects"] |
| 34 | + R_DATA["/api/data"] |
| 35 | + R_UAUTH["/api/userAuth"] |
| 36 | + R_STORE["/api/storage"] |
| 37 | + R_SCHEMA["/api/schemas"] |
| 38 | + end |
| 39 | +
|
| 40 | + subgraph Controllers["🧩 Controllers"] |
| 41 | + C_AUTH["auth.controller\nregister / login\nchange-password / delete\nsendOtp / verifyOtp"] |
| 42 | + C_PROJ["project.controller\ncreateProject / updateProject\ncreateCollection / deleteCollection\ngetData / insertData / editRow\ndeleteRow / uploadFile / listFiles\ndeleteFile / analytics\nupdateExternalConfig"] |
| 43 | + C_DATA["data.controller\ninsertData / getAllData\ngetSingleDoc / updateSingleData\ndeleteSingleDoc"] |
| 44 | + C_UAUTH["userAuth.controller\nsignup / login / me"] |
| 45 | + C_STORE["storage.controller\nuploadFile / deleteFile\ndeleteAllFiles"] |
| 46 | + C_SCHEMA["schema.controller\ncheckSchema / createSchema"] |
| 47 | + end |
| 48 | +
|
| 49 | + subgraph Utils["🔧 Utils / Services"] |
| 50 | + CONN_MGR["connection.manager\nBYOD DB connections\n(registry cache)"] |
| 51 | + INJECT["injectModel\nDynamic Mongoose Model"] |
| 52 | + QUERY["queryEngine\nDynamic Query Builder"] |
| 53 | + STORE_MGR["storage.manager\nSupabase / External Storage"] |
| 54 | + EMAIL["emailService\nNodemailer / SMTP"] |
| 55 | + ENCRYPT["encryption\nAES-256-GCM"] |
| 56 | + GC["GC.js\nGarbage Collector\n(stale connections + storage)"] |
| 57 | + REDIS["redisCaching.js\nProject-by-APIKey Cache"] |
| 58 | + VALID["input.validation\nSchema-based Validator"] |
| 59 | + end |
| 60 | + end |
| 61 | +
|
| 62 | + subgraph Data["🗄️ Data Layer"] |
| 63 | + MONGO_MAIN["MongoDB Atlas\n(urBackend Internal DB)"] |
| 64 | + MONGO_EXT["External MongoDB\n(BYOD — User's own DB)"] |
| 65 | + SUPABASE["Supabase Storage\n(urBackend Internal)"] |
| 66 | + SUPABASE_EXT["External Storage\n(BYOD — User's own)"] |
| 67 | + REDIS_DB["Redis\n(Upstash)"] |
| 68 | + end |
| 69 | +
|
| 70 | + DEV -->|"Browser"| Frontend |
| 71 | + EXTAPP -->|"x-api-key header"| R_DATA & R_UAUTH & R_STORE & R_SCHEMA |
| 72 | +
|
| 73 | + Frontend -->|"JWT Bearer Token"| R_AUTH & R_PROJ |
| 74 | + APP --> Routes |
| 75 | + R_AUTH --> AUTH_MW --> C_AUTH |
| 76 | + R_PROJ --> AUTH_MW --> VERIFY_EMAIL --> C_PROJ |
| 77 | + R_DATA --> API_MW --> LOGGER --> C_DATA |
| 78 | + R_UAUTH --> API_MW --> LOGGER --> C_UAUTH |
| 79 | + R_STORE --> API_MW --> LOGGER --> C_STORE |
| 80 | + R_SCHEMA --> API_MW --> LOGGER --> C_SCHEMA |
| 81 | +
|
| 82 | + C_AUTH --> MONGO_MAIN |
| 83 | + C_PROJ --> CONN_MGR |
| 84 | + C_DATA --> CONN_MGR |
| 85 | + C_UAUTH --> CONN_MGR |
| 86 | + C_STORE --> STORE_MGR |
| 87 | + C_SCHEMA --> CONN_MGR |
| 88 | +
|
| 89 | + CONN_MGR -->|"isExternal: false"| MONGO_MAIN |
| 90 | + CONN_MGR -->|"isExternal: true\n(decrypt config)"| MONGO_EXT |
| 91 | + STORE_MGR -->|"isExternal: false"| SUPABASE |
| 92 | + STORE_MGR -->|"isExternal: true"| SUPABASE_EXT |
| 93 | +
|
| 94 | + API_MW -->|"Cache lookup"| REDIS_DB |
| 95 | +
|
| 96 | + C_AUTH --> EMAIL |
| 97 | +``` |
| 98 | + |
| 99 | +--- |
| 100 | + |
| 101 | +## 2. API Request Flow — External App (API Key) |
| 102 | + |
| 103 | +```mermaid |
| 104 | +sequenceDiagram |
| 105 | + participant App as External App |
| 106 | + participant MW as verifyApiKey Middleware |
| 107 | + participant Redis as Redis Cache |
| 108 | + participant DB as MongoDB (Projects) |
| 109 | + participant Ctrl as Controller |
| 110 | + participant DataDB as Data DB (Internal / External) |
| 111 | +
|
| 112 | + App->>MW: Request with x-api-key header |
| 113 | + MW->>Redis: Lookup hashed API key |
| 114 | + alt Cache hit |
| 115 | + Redis-->>MW: Return cached project |
| 116 | + else Cache miss |
| 117 | + MW->>DB: findOne({ apiKey: hashedKey }) |
| 118 | + DB-->>MW: Project doc (with owner, resources) |
| 119 | + MW->>Redis: Store in cache |
| 120 | + end |
| 121 | + MW->>MW: Check owner.isVerified |
| 122 | + MW->>Ctrl: req.project attached → next() |
| 123 | + Ctrl->>DataDB: Query (internal or external via connection.manager) |
| 124 | + DataDB-->>Ctrl: Results |
| 125 | + Ctrl-->>App: JSON Response |
| 126 | +``` |
| 127 | + |
| 128 | +--- |
| 129 | + |
| 130 | +## 3. BYOD (Bring Your Own Database/Storage) Flow |
| 131 | + |
| 132 | +```mermaid |
| 133 | +flowchart TD |
| 134 | + A["API Request arrives"] --> B["verifyApiKey middleware\nattaches req.project"] |
| 135 | + B --> C{"project.resources.db\n.isExternal?"} |
| 136 | + C -->|No| D["Use urBackend shared\nMongoDB connection"] |
| 137 | + C -->|Yes| E["connection.manager.js\nCheck registry cache"] |
| 138 | + E --> F{"Active connection\nin registry?"} |
| 139 | + F -->|Yes| G["Reuse cached connection"] |
| 140 | + F -->|No| H["Decrypt AES-256-GCM\ncredentials from Project doc"] |
| 141 | + H --> I["mongoose.createConnection(dbUri)"] |
| 142 | + I --> J["Store in registry\nwith lastAccessed timestamp"] |
| 143 | + J --> G |
| 144 | + G --> K["injectModel.js\nCreate dynamic Mongoose model\nfor collection + schema"] |
| 145 | + D --> K |
| 146 | + K --> L["queryEngine.js\nBuild + execute query"] |
| 147 | + L --> M["Return result to controller"] |
| 148 | +``` |
| 149 | + |
| 150 | +--- |
| 151 | + |
| 152 | +## 4. MongoDB Data Models |
| 153 | + |
| 154 | +```mermaid |
| 155 | +erDiagram |
| 156 | + Developer { |
| 157 | + ObjectId _id |
| 158 | + string email |
| 159 | + string password |
| 160 | + boolean isVerified |
| 161 | + date createdAt |
| 162 | + date updatedAt |
| 163 | + } |
| 164 | +
|
| 165 | + Project { |
| 166 | + ObjectId _id |
| 167 | + string name |
| 168 | + string description |
| 169 | + ObjectId owner |
| 170 | + string apiKey |
| 171 | + string jwtSecret |
| 172 | + number storageUsed |
| 173 | + number storageLimit |
| 174 | + number databaseUsed |
| 175 | + number databaseLimit |
| 176 | + object resources |
| 177 | + date createdAt |
| 178 | + date updatedAt |
| 179 | + } |
| 180 | +
|
| 181 | + Collection { |
| 182 | + string name |
| 183 | + FieldSchema[] model |
| 184 | + } |
| 185 | +
|
| 186 | + FieldSchema { |
| 187 | + string key |
| 188 | + string type |
| 189 | + boolean required |
| 190 | + } |
| 191 | +
|
| 192 | + OTP { |
| 193 | + ObjectId userId |
| 194 | + string otp |
| 195 | + date createdAt |
| 196 | + } |
| 197 | +
|
| 198 | + Log { |
| 199 | + ObjectId project |
| 200 | + string method |
| 201 | + string route |
| 202 | + number status |
| 203 | + number responseTime |
| 204 | + date createdAt |
| 205 | + } |
| 206 | +
|
| 207 | + Developer ||--o{ Project : "owns" |
| 208 | + Project ||--o{ Collection : "has" |
| 209 | + Collection ||--o{ FieldSchema : "has fields" |
| 210 | + Project ||--o{ Log : "generates" |
| 211 | + Developer ||--o{ OTP : "receives" |
| 212 | +``` |
| 213 | + |
| 214 | +--- |
| 215 | + |
| 216 | +## 5. Frontend Structure (Vite + React) |
| 217 | + |
| 218 | +```mermaid |
| 219 | +graph TD |
| 220 | + subgraph Entry["Entry"] |
| 221 | + MAIN["main.jsx"] |
| 222 | + APP["App.jsx\nReact Router"] |
| 223 | + end |
| 224 | +
|
| 225 | + subgraph Providers["Providers"] |
| 226 | + AUTHCTX["AuthContext\n(JWT token + developer state)"] |
| 227 | + end |
| 228 | +
|
| 229 | + subgraph Pages["Pages"] |
| 230 | + LP["Landing Page"] |
| 231 | + LOGIN["Login / Register"] |
| 232 | + DASH["Dashboard\n(Projects list)"] |
| 233 | + PROJ["Project Detail\n(Collections, API Key, Settings)"] |
| 234 | + COLL["Collection View\n(Browse & manage data)"] |
| 235 | + STORE_PG["Storage Page\n(File upload / delete)"] |
| 236 | + ANALYTICS["Analytics Page"] |
| 237 | + PROFILE["Profile Page"] |
| 238 | + BYOD_PG["BYOD Config Page"] |
| 239 | + end |
| 240 | +
|
| 241 | + subgraph Components["Shared Components"] |
| 242 | + NAVBAR["Navbar"] |
| 243 | + SIDEBAR["Sidebar"] |
| 244 | + MODALS["Modals\n(Create Project / Collection,\nBulk Mail, Schema, etc.)"] |
| 245 | + TABLES["Data Tables"] |
| 246 | + CHARTS["Usage Charts"] |
| 247 | + end |
| 248 | +
|
| 249 | + MAIN --> APP |
| 250 | + APP --> AUTHCTX |
| 251 | + AUTHCTX --> Pages |
| 252 | + Pages --> Components |
| 253 | + Pages -->|"fetch / axios"| BackendAPI["Backend REST API"] |
| 254 | +``` |
| 255 | + |
| 256 | +--- |
| 257 | + |
| 258 | +## 6. Security & Rate Limiting |
| 259 | + |
| 260 | +| Layer | Mechanism | Limit / Detail | |
| 261 | +|---|---|---| |
| 262 | +| Dashboard routes (`/api/auth`, `/api/projects`) | `dashboardLimiter` | 1000 req / 15 min | |
| 263 | +| API consumer routes | `limiter` (custom) | Configurable | |
| 264 | +| Developer auth | JWT (`authMiddleware`) | Bearer token, signed per dev | |
| 265 | +| API consumer auth | `verifyApiKey` | SHA-256 hashed key + Redis cache | |
| 266 | +| Email verification gate | `verifyEmail` | `owner.isVerified` must be `true` | |
| 267 | +| CORS | `adminCorsOptions` | Whitelist: `urbackend.bitbros.in` only | |
| 268 | +| Credential storage | AES-256-GCM encryption | BYOD DB/Storage configs encrypted in MongoDB | |
| 269 | +| File uploads | `multer` memory storage | 10 MB per file limit | |
| 270 | + |
| 271 | +--- |
| 272 | + |
| 273 | +## 7. Infrastructure Overview |
| 274 | + |
| 275 | +```mermaid |
| 276 | +graph LR |
| 277 | + subgraph Hosting["Hosting"] |
| 278 | + FE["Frontend\nVercel"] |
| 279 | + BE["Backend\nRender / Railway"] |
| 280 | + end |
| 281 | +
|
| 282 | + subgraph External["External Services"] |
| 283 | + MONGO["MongoDB Atlas\n(Primary DB)"] |
| 284 | + RDS["Upstash Redis\n(API Key Cache)"] |
| 285 | + SUP["Supabase\n(File Storage)"] |
| 286 | + SMTP["SMTP Server\n(OTP / Emails)"] |
| 287 | + end |
| 288 | +
|
| 289 | + subgraph BYOD["BYOD (User-owned)"] |
| 290 | + USER_MONGO["User's MongoDB Atlas"] |
| 291 | + USER_SUP["User's Supabase"] |
| 292 | + end |
| 293 | +
|
| 294 | + FE -->|"HTTPS REST"| BE |
| 295 | + ExternalApp["External App"] |
| 296 | + FE -->|"HTTPS REST"| BE |
| 297 | + ExternalApp -->|"x-api-key"| BE |
| 298 | + BE --> MONGO |
| 299 | + BE --> RDS |
| 300 | + BE --> SUP |
| 301 | + BE --> SMTP |
| 302 | + BE -.->|"Optional BYOD"| USER_MONGO |
| 303 | + BE -.->|"Optional BYOD"| USER_SUP |
| 304 | +``` |
0 commit comments