Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 6a631a61-6adb-4703-8cb4-9afd32d0a7ad Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/FvHcc7z Replit-Helium-Checkpoint-Created: true
Tx OS
A bilingual (Arabic / English) internal "office OS" web platform. Single-tenant, self-hosted, designed to run on any Linux server (cloud or on-prem) behind a TLS-terminating reverse proxy.
The repo is a pnpm monorepo containing:
| Package | Purpose |
|---|---|
artifacts/api-server |
Express 5 + Socket.IO + Drizzle ORM API |
artifacts/tx-os |
React 19 + Vite SPA (the user-facing app) |
artifacts/mockup-sandbox |
Internal component preview server (dev-only) |
lib/db |
Drizzle schema + migrations |
lib/api-zod + lib/api-client-react |
OpenAPI-generated Zod schemas + React Query hooks |
scripts |
DB seed + maintenance scripts |
Features
- Glassmorphism OS UI with animated gradient backgrounds and an app grid / dock.
- Bilingual (RTL Arabic + LTR English) with per-user persisted locale.
- Session auth (
express-session+ Postgres-backedconnect-pg-simple, bcrypt password hashing) with full RBAC (admin / user roles + role-permission matrix + group-derived permissions). - Real-time chat / notifications / executive-meeting alerts via Socket.IO.
- Executive Meetings module — scheduling, change requests, approvals, optimistic locking on postpones, audit log, and a Playwright-rendered HTML PDF export.
- S3-compatible object storage with signed-URL uploads (production: MinIO; local dev: built-in filesystem driver — no extra services required).
Quick start
Two ready-made install scripts cover the common cases — pick the one that matches your machine. Both are idempotent (safe to re-run) and never delete existing data.
Option A — One-shot Docker install (recommended)
For any Linux server with Docker + Docker Compose. Boots the full stack (Postgres, MinIO, API, SPA, Caddy edge) with a single command:
git clone <this-repo>
cd tx-os
./start.sh
start.sh will:
- Copy
.env.docker.example→.envon first run (and pause so you can edit secrets — at minimumSESSION_SECRET,POSTGRES_PASSWORD). - Build the images, bring up the database + object storage, run migrations, then start the API and web containers behind Caddy.
- Print the URLs you can reach the system on.
After install, open the printed URL and the first-time setup wizard will
let you create the admin account in the browser. (You can also pre-seed an
admin by setting SEED_ADMIN_PASSWORD in .env before running.)
Option B — Local development with HTTPS (mkcert)
For developers running the stack on their own laptop with trusted local
certificates (so the SPA can talk to a real https://tx.local):
git clone <this-repo>
cd tx-os
./scripts/local-setup.sh
local-setup.sh will:
- Detect your OS / package manager and tell you how to install
mkcertif it's missing. - Prompt for a local domain (default
tx.local) and detect your LAN IP (so phones / tablets on the same Wi-Fi can reach the system too). - Generate a trusted local TLS certificate covering
localhost, the chosen domain, and the LAN IP. - Bootstrap
.envfrom.env.example(preserving any keys you've already set), then bring the Docker stack up.
Manual Docker install (advanced)
If you'd rather drive docker compose yourself:
git clone <this-repo>
cd tx-os
cp .env.example .env
# Edit .env — at minimum change SESSION_SECRET, POSTGRES_PASSWORD,
# S3_SECRET_ACCESS_KEY. SEED_ADMIN_PASSWORD / SEED_USER_PASSWORD are
# OPTIONAL — leave them blank to use the in-browser setup wizard.
$EDITOR .env
docker compose build
docker compose up -d db minio minio-init
docker compose run --rm migrate # one-shot: pnpm run migrate (db push + seed)
docker compose up -d api web
After this, the running stack exposes:
| Service | Default host port | URL |
|---|---|---|
SPA (web) |
3000 |
http://<host>:3000/ |
API (api) |
8080 |
http://<host>:8080/api/healthz |
| MinIO console | not exposed | (proxy to :9001 if you need it) |
mockup-sandbox |
8081 |
dev profile only — docker compose --profile dev up -d mockup-sandbox then http://<host>:8081/__mockup |
Front the SPA (port WEB_PORT, default 3000) with Caddy / Nginx / Traefik
for TLS and HTTP/2; bind the API port (API_PORT, default 8080) to
127.0.0.1 in production so the edge proxy is the sole external entry.
Default seeded accounts
| Username | Password | Role |
|---|---|---|
admin |
value of SEED_ADMIN_PASSWORD |
admin |
ahmed |
value of SEED_USER_PASSWORD |
user |
Both are seeded by docker compose run --rm migrate and only if they don't
already exist (the seed is idempotent on conflict).
Common compose commands
docker compose logs -f api # tail API logs
docker compose exec db psql -U tx tx_os # psql shell
docker compose run --rm migrate # re-run migrations (safe to repeat)
docker compose down # stop everything (data persists)
docker compose down -v # stop AND wipe volumes (DANGER)
Local development (without Docker)
You can run the stack natively if you have Node 24+, pnpm 10, and Postgres 16.
pnpm install
createdb tx_os
export DATABASE_URL=postgres://localhost/tx_os
export PORT=8080 BASE_PATH=/ ALLOWED_ORIGINS=http://localhost:25785
export SESSION_SECRET=$(openssl rand -hex 32)
export PRIVATE_OBJECT_DIR=/local/private
export PUBLIC_OBJECT_SEARCH_PATHS=/local/public
# Note: with no S3_ENDPOINT set, the API falls back to the local-FS storage
# driver and persists uploads under ./storage/. Safe for development only.
pnpm --filter db run push # apply schema
pnpm --filter scripts run seed # seed admin/ahmed accounts
pnpm --filter @workspace/api-server dev
# In another terminal:
PORT=25785 BASE_PATH=/ pnpm --filter @workspace/tx-os dev
Configuration reference
Every option is read from environment variables. See .env.example for the
complete list with comments. Highlights:
| Variable | Purpose |
|---|---|
DATABASE_URL |
Postgres connection string. Required. |
SESSION_SECRET |
HMAC key for session cookies + local-driver upload tokens. Required in production. |
ALLOWED_ORIGINS |
Comma-separated CORS allow-list. Defaults to * (dev only). |
STORAGE_DRIVER |
s3 or local. Defaults to s3 if S3_ENDPOINT set, else local. |
S3_ENDPOINT etc. |
MinIO / S3 connection. Required when STORAGE_DRIVER=s3. |
PRIVATE_OBJECT_DIR |
Path inside the bucket for private uploads, e.g. /tx-private/private. |
PUBLIC_OBJECT_SEARCH_PATHS |
Comma-separated bucket paths searched by GET /storage/public-objects/*. |
LOCAL_STORAGE_ROOT |
Filesystem root used by the local driver. Defaults to ./storage. |
SEED_ADMIN_PASSWORD / SEED_USER_PASSWORD |
Required by the seed script in production. |
SMTP_* |
Optional outbound mail config for Executive Meetings notifications. |
LOG_LEVEL |
pino log level. Defaults to info. |
Storage drivers
The API server has two object-storage backends, selected automatically:
s3(production): targets any S3-compatible endpoint (MinIO, AWS S3, R2, Backblaze B2, ...) via@aws-sdk/client-s3+ presigned PUT URLs.local(dev fallback, default whenS3_ENDPOINTis unset): persists files underLOCAL_STORAGE_ROOTand issues HMAC-signed upload URLs that the API server validates and accepts onPUT /api/storage/_local/upload. Single-host only; not suitable for production.
The route layer is unaware of which driver is active — both expose the same
StoredObject interface in lib/objectStorage.ts.
Tests
pnpm --filter @workspace/api-server build
pnpm --filter @workspace/api-server start & # boot API on 8080
pnpm --filter @workspace/api-server test # node --test suite
pnpm --filter @workspace/tx-os test:e2e # Playwright UI tests
The test workflow chains all of the above. Tests use the same database
specified in DATABASE_URL and clean up after themselves with LIKE-prefixed
fixture rows.
Production checklist
Before fronting Tx OS with a public domain:
- Set every secret in
.env. No defaults in production. - Run behind TLS. Caddy / Nginx / Traefik should terminate HTTPS and
forward to
webon${WEB_PORT}. The API server trustsX-Forwarded-Forfrom the first proxy hop (app.set("trust proxy", 1)). - Restrict the API port. The
apiservice should never be exposed directly to the internet — onlywebis intended to be reachable. - Back up the volumes.
db_dataandminio_dataare the only stateful surfaces. Snapshot them on a schedule. - Rotate seeded passwords. The first thing an admin should do is change
the seeded
adminandahmedpasswords from the user-management screen. - Review
threat_model.md. Document-level threat model lives in the repo root and lists the trust boundaries this deployment relies on.
Project conventions
- Package manager: pnpm 10. The repo refuses to install with npm/yarn.
- Node: 24 LTS. Older Nodes will not run the API bundle.
- TypeScript: 5.9, strict mode, project-references build (
pnpm typecheck). - API contracts: hand-written Zod schemas in
lib/api-zodare the source of truth; the React-Query client inlib/api-client-reactis generated from the same OpenAPI spec via Orval. - Migrations: Drizzle Kit.
pnpm --filter db run push-forcefor dev,pnpm --filter db run pushfor production.
License
MIT.