Neosrate
Reddit-style social platform — Spring Boot API + React/TypeScript front, with S3 media upload.
Back-end (API)
- Java 21
- Spring Boot 3
- Spring Security
- Spring Data JPA
- MySQL 8
- JWT (Auth0)
- BCrypt
- ModelMapper
- AWS S3 SDK
Front-end
- React 18
- TypeScript
- Vite (SWC)
- React Router DOM 6
- Axios
- Tailwind CSS 3
- Phosphor React
- jwt-decode
Full-screen for best quality.
Context
Neosrate is a Reddit-style social platform. Users create communities (c/name), publish posts with text, image or video, like, comment and follow a personalized feed. Dashboard to edit profile, photo, posts and communities. Dark interface with violet/slate accent.
The back-end (Spring Boot 3 + Java 21 + MySQL 8) implements stateless JWT auth, S3 media upload with file type validation, and explicit transactional deletion of users and communities.
The front-end (React 18 + TypeScript + Vite) consumes the API via Axios, manages auth in localStorage with expiration check via jwt-decode, and implements server-side pagination for posts and client-side for comments.
Technical decisions
API · Stateless JWT via OncePerRequestFilter
Each request passes through SecurityFilter, which extracts the token from the Authorization header, validates the HMAC256 signature via Auth0 SDK and injects UserDetails into the SecurityContext. CSRF disabled — no session cookie. Token carries userId, username and email as claims, no DB roundtrip to identify the caller.
API · AWS S3 for all media files
Profile images, community photos and post media go directly to S3 — database stores only the file_path. S3Service validates file type (JPEG, PNG, GIF, MP4) before upload and uses timestamp naming to avoid collision. New users and communities receive a default image via server-side copy within S3, without transferring the file.
API · Manual delete via @Transactional instead of FK constraint
Deleting a user or community cleans all related tables (posts, comments, likes, memberships, profile) via sequential repository calls within a single @Transactional. The order is explicit and traceable.
Front · Auth via localStorage + jwt-decode
Auth lives in four localStorage keys (authenticated, token, userId, username). On app load, the token is decoded with jwt-decode to check expiration without a server roundtrip. Auth state propagated via props where needed.
Front · Server-side pagination for posts, client-side for comments
Posts use server pagination: maxPerPagegrows +10 per “load more”, API returns only the needed slice. Comments are fetched at once and sliced on the client: comments.filter(c => c.postId === id).slice(0, maxComments).
Run locally
Requires: Docker and Git installed.
mkdir neosrate-local && cd neosrate-local
git clone https://github.com/odgiedev/neosrate
git clone https://github.com/odgiedev/neosrate-api
cp neosrate/.env.example neosrate/.env
cp neosrate-api/.env.example neosrate-api/.env
# Terminal 1 — API
cd neosrate-api && docker compose up
# Terminal 2 — Front
cd neosrate && docker compose up