Synaplan
기업을 위한 오픈소스 AI 플랫폼
Tidetime은 단일 회사를 위한 오픈소스 자체 호스팅 일정 관리 서비스
Tidetime is open-source, self-hosted appointment scheduling for a single company: services, providers, booking pages, calendar conflict checks, meeting links, and email. Deploy it with Docker.
비즈니스TypeScript · ShellGitHub @Sulaiman-Dauda온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Open-source, self-hosted appointment scheduling for a single company: services, providers, booking pages, calendar conflict checks, and email. Deploy with Docker.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Self-hosted appointment scheduling for a single company with multiple services and multiple providers. Customers pick a service, choose a provider or let the system assign one, and book an open slot. Your team manages availability, bookings, and customers from one dashboard.
Tidetime is open source and runs on your own server. There is no hosted plan, no per-seat pricing, and no third-party analytics.
You need Node.js 20 or newer and a PostgreSQL database. docker compose up -d starts one locally.
git clone https://github.com/Sulaiman-Dauda/Tidetime.git tidetime
cd tidetime
cp .env.example .env
The example file is set up for production, so edit .env before going on. Delete the NODE_ENV=production line, set APP_URL=http://localhost:3100, and set DATABASE_URL=postgres://postgres:postgres@localhost:5432/tidetime (the database docker compose up -d starts). The secrets can stay empty in development.
npm ci
npm run db:migrate
npm run dev
Open http://localhost:3100/setup to create the company and its owner account. From there, invite teammates under Members and assign them to services as providers under Services.
To try a demo company instead, skip /setup and seed the empty database. It creates a sample service with two providers, and you sign in as [email protected] with the password password123. Do not run both: the seed adds its own company, and setup is closed once users exist.
npm run db:seed
Copy .env.example to .env and fill in the values. The essentials:
| Variable | Required | Purpose |
|---|---|---|
APP_URL | Yes | Public URL of the instance, used in links and emails. |
APP_NAME | No | Product name used in browser titles, in emails, and in authenticator apps. The company name set in Settings does not replace it there. Defaults to Tidetime. |
DATABASE_URL | Yes | PostgreSQL connection string. |
AUTH_SECRET | Yes | Random value of at least 32 characters. Encrypts stored credentials and two-factor secrets, and signs OAuth state, RSVP links and spam-check tokens. Sessions do not depend on it. |
CRON_SECRET | Yes | Random value of at least 32 characters. Protects the background jobs endpoint. |
POSTGRES_PASSWORD | Prod | Password for the bundled PostgreSQL container in the production Compose file. |
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET | No | Enable Google Calendar and Google Meet. |
Generate a secret with openssl rand -base64 32. SMTP and Microsoft 365 email are set up in the dashboard after the app is running, not in the environment file.
In production the app validates its configuration on boot and refuses to start with a missing or weak secret.
On a fresh Linux server (root or sudo), one command installs everything (Docker, secrets, firewall, the stack) and prints the address when it is live:
curl -fsSL https://raw.githubusercontent.com/Sulaiman-Dauda/Tidetime/main/install.sh | bash
Prefer to do it by hand? The production Compose file runs PostgreSQL, the standalone Next.js server, a background jobs worker, and Caddy:
cp .env.example .env
# Fill APP_URL, POSTGRES_PASSWORD, AUTH_SECRET, and CRON_SECRET.
# Compose builds DATABASE_URL itself from POSTGRES_PASSWORD.
docker compose -f docker-compose.prod.yml up -d --build
This builds the image from source. To run the published image instead, which also updates the same way as an installer setup, add TIDETIME_IMAGE=ghcr.io/sulaiman-dauda/tidetime:latest to .env and start with docker compose -f docker-compose.prod.yml pull followed by docker compose -f docker-compose.prod.yml up -d.
The app container applies database migrations before it starts. The jobs worker calls the protected cron endpoint on an interval to handle webhook retries and data retention. The application port stays bound to localhost so all remote traffic passes through Caddy, so the instance is reached at http://<your-server-ip> (or https://<your-domain> once a domain is attached).
For domain setup, backups, Microsoft 365 email, and upgrade notes, see docs/DEPLOYMENT.md.
Team members are managed under Members, each with one of four roles:
A provider is a member assigned to a service. These boundaries are enforced in the server queries and mutations, not only in the interface.
Google Calendar and Meet. Google needs the instance on a custom domain with HTTPS, because it rejects plain-HTTP and IP-address redirect URIs. Once the domain is live (Settings, Domain), create Web application OAuth credentials in Google Cloud with the redirect URI https://<your-domain>/api/google-calendar/callback, add the client ID and secret to your environment, and restart. Providers then connect their own calendars from the dashboard.
Microsoft 365. Register an app in Microsoft Entra and connect it from Dashboard, Connections. The same registration covers both mailbox sending and calendar conflict checks. Full steps are in the deployment notes.
Zapier and generic webhooks. Add a Catch Hook URL under Dashboard, Connections, Zapier webhooks and pick which events to send. Each delivery includes:
Content-Type: application/jsonX-Tidetime-Signature-256: sha256=<HMAC>{ triggerEvent, createdAt, payload }Each webhook gets a random signing secret when you add it. The dashboard does not show it yet; read it from the secret column of the webhooks table to verify the signature.
Targets must be publicly routable HTTP or HTTPS URLs, redirects are not followed, requests time out after ten seconds, and failed deliveries retry with backoff.
npm run dev # start the dev server on port 3100
npm run check # lint, type-check, unit tests, and a production build
npm run test # unit tests only
npm run test:e2e # end-to-end tests (Playwright)
npm run db:studio # browse the database with Drizzle Studio
To reset a local database to a clean state:
npm run db:reset -- --confirm <database_name>
npm run db:migrate
npm run db:seed
The reset command refuses to run in production mode, against remote hosts, or without a matching database name.
Issues and pull requests are welcome. Please run npm run check before opening a pull request, and see CONTRIBUTING.md and CODE_OF_CONDUCT.md. Security reports go through SECURITY.md.
Released under the MIT License.