How nazmulxdev/ecospark-hub works
1. Runtime and entrypoints
- This is a TypeScript REST API built on Node.js + Express, with src/app.ts assembling middleware/routes and src/server.ts starting the HTTP server.
- src/routes/index.ts is the main composition point that mounts all feature routers under the API namespace.
2. Layered request flow
- The codebase follows a clear route → controller → service → Prisma pattern.
- Controllers handle HTTP concerns, services hold business logic, and Prisma is the single persistence boundary to PostgreSQL.
- Validation is enforced at the edge with Zod via per-module validation files and the ValidateRequest middleware.
3. Domain module boundaries
- Each business area is isolated in its own module under src/modules/: auth, users, idea, vote, comment, watchlist, category, blog, member, admin, payment, and ideaPurchase.
- These modules are not just route groups; they represent distinct domain boundaries with their own controllers, services, constants, utils, and validation schemas.
4. Authentication and authorization
- Authentication is handled through Better Auth (src/lib/auth.ts) rather than a hand-rolled token system.
- Authorization is layered on top with AuthMiddelware, using role-based access control for USER / MEMBER / ADMIN flows.
- The app also extends Express types in src/types/express, which suggests request-scoped auth/session/user data is injected into handlers.
5. Core content workflow
- The central domain is the Idea lifecycle: drafts are created by members, submitted for review, then moved through UNDER_REVIEW → APPROVED / REJECTED.
- Public reads are separated from privileged writes: approved ideas are exposed publicly, while member/admin endpoints cover creation, edits, review, and moderation.
- Slug-based access is used for idea and blog retrieval, indicating a human-friendly URL layer on top of database IDs.
6. Community interaction features
- The platform’s engagement layer is split into votes, comments, and watchlists.
- Votes are tracked as a dedicated model and module, comments support nested replies, and watchlists let users save ideas for later access.
- These features are all idea-centric and depend on the authenticated user context, so they sit downstream of auth and upstream of Prisma.
7. Payments and monetization
- Payments are implemented as a separate subsystem with Stripe integration in src/config/stripe.config.ts and payment logic in src/modules/payment plus src/modules/ideaPurchase.
- The architecture includes both direct purchase and pay-later/resume-payment flows, and the README indicates status transitions such as UNPAID → PENDING → PAID.
- payment.cron.ts suggests there is also background reconciliation or cleanup logic beyond synchronous HTTP requests.
- Stripe webhooks are a critical inbound boundary: payment state is finalized asynchronously from Stripe back into the database.
8. Membership and admin operations
- Membership is modeled as its own domain with application and dashboard endpoints, distinct from general user features.
- Admin features cover user-role management, membership-request review, and analytics/dashboard data.
- This implies a higher-privilege operational plane that reads across multiple domain models rather than owning a separate datastore.
9. Media and file handling
- Image uploads are handled with multer at the request boundary and persisted to Cloudinary.
- The presence of deleteUploadedFileFromGlobalErrorHandler.ts shows uploaded files are cleaned up on failure, so file handling is integrated with global error recovery rather than left to controllers.
10. Data model and persistence
- Prisma is the single ORM, with schema split across domain files in prisma/schema/*.prisma and migrations under prisma/migrations.
- The schema reflects the product’s major aggregates: User, Idea, Category, Vote, Comment, Watchlist, Blog, IdeaPayment, IdeaPurchase, MembershipPayment, and Member.
- PostgreSQL is the main system of record; there are no signs of additional primary datastores.
11. Cross-cutting infrastructure
- The repo uses centralized configuration modules for environment, Prisma, Stripe, Cloudinary, and multer, which keeps external-service wiring out of feature modules.
- QueryBuilder indicates shared support for pagination, filtering, search, and sorting across list endpoints.
- generateSlug and shared response helpers (AppResponse, AppErrorResponse) show the API enforces consistent output and URL conventions across modules.
12. Error handling and resilience
- Errors are normalized through dedicated handlers for Prisma, Zod, JWT, Multer, syntax, Better Auth, and system errors.
- GlobalErrorHandler is the final boundary, translating internal failures into the repository’s standard response shape and optionally cleaning up uploaded files.
- This makes error handling a first-class architectural concern rather than an ad hoc controller responsibility.
13. Operational packaging
- The presence of vercel.json suggests deployment is intended to work in a Vercel-hosted environment, even though the app is structured as a conventional Express server.
- src/scripts/seed.ts and the Prisma migration history indicate the project has an explicit database lifecycle: generate, migrate, seed, then run the API.
14. High-level data flow
- Requests enter through Express routes, pass through validation and auth middleware, hit controllers, then business logic in services, and finally read/write PostgreSQL via Prisma.
- Side effects branch out to Stripe, Cloudinary, and Better Auth where needed, while webhooks and cron jobs feed asynchronous state back into the same database.
Main entry points: index.ts Route mount · prisma.ts Prisma client · app.ts App setup · AuthMiddelware.ts Auth guard
Components 23
Runtime
Express entrypoints and request pipeline
- Main entry · Process start and server launch
src/index.ts - HTTP server · Starts the Express app
src/server.ts - App setup · Assembles middleware and app-level wiring
src/app.ts - Route mount · Mounts feature routers under the API namespace
src/routes/index.ts
Domain modules
Feature boundaries under src/modules
- Auth · Authentication and session flow
src/modules/auth - Ideas · Idea lifecycle and moderation workflow
src/modules/idea - Engagement · Votes, comments, and watchlists around ideas
- Content · Categories and blog publishing
- Membership · Member area and membership state
src/modules/member - Apply member · Membership application flow
src/modules/beMember - Admin · Privileged moderation and dashboard operations
src/modules/admin - Payments · Stripe-backed payment lifecycle and reconciliation
src/modules/payment - Idea purchase · Idea purchase and payment linkage
src/modules/ideaPurchase
Infrastructure
Shared integrations, middleware, and error handling
- Better Auth · Central authentication integration
src/lib/auth.ts - Prisma client · Single database access boundary
src/lib/prisma.ts - Validate req · Edge validation for request payloads
src/middlewares/ValidateRequest.ts - Auth guard · Role-based access control for user, member, and admin flows
src/middlewares/AuthMiddelware.ts - Error stack · Normalized handlers and global failure boundary
src/middlewares/GlobalErrorHandler.ts - Cloudinary · Image upload persistence
src/config/cloudinary.config.ts - Stripe · Payment gateway integration and webhook source
src/config/stripe.config.ts
Data layer
Prisma schemas, migrations, and seed lifecycle
- Prisma schema · Domain models and enums split across Prisma files
prisma/schema/schema.prisma - Migrations · Schema evolution history
prisma/migrations - Seed data · Initial database population
src/utils/seed.ts
Connections 39
- Main entry → HTTP server: starts · Bootstraps the HTTP server
- HTTP server → App setup: loads · Server uses the configured Express app
- App setup → Route mount: mounts · App delegates API routing to the route composer
- Route mount → Auth: routes · Mounts auth endpoints
- Route mount → Ideas: routes · Mounts idea endpoints
- Route mount → Engagement: routes · Mounts voting, commenting, and watchlist endpoints
- Route mount → Content: routes · Mounts categories and blog endpoints
- Route mount → Membership: routes · Mounts member endpoints
- Route mount → Apply member: routes · Mounts membership application endpoints
- Route mount → Admin: routes · Mounts admin endpoints
- Route mount → Payments: routes · Mounts payment endpoints
- Route mount → Idea purchase: routes · Mounts idea purchase endpoints
- Auth → Better Auth: authn · Uses Better Auth for authentication
- Auth → Prisma client: stores · Persists user/session state through Prisma
- Ideas → Validate req: validates · Idea inputs are checked at the edge
- Ideas → Auth guard: guards · Member/admin actions require authorization
- Ideas → Prisma client: persists · Reads and writes ideas through Prisma
- Engagement → Auth guard: guards · Engagement actions require authenticated users
- Engagement → Prisma client: persists · Votes, comments, and watchlists use Prisma
- Content → Prisma client: reads · Categories and blogs are fetched from the database
- Membership → Auth guard: guards · Member area is privilege-aware
- Membership → Prisma client: persists · Membership state is stored via Prisma
- Apply member → Validate req: validates · Membership application payloads are validated
- Apply member → Prisma client: persists · Membership requests are written to the database
- Admin → Auth guard: guards · Admin functions are role-restricted
- Admin → Prisma client: reads/writes · Admin workflows span multiple models
- Payments → Stripe: charges · Stripe handles payment processing and webhooks
- Payments → Prisma client: persists · Payment state is finalized in Prisma
- Idea purchase → Payments: coordinates · Idea purchase flows depend on payment state
- Idea purchase → Prisma client: persists · Purchase linkage is stored in Prisma
- App setup → Validate req: uses · Request validation is applied in the app layer
- App setup → Auth guard: uses · Authorization is applied globally or per route
- App setup → Error stack: finalizes · Global error handling terminates the request pipeline
- App setup → Cloudinary: uploads · File handling is wired through Cloudinary
- App setup → Stripe: webhooks · Payment webhooks re-enter the app boundary
- App setup → Prisma client: depends on · Application data flows through Prisma
- Prisma client → Prisma schema: schema · Client is generated from the Prisma schema
- Prisma schema → Migrations: evolves via · Schema changes are tracked by migrations
- Prisma schema → Seed data: bootstraps · Seed data aligns with the schema