A web app for creating, sharing, and exploring interactive node-based graphs. Users can sign up, build graphs with a visual editor, make them public or private, like and comment on other people's graphs, and customize their profile.
| Graph View | Node Editor | Home Page |
|---|---|---|
![]() |
![]() |
![]() |
docker compose up --build -dOpen http://localhost:5173.
To stop and wipe the database:
docker compose down -vBackend:
cd backend
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r ../requirements.txt
# create a .env with DATABASE_URL and JWT_SECRET_KEY
python3 app.pyFrontend (from project root):
npm install
npm run devBackend tests run against an in-memory SQLite database — no Docker needed:
pip install -r requirements.txt
python -m pytest tests.py -vNote: Front-end tests are not functional at the moment.
- In-memory TTL cache — graph and paginated list responses are cached process-locally with configurable expiry, avoiding repeated DB queries for hot data.
- Rate limiting — node saves and avatar updates enforce a short cooldown per user to prevent spam writes.
- Pagination — the public graph listing supports
page/page_sizequery params so only a slice is loaded at a time. - Join-based comment loading — comments are fetched with an
outerjointo the users table in a single query, avoiding N+1. - Two-stage Docker build — the frontend Dockerfile uses a Node build stage then copies only the static output into a slim nginx image.
- Password hashing — passwords are stored as bcrypt hashes; plain-text passwords never touch the database.
- JWT in httpOnly cookies — access tokens are stored in cookies with CSRF double-submit protection enabled in production.
- Ownership enforcement — every mutating endpoint verifies the caller owns the target resource before allowing changes.
- Private graph access control — private graphs (and their comments/likes) return 404 for anyone who is not the owner.
- Input validation & sanitization — graph names are restricted to alphanumeric + spaces (max 40 chars), node fields are clamped (radius 8–100, font size 8–100, title ≤40, data ≤2000), comments are capped at 200 chars, and avatar URLs are validated against an allowlist of schemes.
- Account deletion — deleting an account cascades through graphs, comments, and likes so no orphaned data remains.
Backend (Python — see requirements.txt):
- Flask ≥ 2.0
- Flask-JWT-Extended ≥ 4.0
- Flask-Cors ≥ 3.0
- Flask-SQLAlchemy ≥ 2.5
- Flask-Bcrypt ≥ 0.7
- psycopg2-binary ≥ 2.8
- python-dotenv ≥ 0.20
- SQLAlchemy ≥ 1.4
Frontend (npm — see package.json):
- react ^19.2.0
- react-dom ^19.2.0
- react-router-dom ^7.13.1
- tailwindcss ^4.2.1
- vite ^7.3.1
Some icons used in this project are sourced from game-icons.net.


