{"id":48676139,"url":"https://github.com/gorkem-bwl/atlas","last_synced_at":"2026-05-21T06:08:20.010Z","repository":{"id":348011483,"uuid":"1165648568","full_name":"gorkem-bwl/atlas","owner":"gorkem-bwl","description":"Self-hosted business platform with CRM, HRM, invoices, projects, contracts, documentation, task management, spreadsheets, file storage, and drawing tools. Alternative to Zoho and Odoo.","archived":false,"fork":false,"pushed_at":"2026-04-22T01:12:41.000Z","size":28236,"stargazers_count":65,"open_issues_count":0,"forks_count":16,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-22T03:03:44.234Z","etag":null,"topics":["analytics","business","crm","documentation-tool","drive","file","file-manager","hrm"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gorkem-bwl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-24T11:49:36.000Z","updated_at":"2026-04-22T01:12:44.000Z","dependencies_parsed_at":null,"dependency_job_id":"0b3b3cfb-e536-4e7d-af85-4522cd707bc4","html_url":"https://github.com/gorkem-bwl/atlas","commit_stats":null,"previous_names":["bluewave-labs/atlas","gorkem-bwl/atlas"],"tags_count":44,"template":false,"template_full_name":null,"purl":"pkg:github/gorkem-bwl/atlas","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gorkem-bwl%2Fatlas","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gorkem-bwl%2Fatlas/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gorkem-bwl%2Fatlas/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gorkem-bwl%2Fatlas/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gorkem-bwl","download_url":"https://codeload.github.com/gorkem-bwl/atlas/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gorkem-bwl%2Fatlas/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32274987,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-25T18:29:39.964Z","status":"ssl_error","status_checked_at":"2026-04-25T18:29:32.149Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["analytics","business","crm","documentation-tool","drive","file","file-manager","hrm"],"created_at":"2026-04-10T15:14:38.276Z","updated_at":"2026-05-21T06:08:20.005Z","avatar_url":"https://github.com/gorkem-bwl.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n   \u003cimg width=\"350\" height=\"330\" alt=\"image\" src=\"https://github.com/user-attachments/assets/a9c1bd4b-1538-4378-81bd-a883175ac309\" /\u003e\n\u003c/p\u003e\n\n\nA self-hosted business platform that brings CRM, HRM, invoicing, agreements, documents, projects \u0026 tasks, file storage, and whiteboards into one connected workspace for your team. An open alternative to [Zoho](https://zoho.com/) and [Odoo](https://www.odoo.com/).\n\n**Live demo:** [app.dodoapps.net](https://app.dodoapps.net) · **Docker image:** [`ghcr.io/gorkem-bwl/atlas`](https://github.com/gorkem-bwl/atlas/pkgs/container/atlas) (multi-arch amd64 + arm64) · **Releases:** [github.com/gorkem-bwl/atlas/releases](https://github.com/gorkem-bwl/atlas/releases)\n\n\n\nhttps://github.com/user-attachments/assets/8baaa7d3-4d8e-45ba-b769-73b3feabd58a\n\n\n\n\n## Quick start (Docker)\n\n**macOS / Linux:**\n```bash\ngit clone https://github.com/gorkem-bwl/atlas.git\ncd atlas\nchmod +x setup.sh\n./setup.sh\n```\n\n**Windows (PowerShell):**\n```powershell\ngit clone https://github.com/gorkem-bwl/atlas.git\ncd atlas\npowershell -ExecutionPolicy Bypass -File setup.ps1\n```\n\nThis will:\n1. Generate secure secrets automatically\n2. Start PostgreSQL, Redis, and Atlas via Docker\n3. Wait for the service to be healthy\n\nThen open **http://localhost:3001** and create your admin account.\n\n## Manual Docker setup\n\n```bash\ngit clone https://github.com/gorkem-bwl/atlas.git\ncd atlas\ndocker compose -f docker-compose.production.yml up -d\n```\n\nOpen **http://localhost:3001** and create your admin account. Secrets are auto-generated on first run.\n\nTo pin a specific version: `IMAGE_TAG=\u003cversion\u003e docker compose -f docker-compose.production.yml up -d` — see the [latest release](https://github.com/gorkem-bwl/atlas/releases/latest) for the current tag.\n\n## HTTPS with Caddy (optional)\n\n```bash\n# 1. Set your domain in .env\necho 'ATLAS_DOMAIN=atlas.yourdomain.com' \u003e\u003e .env\n\n# 2. Point your domain's DNS A record to your server's IP\n\n# 3. Start with HTTPS\ndocker compose -f docker-compose.production.yml -f docker-compose.https.yml up -d\n```\n\nCaddy automatically obtains and renews Let's Encrypt SSL certificates. Ports 80 and 443 must be open.\n\n## Development setup\n\n```bash\n# 1. Start PostgreSQL and Redis\ndocker compose up -d\n\n# 2. Install dependencies\nnpm install\n\n# 3. Create environment file\ncp .env.example .env\n\n# 4. Update .env for local development:\n#    - DATABASE_URL=postgresql://postgres:postgres@localhost:5432/atlas\n#    - CLIENT_PUBLIC_URL=http://localhost:5180\n#    - CORS_ORIGINS=http://localhost:5180,http://localhost:3001\n#    The JWT secrets in .env.example are placeholders — generate real ones:\n#      openssl rand -hex 32  → paste into JWT_SECRET\n#      openssl rand -hex 32  → paste into JWT_REFRESH_SECRET\n#      openssl rand -hex 32  → paste into TOKEN_ENCRYPTION_KEY\n\n# 5. Start dev servers\nnpm run dev\n```\n\n- Client: http://localhost:5180\n- Server: http://localhost:3001\n- On first visit, you'll be prompted to create an admin account.\n\n## API documentation\n\nAtlas exposes an OpenAPI 3.1 specification and an interactive reference UI:\n\n- **Raw spec:** `http://localhost:3001/api/v1/openapi.json`\n- **Interactive reference** (Scalar): `http://localhost:3001/api/v1/reference`\n\nThe spec is generated from Zod schemas in `packages/server/src/openapi/paths/`. When a route adopts `defineRoute()`, the same schema drives both the OpenAPI registration and runtime request validation — so documentation and wire contract cannot drift.\n\nOn a self-hosted deployment, replace `localhost:3001` with your Atlas domain.\n\n## Apps\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"50%\"\u003e\n      \u003cimg src=\"docs/screenshots/crm.png\" alt=\"CRM\" /\u003e\u003cbr/\u003e\n      \u003cb\u003eCRM\u003c/b\u003e — Pipeline, contacts, companies, deals, leads, forecasting, saved views, web-to-lead forms\n    \u003c/td\u003e\n    \u003ctd width=\"50%\"\u003e\n      \u003cimg src=\"docs/screenshots/hr.png\" alt=\"HR\" /\u003e\u003cbr/\u003e\n      \u003cb\u003eHRM\u003c/b\u003e — Employees, departments, org chart, leave management, attendance\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      \u003cimg src=\"docs/screenshots/projects.png\" alt=\"Work\" /\u003e\u003cbr/\u003e\n      \u003cb\u003eWork\u003c/b\u003e — Projects, tasks, time tracking, billing, reports, budgets\n    \u003c/td\u003e\n    \u003ctd\u003e\n      \u003cimg src=\"docs/screenshots/calendar.png\" alt=\"Calendar\" /\u003e\u003cbr/\u003e\n      \u003cb\u003eCalendar\u003c/b\u003e — Month/week/day/year/agenda views with Google Calendar sync\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      \u003cimg src=\"docs/screenshots/invoices.png\" alt=\"Invoices\" /\u003e\u003cbr/\u003e\n      \u003cb\u003eInvoices\u003c/b\u003e — Invoice creation, recurring billing, templates, payment tracking\n    \u003c/td\u003e\n    \u003ctd\u003e\n      \u003cimg src=\"docs/screenshots/sign.png\" alt=\"Agreements\" /\u003e\u003cbr/\u003e\n      \u003cb\u003eAgreements\u003c/b\u003e — PDF contracts with e-signatures, templates, counterparty linking, sequential signing, audit trail, reminders\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      \u003cimg src=\"docs/screenshots/drive.png\" alt=\"Drive\" /\u003e\u003cbr/\u003e\n      \u003cb\u003eDrive\u003c/b\u003e — File storage with versioning, sharing, comments, activity log, password-protected links\n    \u003c/td\u003e\n    \u003ctd\u003e\n      \u003cimg src=\"docs/screenshots/write.png\" alt=\"Write\" /\u003e\u003cbr/\u003e\n      \u003cb\u003eWrite\u003c/b\u003e — Rich text editor with cover images, comments, templates\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      \u003cimg src=\"docs/screenshots/system.png\" alt=\"System\" /\u003e\u003cbr/\u003e\n      \u003cb\u003eSystem\u003c/b\u003e — CPU/memory/disk monitoring, email settings, role-based app permissions\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\nAtlas also includes **Draw** — an Excalidraw-based canvas with PDF export, image insertion, and presentation mode.\n\n**Data import.** Bring your CRM data with you. Atlas ships with an Odoo importer (Settings → Data import) that ingests `res.partner`, `crm.lead`, and CRM activity CSV exports — mapping companies, contacts, leads, deals, and activities into your tenant in one pass, with per-row validation and a skipped-row report. HubSpot is on the way.\n\n\n## Tech stack\n\n- **Frontend**: React, TypeScript, Vite, TanStack Query, Zustand\n- **Backend**: Express, TypeScript, Drizzle ORM, PostgreSQL\n- **Infrastructure**: Docker, Redis, BullMQ\n\n## Environment variables\n\nAtlas boots with a small set of **required** secrets. Everything else is optional and only enables specific features — see the *What needs what* table below.\n\n### Required (Atlas will not start without these)\n\n| Variable | Description |\n|----------|-------------|\n| `JWT_SECRET` | JWT signing key. Min 32 chars. Generate: `openssl rand -hex 32` |\n| `JWT_REFRESH_SECRET` | Refresh-token signing key. Min 32 chars. Generate: `openssl rand -hex 32` |\n| `TOKEN_ENCRYPTION_KEY` | 64-char hex string used to encrypt Google OAuth tokens at rest. Generate: `openssl rand -hex 32` |\n\n\u003e The Docker `setup.sh` / `setup.ps1` scripts generate all three for you on first run. If you use `docker-compose.production.yml` directly, the compose file auto-generates them as well. You only need to set them manually when running Atlas outside Docker (e.g. development, or a custom deploy).\n\n### Networking \u0026 database (defaults work for most setups)\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `DATABASE_URL` | `postgresql://postgres:postgres@localhost:5432/atlas` | PostgreSQL connection string |\n| `POSTGRES_PASSWORD` | `atlas` | Postgres password when using the bundled Docker compose |\n| `REDIS_URL` | *(unset)* | Redis connection. Required **only** for the Google sync background worker; everything else runs without Redis. |\n| `PORT` | `3001` | Server port |\n| `SERVER_PUBLIC_URL` | `http://localhost:3001` | Publicly reachable URL of the Atlas API (used in invitation / password-reset links, and as the default OAuth redirect host) |\n| `CLIENT_PUBLIC_URL` | `http://localhost:5180` in dev, same as `SERVER_PUBLIC_URL` in production | Publicly reachable URL of the Atlas web app |\n| `CORS_ORIGINS` | *(derived from `CLIENT_PUBLIC_URL`)* | Comma-separated origins allowed to call the API |\n| `DISABLE_PUBLIC_SIGNUP` | `true` | Public self-registration is **off by default** on every self-hosted instance. The first-run setup flow and tenant invitations always work. Set `DISABLE_PUBLIC_SIGNUP=false` only if you're running Atlas as an open SaaS where anyone can create their own workspace. |\n\n### Optional integrations\n\n| Variable | Default | Needed for |\n|----------|---------|-----------|\n| `SMTP_HOST` | — | Outgoing email (see [SMTP setup](#smtp-setup-optional)) |\n| `SMTP_PORT` | `587` | SMTP port |\n| `SMTP_USER` | — | SMTP auth user |\n| `SMTP_PASS` | — | SMTP auth password |\n| `SMTP_FROM` | `Atlas \u003cnoreply@atlas.so\u003e` | From-address used on outgoing mail. Change this to match your domain. |\n| `GOOGLE_CLIENT_ID` | — | Google OAuth (Calendar / Gmail / Drive per-user sync — see [Google integration](#google-integration-optional)) |\n| `GOOGLE_CLIENT_SECRET` | — | Google OAuth secret |\n| `GOOGLE_REDIRECT_URI` | `{SERVER_PUBLIC_URL}/api/v1/auth/google/callback` | Override the OAuth redirect URL if the server sits behind a proxy with a different hostname |\n\n### What needs what\n\nAtlas is designed so you only pay for the integrations you want. If you skip the optional variables above, the affected features silently become unavailable — the rest of the app keeps working.\n\n| Feature | Requires |\n|---------|----------|\n| CRM, HRM, Work (projects + tasks), Invoices, Agreements, Drive (Atlas-native), Write, Draw, Calendar (local events) | **Nothing extra.** Runs on Postgres alone. |\n| Password-reset emails | SMTP |\n| Team-member invitation emails | SMTP |\n| Sign / agreement reminder emails | SMTP |\n| CRM outbound email to contacts | SMTP (+ Google for per-user Gmail tracking) |\n| Calendar sync with Google Calendar | Google OAuth (per user) |\n| Gmail read/send inside CRM | Google OAuth (per user) |\n| Google Drive file import/export inside Drive app | Google OAuth (per user) |\n| Background Google sync worker (non-blocking) | Redis + Google OAuth |\n\nIf you plan to run Atlas as a closed team tool with no email needs, you can skip SMTP and Google entirely. Users just won't receive emails (invitations have to be shared as links manually) and `/calendar`, `/crm`, `/drive` will work locally without Google sync.\n\n## SMTP setup (optional)\n\nAtlas **sends** email (it never receives). SMTP is used for:\n\n- Password reset links\n- Team-member invitations (`POST /auth/invitation`)\n- Agreement reminders (hourly scheduler, Sign app)\n- CRM outbound messages from the CRM email composer\n- The \"Send test email\" button in **Settings → System**\n\nIf `SMTP_HOST` is not set, all of the above are logged and skipped — no errors, features that depend on them just can't deliver.\n\n### Common providers\n\n```env\n# Gmail (requires an App Password, not your regular password — enable 2FA first)\nSMTP_HOST=smtp.gmail.com\nSMTP_PORT=587\nSMTP_USER=you@yourdomain.com\nSMTP_PASS=your-16-char-app-password\nSMTP_FROM=Atlas \u003cyou@yourdomain.com\u003e\n\n# SendGrid\nSMTP_HOST=smtp.sendgrid.net\nSMTP_PORT=587\nSMTP_USER=apikey\nSMTP_PASS=SG.your-api-key\nSMTP_FROM=Atlas \u003cnoreply@yourdomain.com\u003e\n\n# Resend\nSMTP_HOST=smtp.resend.com\nSMTP_PORT=587\nSMTP_USER=resend\nSMTP_PASS=re_your-api-key\nSMTP_FROM=Atlas \u003cnoreply@yourdomain.com\u003e\n\n# Postmark\nSMTP_HOST=smtp.postmarkapp.com\nSMTP_PORT=587\nSMTP_USER=\u003cserver-token\u003e\nSMTP_PASS=\u003cserver-token\u003e\nSMTP_FROM=Atlas \u003cnoreply@yourdomain.com\u003e\n```\n\nAfter editing `.env`, restart Atlas and click **Settings → System → Send test email** to verify delivery.\n\n## Google integration (optional)\n\nAtlas uses Google OAuth on a **per-user** basis. Each user clicks *Connect Google* in their own **Settings** to grant access — the admin only has to provide the OAuth client ID/secret once. Without Google set up, `/calendar` still works (events live in Postgres), CRM email features are hidden, and Drive works for Atlas-native files only.\n\n### 1. Create an OAuth client\n\n1. Open [Google Cloud Console](https://console.cloud.google.com) and create or select a project.\n2. **APIs \u0026 Services → Library** — enable:\n   - Gmail API\n   - Google Calendar API\n   - Google Drive API\n3. **APIs \u0026 Services → OAuth consent screen** — configure:\n   - User type: *External* (unless you're on Google Workspace, in which case *Internal* is simpler).\n   - App name, support email, developer contact.\n   - While in *Testing* status you can only authenticate accounts listed under **Test users**. For a single-company deployment that's often enough. If you want anyone in your org (or the public) to be able to connect, click **Publish app** — note that the sensitive scopes (`gmail.readonly`, `gmail.send`) require [Google verification](https://support.google.com/cloud/answer/9110914) before the app leaves *In production* warning state.\n4. **APIs \u0026 Services → Credentials → Create credentials → OAuth 2.0 Client ID**:\n   - Application type: *Web application*.\n   - Authorized redirect URI: `https://your-atlas-domain/api/v1/auth/google/callback` (use `http://localhost:3001/api/v1/auth/google/callback` for local dev).\n\n### 2. Add to `.env`\n\n```env\nGOOGLE_CLIENT_ID=xxxxxxxxxx.apps.googleusercontent.com\nGOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxxxxxxxxx\n# Optional — only needed if the server's public URL differs from the OAuth redirect host\n# GOOGLE_REDIRECT_URI=https://your-atlas-domain/api/v1/auth/google/callback\n```\n\nRestart Atlas. The **Connect Google** option appears in **Settings → Integrations** for each user.\n\n### Scopes that Atlas requests\n\nOn the initial connection:\n\n- `https://www.googleapis.com/auth/gmail.readonly`\n- `https://www.googleapis.com/auth/gmail.send`\n- `https://www.googleapis.com/auth/calendar.readonly`\n- `https://www.googleapis.com/auth/calendar.events`\n\nDrive scopes are requested incrementally only when the user first opens the Drive integration, so users who never touch Drive don't grant those:\n\n- `https://www.googleapis.com/auth/drive.readonly`\n- `https://www.googleapis.com/auth/drive.file`\n\nTokens are encrypted at rest with `TOKEN_ENCRYPTION_KEY` before being written to Postgres.\n\n### Background sync (optional)\n\nIf `REDIS_URL` is also set, Atlas enables a BullMQ worker that keeps user Gmail/Calendar in sync outside the request path (periodic pull, webhook delivery). Without Redis, sync happens on-demand when users open the CRM or Calendar views — still functional, just not ambient.\n\n## Troubleshooting\n\n**\"network ... not found\" error**\n\n```bash\ndocker compose -f docker-compose.production.yml down\ndocker compose -f docker-compose.production.yml up -d\n```\n\n**Port 3001 already in use**\n\nStop the process using port 3001, or set a different port in `.env`:\n```\nPORT=3002\n```\n\n**Update to latest version**\n\n```bash\ndocker compose -f docker-compose.production.yml pull\ndocker compose -f docker-compose.production.yml up -d\n```\n\n**Reset everything (fresh start)**\n\n```bash\ndocker compose -f docker-compose.production.yml down -v\ndocker compose -f docker-compose.production.yml up -d\n```\n\n## System requirements\n\n### Minimum\n\n- 2 GB RAM + 4 GB swap (or 4 GB RAM)\n- 1 vCPU\n- 10 GB disk\n- Docker 20+ with Compose plugin\n\n### Recommended\n\n- 4 GB RAM\n- 2 vCPU\n- 20 GB disk\n\n### Supported platforms\n\n| Platform | Architecture | Status |\n|----------|-------------|--------|\n| Ubuntu / Debian / CentOS | x86_64 (amd64) | Full support |\n| AWS EC2, DigitalOcean, Hetzner, Linode | amd64 | Full support |\n| AWS Graviton, Oracle Cloud Ampere | arm64 | Full support |\n| Apple Silicon Mac (M1–M4) | arm64 | Full support |\n| Raspberry Pi 5 (8 GB) | arm64 | Supported (slower builds) |\n| Raspberry Pi 4 (8 GB) | arm64 | Supported (needs swap, slow builds) |\n| Windows (WSL2 + Docker Desktop) | amd64 | Supported |\n\n### Not supported\n\n| Platform | Reason |\n|----------|--------|\n| Raspberry Pi 3 / Zero / Zero 2 W | 32-bit ARM — Node 20 requires arm64 |\n| Machines with \u003c 2 GB RAM and no swap | Build and runtime will OOM |\n| 32-bit x86 (i386) | Docker images are 64-bit only |\n\n\u003e **Tip:** On 2 GB machines, add swap before building:\n\u003e ```bash\n\u003e sudo fallocate -l 4G /swapfile \u0026\u0026 sudo chmod 600 /swapfile\n\u003e sudo mkswap /swapfile \u0026\u0026 sudo swapon /swapfile\n\u003e echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab\n\u003e ```\n\n## License\n\n[GNU Affero General Public License v3.0](LICENSE) — free to use, modify, and distribute. If you run a modified version as a network service, you must make the source available to users.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgorkem-bwl%2Fatlas","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgorkem-bwl%2Fatlas","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgorkem-bwl%2Fatlas/lists"}