Skip to content

jaseci-labs/this_is_not_jac

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

This is NOT Jac

A production-grade, non-Jac twin of the this is jac showcase. The original is a single fullstack Jac application (object-spatial graphs, walkers, client + server + native in one language). This repo rebuilds the exact same product with a conventional, boring, battle-tested stack — React + FastAPI + Postgres + Redis

  • a C→wasm game — so you can compare the two side by side.

Everything the Jac app does (a public guestbook graph, an embedded littleX social network, a live graph visualizer, a "read this site's own source" viewer, and a C cube-shooter compiled to WebAssembly) is reproduced here with separate, independently deployable services.


Architecture

                          ┌──────────────────────────────────────────┐
   browser  ──:8080──▶    │  frontend  (nginx : alpine)              │
                          │  • serves the built Vite/React SPA       │
                          │  • SPA fallback for /, /littlex, ...      │
                          │  • reverse-proxies same-origin:          │
                          │      /api/  /graph  /docs                 │
                          │      /openapi.json  /static/  ──┐         │
                          └─────────────────────────────────┼─────────┘
                                                            │
                                                            ▼
                          ┌──────────────────────────────────────────┐
                          │  backend  (gunicorn + 4 uvicorn workers)  │
                          │  FastAPI + async SQLAlchemy               │
                          │  /api/*  /graph  /docs  /static/*         │
                          └───────┬───────────────┬─────────┬─────────┘
                                  │               │         │
                       ┌──────────▼───┐   ┌───────▼────┐    │  POST /analyze
                       │  postgres 16 │   │  redis 7   │    ▼
                       │  (durable)   │   │  (cache)   │  ┌──────────────────┐
                       └──────────────┘   └────────────┘  │  analytics       │
                                                          │  (uvicorn x2)    │
                                                          │  separate FastAPI│
                                                          └──────────────────┘

   C cube-shooter ──(clang --target=wasm32)──▶ backend/static/main.wasm
                                              served at /static/main.wasm,
                                              instantiated by the WebGL shim.
Service Tech Role
frontend Vite + React + TS, served by nginx SPA + single-origin reverse proxy to the backend
backend FastAPI, async SQLAlchemy, gunicorn The data API, graph visualizer, Swagger docs, static assets
analytics FastAPI, uvicorn A genuinely separate microservice (mirrors the Jac sv import)
postgres PostgreSQL 16 Durable relational store for all tables
redis Redis 7 Read-through cache (transparent in-process LRU fallback)
C → wasm clang --target=wasm32 The cube-shooter game module (/static/main.wasm)

How it maps to the original Jac app

The Jac version expresses the whole product in one object-spatial language. Here each Jac concept is reimplemented with its conventional equivalent:

Jac feature Non-Jac equivalent here
Per-user root node A roots row (anonymous session) / a users + profiles row
Object-spatial graph (nodes + edges) Relational tables with foreign keys (app/models/*.py)
node / edge archetypes SQLAlchemy ORM models
walker traversals FastAPI endpoints + SQLAlchemy queries (app/api/*.py)
visit [-->] graph walk WHERE / JOIN over the FK relationships
allroots() cross-root read An unscoped SELECT (no root_id filter)
Per-root read WHERE root_id = :me
sv import to another server A real HTTP call to the analytics microservice (POST /analyze)
Jac client (.cl.jac) UI React + TypeScript components (frontend/src/)
sv endpoints (RPC over the graph) REST endpoints under /api/*
Jac auth / per-user isolation JWT bearer tokens + password_hash (app/core/security.py)
Jac runtime graph visualizer (/graph) A server-rendered HTML graph page at /graph
Native Jac (na) → wasm A hand-written C shooter compiled to wasm (native/shooter.c)
"Read this site's own source" panel Pygments-highlighted source endpoints (/api/source/*)

Quick start

Local development (no docker)

Zero setup — the backend falls back to SQLite and an in-process cache, so you don't even need Postgres or Redis running.

# one terminal: launches analytics (:8200), backend (:8100), frontend (:5173)
./scripts/dev.sh

Then open http://localhost:5173. The Vite dev server proxies /api, /graph, /docs, /openapi.json, and /static to the backend, so everything is same-origin (cookies, iframes, and wasm fetches all just work).

URLs:

What URL
App (open this) http://localhost:5173
Backend health http://localhost:8100/api/health
Swagger docs http://localhost:8100/docs
Graph visualizer http://localhost:8100/graph
Analytics health http://localhost:8200/health

Build just the frontend bundle:

./scripts/build.sh        # -> frontend/dist

Docker (production-like)

cp .env.example .env      # then edit: set TINJ_SECRET_KEY + POSTGRES_PASSWORD
docker compose up --build

Open http://localhost:8080. The frontend nginx container serves the built SPA and proxies the API to the backend service, which talks to postgres, redis, and analytics.

Run database migrations (the production schema path):

docker compose exec backend alembic upgrade head

The app's init_db() create_all runs automatically on startup for the zero-setup dev path; Alembic is the production migration path. Both produce the identical schema (see backend/alembic/versions/0001_initial.py).


Environment variables

All backend config is read from TINJ_-prefixed env vars (see backend/app/core/config.py). The most important ones:

Variable Example Notes
TINJ_ENVIRONMENT production development | production
TINJ_DATABASE_URL postgresql+asyncpg://tinj:pw@postgres:5432/tinj Async DSN. Defaults to local SQLite.
TINJ_REDIS_URL redis://redis:6379/0 Cache; falls back to in-process LRU if unreachable
TINJ_SECRET_KEY <openssl rand -hex 32> Required in prod. Signs JWTs.
TINJ_ANALYTICS_URL http://analytics:8000 Analytics microservice base URL
TINJ_CORS_ORIGINS ["http://localhost:8080"] Allowed browser origins
TINJ_SOURCE_ROOT /repo Repo root the source viewer exposes (RO mount)
TINJ_STATIC_DIR /app/static Bundled wasm / captures / logos
TINJ_FRONTEND_DIST /app/frontend-dist Optional: let the backend serve the SPA directly

Compose-only secrets (.env): POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD. See .env.example for the documented full list.


Endpoints

The backend mounts these routers (full interactive list at /docs):

Meta

  • GET /api/health — liveness + cache backend + pid

Auth (/api/auth)

  • POST /register, POST /login, POST /logout, GET /me — JWT bearer auth

Guestbook (/api/guestbook)

  • POST /sign, GET "", GET /explore, GET /stats

Graph

  • GET /api/graph/data — graph snapshot (JSON)
  • GET /graph — server-rendered live graph visualizer (HTML)

Source viewer (/api/source)

  • GET /files, GET /file?path=... — Pygments-highlighted source

littleX (/api/lx)

  • profiles: POST /setup_profile, GET /profile, GET /profiles
  • feed: POST /feed, GET /trending, POST /tweet, POST /like, POST /comment, POST /delete
  • social: POST /follow, POST /unfollow
  • channels: GET|POST /channels, GET /channels/{id}, POST /channels/{id}/join|leave|post

Analytics microservice (separate service)

  • GET /health, POST /analyze

Scaling notes

This stack is built to scale horizontally:

  • Gunicorn + uvicorn workers — the backend runs gunicorn -w 4 -k uvicorn.workers.UvicornWorker. Tune -w to roughly 2 × cores. Run multiple backend replicas behind a load balancer; they are interchangeable.
  • Stateless auth (JWT) — auth is a signed HS256 bearer token, so any backend replica can validate any request with no shared session store. Scale the API tier freely.
  • Redis cache — read-heavy endpoints (source listing, graph snapshots) are cached through Redis with a short TTL. The cache layer transparently falls back to an in-process LRU if Redis is unreachable, so a Redis blip degrades rather than breaks. Point all replicas at the same Redis for a shared cache.
  • Postgres connection pool — async SQLAlchemy uses a real pool (db_pool_size, db_max_overflow, pool_pre_ping, pool_recycle). Size the pool so replicas × (pool_size + max_overflow) stays under Postgres max_connections; add PgBouncer in front for large fan-outs.
  • Separate analytics service — independently scalable. It is stateless and can be replicated on its own schedule, exactly like the Jac sv import target.
  • CDN for static / wasmfrontend/dist assets are content-hashed and served with Cache-Control: immutable. Put a CDN in front of /assets/ and /static/ (including main.wasm) to offload bandwidth; the nginx config already sets long-lived caching headers for hashed assets.
  • Database migrations — schema changes ship via alembic upgrade head as a pre-deploy step; the app never alters schema in production.

Repo layout

.
├── backend/            FastAPI app (app.main:app), models, alembic migrations
│   ├── app/            api/  core/  models/  services/  schemas
│   ├── alembic/        env.py + versions/0001_initial.py (all tables)
│   ├── static/         bundled wasm / captures / logos
│   ├── Dockerfile      gunicorn + uvicorn workers, non-root, healthcheck
│   └── requirements.txt
├── analytics/          separate FastAPI microservice (app.main:app)
│   ├── app/main.py
│   └── Dockerfile      uvicorn --workers 2, non-root, healthcheck
├── frontend/           Vite + React + TS SPA
│   ├── src/            components, littlex, wasm shim
│   ├── nginx.conf      SPA fallback + reverse proxy (baked into the image)
│   └── Dockerfile      bun build -> nginx:alpine
├── infra/nginx/        canonical nginx.conf (mirrors frontend/nginx.conf)
├── native/             C cube-shooter -> wasm (shooter.c, build.sh)
├── scripts/            dev.sh (local stack), build.sh (frontend bundle)
├── docker-compose.yml  full production-like stack
├── .env.example        documented env vars
└── README.md

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors