diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 213d847..69a6199 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,9 +1,13 @@ name: Deploy HeadyConnection + on: push: branches: [main] + pull_request: + branches: [main] + jobs: - deploy: + test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -13,3 +17,12 @@ jobs: cache: 'npm' - run: npm ci - run: npm test + - name: Verify server starts + run: | + node index.js & + sleep 2 + curl -f http://localhost:8080/health || exit 1 + curl -f http://localhost:8080/ || exit 1 + curl -f http://localhost:8080/docs || exit 1 + curl -f http://localhost:8080/services || exit 1 + kill %1 diff --git a/Dockerfile b/Dockerfile index 4a7722c..83cab18 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,25 @@ -FROM node:20-slim +FROM node:20-slim AS build WORKDIR /app COPY package*.json ./ RUN npm ci --production -COPY . . -ENV NODE_ENV=production -ENV PORT=8080 + +FROM node:20-slim +WORKDIR /app + RUN groupadd -r heady && useradd -r -g heady heady + +COPY --from=build /app/node_modules ./node_modules +COPY package*.json ./ +COPY index.js site-config.json ./ + RUN chown -R heady:heady /app USER heady + +ENV NODE_ENV=production +ENV PORT=8080 EXPOSE 8080 + +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD node -e "const http=require('http');const r=http.get('http://localhost:8080/health',s=>{process.exit(s.statusCode===200?0:1)});r.on('error',()=>process.exit(1))" + CMD ["node", "index.js"] diff --git a/README.md b/README.md index a656452..5bf4aa2 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,91 @@ -# π€ HeadyConnection +# HeadyConnection > **Community & Connection** Collaborative AI workspace β connecting creators, developers, and enterprises through shared intelligence. [](https://headyconnection.org) -[](https://github.com/HeadyMe/Heady-pre-production-9f2f0642) +[](https://github.com/HeadyMe/headyos-core) ## Quick Start ```bash git clone https://github.com/HeadyMe/headyconnection-core.git cd headyconnection-core -npm install && npm start +npm install +npm start ``` -## Features +The server starts on port `8080` by default. Visit `http://localhost:8080` to see the landing page. -- π€ **Collaborative Workspaces** β Shared AI context across teams -- π‘ **Knowledge Sharing** β Cross-team intelligence transfer -- π **Community Hub** β Open-source contribution platform -- π **Deep Integration** β Connect with all Heady services +## Configuration ---- +All configuration is via environment variables: -**Β© 2026 Heady Systems LLC.** Built with Sacred Geometry Β· Powered by the Heady Latent OS +| Variable | Default | Description | +|---|---|---| +| `PORT` | `8080` | Server listen port | +| `NODE_ENV` | `development` | `production` enables structured JSON logs and HSTS | +| `BASE_URL` | `https://headyconnection.org` | Public base URL | +| `ALLOWED_ORIGINS` | Same as `BASE_URL` | Comma-separated CORS origins | + +## Routes + +| Method | Path | Description | +|---|---|---| +| `GET` | `/` | Landing page with features and ecosystem links | +| `GET` | `/docs` | Documentation page | +| `GET` | `/services` | Heady ecosystem service directory | +| `GET` | `/health` | Health check (JSON) | + +## Architecture + +HeadyConnection is a lightweight Express server that provides the community-facing landing page, documentation, and ecosystem navigation for the Heady Latent OS. + +- **Runtime:** Node.js 20+ with Express +- **Deployment:** Docker container on Google Cloud Run +- **Configuration:** Environment variables + `site-config.json` for branding +- **Security:** HSTS, Content-Type sniffing prevention, XSS protection, frame deny, env-driven CORS +- **Logging:** Structured JSON in production, human-readable in development +- **Shutdown:** Graceful SIGTERM/SIGINT handling for container orchestrators + +## Deployment + +### Docker + +```bash +docker build -t headyconnection . +docker run -p 8080:8080 -e NODE_ENV=production headyconnection +``` + +### Cloud Run + +The GitHub Actions workflow at `.github/workflows/deploy.yml` runs tests on every push to `main`. To add Cloud Run deployment, set the following repository secrets: + +- `GCP_PROJECT_ID` β Google Cloud project ID +- `GCP_SA_KEY` β Service account key JSON with Cloud Run deploy permissions + +## Heady Ecosystem + +| Service | URL | Description | +|---|---|---| +| HeadyMe | [headyme.org](https://headyme.org) | Personal AI Workspace | +| HeadySystems | [headysystems.com](https://headysystems.com) | Core Platform & Orchestration | +| HeadyOS | [headyos.org](https://headyos.org) | Latent Operating System | +| HeadyAPI | [headyapi.org](https://headyapi.org) | API Gateway & Services | +| HeadyIO | [headyio.org](https://headyio.org) | Input/Output & Integration Layer | +| HeadyMCP | [headymcp.org](https://headymcp.org) | Model Context Protocol | +| HeadyBuddy | [headybuddy.org](https://headybuddy.org) | AI Companion & Device Bridge | +| HeadyBot | [headybot.org](https://headybot.org) | Bot Framework & Automation | +| Heady Docs | [docs.headysystems.com](https://docs.headysystems.com) | Documentation Hub | + +## Troubleshooting + +- **Port conflict:** Set `PORT` env var to a different port +- **CORS errors:** Set `ALLOWED_ORIGINS` to include your client origin +- **Health check fails:** Ensure the server started β check logs for startup message + +## License + +Proprietary β Β© 2026 Heady Systems LLC. All Rights Reserved. +For commercial licensing: eric@headysystems.com diff --git a/index.js b/index.js index 9c52f52..3a43abb 100644 --- a/index.js +++ b/index.js @@ -4,13 +4,353 @@ * Projected from the Heady Latent OS */ const express = require('express'); -const app = express(); -const PORT = process.env.PORT || 3000; const siteConfig = require('./site-config.json'); + +const app = express(); +const PORT = parseInt(process.env.PORT, 10) || 8080; +const NODE_ENV = process.env.NODE_ENV || 'development'; +const BASE_URL = process.env.BASE_URL || 'https://headyconnection.org'; + +// --------------------------------------------------------------------------- +// Structured logging helper +// --------------------------------------------------------------------------- +function log(level, message, meta = {}) { + const entry = { + ts: new Date().toISOString(), + level, + service: 'HeadyConnection', + message, + ...meta, + }; + if (NODE_ENV === 'production') { + process.stdout.write(JSON.stringify(entry) + '\n'); + } else { + console.log(`[${entry.ts}] ${level.toUpperCase()} ${message}`, Object.keys(meta).length ? meta : ''); + } +} + +// --------------------------------------------------------------------------- +// Middleware +// --------------------------------------------------------------------------- app.use(express.json({ limit: '1mb' })); -app.get('/health', (req, res) => res.json({ ok: true, service: 'HeadyConnection', domain: 'headyconnection.org', projected: true, ts: new Date().toISOString() })); -app.get('/', (req, res) => { - res.setHeader('Content-Type', 'text/html; charset=utf-8'); - res.send(`
${siteConfig.description}
`); + +// Security headers +app.use((_req, res, next) => { + res.setHeader('X-Content-Type-Options', 'nosniff'); + res.setHeader('X-Frame-Options', 'DENY'); + res.setHeader('X-XSS-Protection', '1; mode=block'); + res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin'); + res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()'); + if (NODE_ENV === 'production') { + res.setHeader('Strict-Transport-Security', 'max-age=63072000; includeSubDomains; preload'); + } + next(); +}); + +// CORS β driven by environment, not hardcoded wildcards +const ALLOWED_ORIGINS = process.env.ALLOWED_ORIGINS + ? process.env.ALLOWED_ORIGINS.split(',').map((o) => o.trim()) + : [BASE_URL]; + +app.use((req, res, next) => { + const origin = req.headers.origin; + if (origin && ALLOWED_ORIGINS.includes(origin)) { + res.setHeader('Access-Control-Allow-Origin', origin); + res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); + res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); + } + if (req.method === 'OPTIONS') return res.sendStatus(204); + next(); +}); + +// Request logging +app.use((req, _res, next) => { + log('info', `${req.method} ${req.path}`, { ip: req.ip }); + next(); +}); + +// --------------------------------------------------------------------------- +// Heady ecosystem cross-links +// --------------------------------------------------------------------------- +const HEADY_SERVICES = [ + { name: 'HeadyMe', url: 'https://headyme.org', desc: 'Personal AI Workspace' }, + { name: 'HeadySystems', url: 'https://headysystems.com', desc: 'Core Platform & Orchestration' }, + { name: 'HeadyOS', url: 'https://headyos.org', desc: 'Latent Operating System' }, + { name: 'HeadyAPI', url: 'https://headyapi.org', desc: 'API Gateway & Services' }, + { name: 'HeadyIO', url: 'https://headyio.org', desc: 'Input/Output & Integration Layer' }, + { name: 'HeadyMCP', url: 'https://headymcp.org', desc: 'Model Context Protocol' }, + { name: 'HeadyBuddy', url: 'https://headybuddy.org', desc: 'AI Companion & Device Bridge' }, + { name: 'HeadyBot', url: 'https://headybot.org', desc: 'Bot Framework & Automation' }, + { name: 'Heady Docs', url: 'https://docs.headysystems.com', desc: 'Documentation Hub' }, +]; + +// --------------------------------------------------------------------------- +// Shared HTML helpers +// --------------------------------------------------------------------------- +function htmlHead(title) { + return ` + + + + +${f.desc}
${s.desc}
HeadyConnection is the community and collaboration layer of the Heady Latent OS ecosystem.
+ +git clone https://github.com/HeadyMe/headyconnection-core.git
+cd headyconnection-core
+npm install
+npm start
+
+ HeadyConnection reads configuration from environment variables:
+PORT β Server port (default: 8080)NODE_ENV β Environment: production or developmentBASE_URL β Public base URL (default: https://headyconnection.org)ALLOWED_ORIGINS β Comma-separated CORS originsHeadyConnection is a lightweight Express service that serves the community landing page, documentation, and ecosystem navigation. It is designed to be deployed as a standalone container on Google Cloud Run.
+site-config.jsonGET /health returns JSON statusGET / β Landing page with features and ecosystem linksGET /docs β This documentation pageGET /services β Heady ecosystem service directoryGET /health β Health check endpoint (JSON)# Build and run locally
+docker build -t headyconnection .
+docker run -p 8080:8080 -e NODE_ENV=production headyconnection
+
+# The GitHub Actions workflow deploys automatically on push to main
+
+ PORT env var to a different portALLOWED_ORIGINS to include your client origin${s.desc}
The complete Heady Latent OS service mesh
+The page you're looking for doesn't exist.
+ Back to Home +