From 29c35f506d658a386644c4b8b5be1d53ebd9ef85 Mon Sep 17 00:00:00 2001 From: x3 Date: Tue, 22 Sep 2026 13:33:22 +0200 Subject: [PATCH] chore: initial repository scaffolding - Add README with features, quick-start (local + Docker) and docs index - Add MIT LICENSE, root .gitignore and .env.example - Add docker-compose.yml (postgres + backend + frontend) - Add root package.json with install:all/dev helpers - Add Gitea CI workflow (backend syntax check, frontend build) --- .env.example | 17 +++++++ .gitea/workflows/ci.yml | 25 ++++++++++ .gitignore | 6 +++ LICENSE | 21 ++++++++ README.md | 104 ++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 45 +++++++++++++++++ package.json | 13 +++++ 7 files changed, 231 insertions(+) create mode 100644 .env.example create mode 100644 .gitea/workflows/ci.yml create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 docker-compose.yml create mode 100644 package.json diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..83c8434 --- /dev/null +++ b/.env.example @@ -0,0 +1,17 @@ +# --- Database (used by backend + docker-compose) --- +DATABASE_URL=postgres://openstack:openstackpw@localhost:5432/openstack +POSTGRES_DB=openstack +POSTGRES_USER=openstack +POSTGRES_PASSWORD=change-me-in-production + +# --- Backend --- +PORT=3000 +JWT_SECRET=change-me-to-a-long-random-string +JWT_EXPIRES_IN=7d +CORS_ORIGIN=http://localhost:5173 +# Comma-separated origins allowed in production, e.g.: +# CORS_ORIGIN=https://openstack.example.com + +# --- Frontend (Vite; must start with VITE_) --- +VITE_API_URL=http://localhost:3000/api +VITE_SOCKET_URL=http://localhost:3000 diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..aac9911 --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,25 @@ +name: ci +on: [push, pull_request] +jobs: + backend: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - run: npm ci + working-directory: backend + - run: node --check src/index.js && node --check src/socket.js + working-directory: backend + frontend: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - run: npm ci + working-directory: frontend + - run: npm run build + working-directory: frontend diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0900635 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +node_modules/ +dist/ +.env +*.log +.DS_Store +coverage/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b67e66d --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 x3 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..384dda6 --- /dev/null +++ b/README.md @@ -0,0 +1,104 @@ +# openStack — Collaborative Workspace (Vue 3 + Express + PostgreSQL) + +A Notion-like collaborative workspace: rich pages, nested hierarchy, workspaces with +role-based members, real-time collaboration (Socket.IO), comments, search, and +light/dark mode. Self-hostable via Node.js or Docker Compose. + +> **Status:** Web app MVP (see [`docs/ROADMAP.md`](docs/ROADMAP.md) for desktop clients +> for Windows / macOS / Linux). + +## Features + +- **Auth** — Register / login with JWT (access token), bcrypt password hashing. +- **Workspaces** — Create workspaces, invite members by email (`owner` / `admin` / + `member` / `viewer`), change roles, remove members. +- **Pages** — Nested pages (`parent_id`), icon + cover, ordering, TipTap rich-text + content stored as JSON + rendered HTML. +- **Real-time collaboration** — Socket.IO rooms per page: live content broadcast, + presence (who is viewing), typing indicators. +- **Comments** — Threaded comments per page. +- **Search** — Full-text search (`ILIKE` on title/content, trigram-ready). +- **Light / dark mode** — CSS variables + persisted user preference. +- **Self-hostable** — Documented for bare-metal (`docs/HOSTING.md`) and Docker Compose. + +## Monorepo layout + +```text +openStack/ +├── frontend/ # Vue 3 + Vite + Pinia + Vue Router + TipTap +├── backend/ # Express + Socket.IO + pg (PostgreSQL) +├── docs/ # SETUP, HOSTING, API, ARCHITECTURE, ROADMAP +├── docker-compose.yml # postgres + backend + frontend +├── .env.example # All required env vars +└── .gitea/workflows/ # CI (lint + build + test) +``` + +## Quick start (development) + +Requirements: Node.js 20+, PostgreSQL 14+. + +```bash +# 1. Clone +git clone https://git.sysdaemon.xyz/x3/openStack.git +cd openStack + +# 2. Configure +cp .env.example .env +# edit .env -> DATABASE_URL, JWT_SECRET, ports + +# 3. Database +createdb openstack +psql openstack < backend/src/db/schema.sql + +# 4. Backend +cd backend && npm install && npm run dev +# -> http://localhost:3000 (API at /api, health at /api/health) + +# 5. Frontend (new terminal) +cd frontend && npm install && npm run dev +# -> http://localhost:5173 +``` + +Default dev flow creates the first user via **Register** in the UI; that user can then +create workspaces and invite others by email (invited email must have an account). + +## Quick start (Docker Compose) + +```bash +cp .env.example .env +# set POSTGRES_PASSWORD, JWT_SECRET, etc. +docker compose up --build +# frontend -> http://localhost:8080 +# backend -> http://localhost:3000/api/health +``` + +See [`docs/HOSTING.md`](docs/HOSTING.md) for production (reverse proxy, TLS, backups). + +## Documentation + +| Doc | Content | +|-----|---------| +| [`docs/SETUP.md`](docs/SETUP.md) | Local dev setup, DB, env vars, troubleshooting | +| [`docs/HOSTING.md`](docs/HOSTING.md) | Bare-metal hosting + Docker Compose hosting | +| [`docs/API.md`](docs/API.md) | REST + Socket.IO contract with curl examples | +| [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) | Data model, auth, realtime design | +| [`docs/ROADMAP.md`](docs/ROADMAP.md) | Webapp milestones + desktop clients (Win/Mac/Linux binaries via releases) | + +## Scripts (root) + +```bash +npm run install:all # install backend + frontend deps +npm run dev # runs backend+frontend concurrently (needs concurrently) +``` + +## Security notes + +- Passwords hashed with bcrypt (12 rounds). Never stored in plain text. +- JWT access tokens (default 7d expiry, configurable). Sent as `Authorization: Bearer `. +- Rate limiting on `/api/auth/*`. Helmet headers enabled. CORS allow-list via `CORS_ORIGIN`. +- Workspace access enforced server-side on every route (membership check + role check). +- Socket.IO authenticates via JWT in `auth.token` and re-checks page access on join. + +## License + +MIT — see [LICENSE](LICENSE). diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..c59a497 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,45 @@ +services: + postgres: + image: postgres:16-alpine + restart: unless-stopped + environment: + POSTGRES_DB: ${POSTGRES_DB:-openstack} + POSTGRES_USER: ${POSTGRES_USER:-openstack} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-openstackpw} + volumes: + - pgdata:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER:-openstack}"] + interval: 5s + timeout: 3s + retries: 10 + + backend: + build: ./backend + restart: unless-stopped + depends_on: + postgres: + condition: service_healthy + environment: + DATABASE_URL: postgres://${POSTGRES_USER:-openstack}:${POSTGRES_PASSWORD:-openstackpw}@postgres:5432/${POSTGRES_DB:-openstack} + PORT: 3000 + JWT_SECRET: ${JWT_SECRET:-change-me} + JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-7d} + CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:8080} + ports: + - "3000:3000" + + frontend: + build: + context: ./frontend + args: + VITE_API_URL: /api + VITE_SOCKET_URL: "" + restart: unless-stopped + depends_on: + - backend + ports: + - "8080:80" + +volumes: + pgdata: diff --git a/package.json b/package.json new file mode 100644 index 0000000..9974d13 --- /dev/null +++ b/package.json @@ -0,0 +1,13 @@ +{ + "name": "openstack", + "version": "0.1.0", + "private": true, + "description": "Notion-like collaborative workspace (Vue + Express + Postgres)", + "scripts": { + "install:all": "npm --prefix backend install && npm --prefix frontend install", + "dev": "npx concurrently \"npm --prefix backend run dev\" \"npm --prefix frontend run dev\"" + }, + "devDependencies": { + "concurrently": "^9.0.1" + } +}