You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Pulled this vertical slice out of the main SJP repo as a standalone code sample. This is the same article submission → review → publish pipeline as the Laravel slice, rebuilt with React, Node.js, and TypeScript. The rest of the system (editorial board, analytics, billing, etc.) lives in the main repo and isn't included here. Docs below are from the relevant wiki pages.
1. Overview
Handles the end-to-end article lifecycle:
Stage
Actor
What happens
Submission
Author
Creates article record, uploads manuscript (PDF/DOCX), associates with a journal
Review
Reviewer
Evaluates submission from queue, transitions status (approve / reject)
Publication
Admin
Publishes approved articles — registers DOI via CrossRef and indexes on Google Scholar
2. Tech Stack
Layer
Technology
Version
Runtime
Node.js
≥ 18
API
Express.js
4.x
Language
TypeScript
5.7
ORM
Prisma
6.x
Database
PostgreSQL
14+
Auth
JWT (access + refresh token rotation)
jsonwebtoken
Validation
Zod
3.x
File Uploads
Multer
1.x
Frontend
React
18.x
Bundler
Vite
6.x
State
Zustand
5.x
Routing
React Router
6.x
Styling
Tailwind CSS
3.x
Forms
React Hook Form + Zod
—
Tests
Jest + Supertest
—
Monorepo
npm workspaces
client/ + server/
3. Running This Module
# Clone & installcd React-Node
npm install
# Database setup
cp .env.example .env # edit DATABASE_URL + credentials
npx prisma migrate dev -w server
npx prisma db seed -w server
# Start dev servers (API :3001, client :5173)
npm run dev
Seeded accounts: admin@sjplatform.local / reviewer@sjplatform.local (password: password). New registrations default to AUTHOR role.
Tests: npm test -w server — runs with mocked Prisma, no PostgreSQL needed.
Refresh tokens expire in 7 days, single-use (rotated on each refresh)
Axios interceptor automatically refreshes on 401 and retries the original request
9. Notes
Publish handles external API failures gracefully — CrossRef and Scholar fail independently, so partial success is possible (warnings returned in response)
File upload validates both extension and MIME type server-side
BigInt fileSize from PostgreSQL is automatically serialised to number in API responses
Frontend uses Zustand with persist middleware for token storage across page reloads
Monorepo managed via npm workspaces — single npm install at root handles both packages