-
Notifications
You must be signed in to change notification settings - Fork 990
Expand file tree
/
Copy path.env.example
More file actions
205 lines (172 loc) · 9.78 KB
/
Copy path.env.example
File metadata and controls
205 lines (172 loc) · 9.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# Postgres
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/crm?schema=public"
# A direct, unpooled connection to that same database, used by
# `prisma migrate deploy` when the API is built on Vercel. Set it only if
# DATABASE_URL points at a pooler; POSTGRES_URL_NON_POOLING is read as a
# fallback. Locally there is nothing to set.
# DIRECT_DATABASE_URL=""
# A throwaway database for `bun run test`. The suite will not touch DATABASE_URL
# and refuses to run without this — these are real integration tests, they write
# and delete rows, and the pre-push hook runs them. The name has to end in
# `_test`. `bun run db:test` creates it and applies the migrations.
TEST_DATABASE_URL="postgresql://postgres:postgres@localhost:5432/crm_test?schema=public"
# Generate your own: openssl rand -base64 32
BETTER_AUTH_SECRET=""
# Who is allowed to sign in — this is the entire authorisation model, so it has
# no default. Comma-separated, and each entry is either a whole email domain or
# a single address:
#
# ALLOWED_SIGN_IN="acme.com" everyone at your company
# ALLOWED_SIGN_IN="acme.com,contractor@gmail.com" …plus one outsider
# ALLOWED_SIGN_IN="you@gmail.com" a one-person install
#
# Subdomains count, so "acme.com" also admits "you@mail.acme.com".
ALLOWED_SIGN_IN=""
# Google is the sign-in method a clone starts with, and the same client is what
# reads Gmail and Calendar. Set both or neither — half a pair is a sign-in
# button that fails at Google.
#
# Leave them empty only if you sign in with Microsoft below, or with your own
# identity provider added on Settings → SSO. With none of the three there is no
# way in at all, and the sign-in page says as much rather than showing you
# nothing.
GOOGLE_CLIENT_ID=""
GOOGLE_CLIENT_SECRET=""
# Microsoft 365 / Entra ID — the other sign-in method, and the same app
# registration is what reads Outlook mail. Set both or neither, exactly like
# the Google pair.
#
# Create the app at https://portal.azure.com → Microsoft Entra ID → App
# registrations, add the redirect URI <API_URL>/api/auth/callback/microsoft,
# and give it the delegated Graph permissions User.Read and Mail.Read. The
# README has the full walkthrough.
#
# You can set Google and Microsoft together: the sign-in page offers both, and
# a rep's mail is read from whichever they signed in with.
# MICROSOFT_CLIENT_ID=""
# MICROSOFT_CLIENT_SECRET=""
# Optional. Enables Slack account linking on Settings > Connections.
# Add APP_URL + /api/auth/oauth2/callback/slack as the Slack OAuth redirect URL.
# SLACK_CLIENT_ID=""
# SLACK_CLIENT_SECRET=""
# Which Entra tenant may sign in. "common" (the default) accepts any work,
# school or personal Microsoft account and leans on ALLOWED_SIGN_IN to decide
# who actually gets in; your own tenant's GUID refuses everyone else at
# Microsoft, before they ever reach us. "organizations" allows any work or
# school account but no personal ones.
# MICROSOFT_TENANT_ID="common"
# Serve the landing page at "/". It markets *this* product, so it is off unless
# you say otherwise: on an install of your own, a stranger arriving at the root
# is sent to /sign-in instead. The only value that turns it on is "true".
# IS_MARKETING="true"
# ── Where things are ─────────────────────────────────────────────────────────
# Only needed when you deploy. The defaults below are the localhost ones.
# The API. Also the origin that mints session cookies and serves /api/auth/*.
# API_URL="http://localhost:3001"
# The web app. Comma-separate if it is served from more than one origin —
# the first is canonical, and the rest are simply allowed to call the API.
# APP_URL="http://localhost:3000"
# Only when the API and the app are on different subdomains of one parent,
# e.g. api.example.com and app.example.com — then set ".example.com" so one
# session cookie covers both.
# AUTH_COOKIE_DOMAIN=""
# The research agent, which is its own deployment. The API reads this too, to
# tell the agent a logo or a photograph is waiting rather than letting it find
# out on its next minute.
# AGENT_URL="http://127.0.0.1:2000"
# Port used by the self-hosted Eve service. Hosted runtimes can keep injecting
# their standard PORT variable instead.
# AGENT_PORT="2000"
# Lets a signed-in rep talk to the agent from the contact sheet.
#
# The browser never calls the agent directly. The app proxies /eve/v1/* on its
# own origin, checks the session, and mints a two-minute token signed with this
# secret; the agent verifies it and learns *which rep* is asking. Set the same
# value for both processes. openssl rand -base64 32
#
# It also authorises two calls the API makes to the agent: the dispatch poke,
# which is what makes a new company's logo appear as it is added instead of on
# the next minute's tick, and the check that a Context API key is real before
# it is saved.
#
# Leave it unset and the Agent tab reports that it is not configured, the poke
# is skipped rather than sent unauthenticated, and a Context key is saved
# without being checked. Nothing else changes: the agent still runs on its own
# schedule.
# AGENT_BRIDGE_SECRET=""
# PORT="3001"
# ── Optional: what the agent can do ──────────────────────────────────────────
# The research agent works with none of these — it falls back to what the CRM
# already knows (your own email and calendar history) and simply reports what
# it could not check. Each key you add unlocks one more place it can look, and
# it tells you at startup which ones are on.
# Perplexity — finds where a person lives on the web, and recent news worth
# knowing before a call. https://perplexity.ai/settings/api
# PERPLEXITY_API_KEY=""
# LinkDAPI via RapidAPI — LinkedIn profiles: name, title, employer, tenure.
# https://rapidapi.com/linkdapi/api/linkdapi-best-unofficial-linkedin-api
# RAPIDAPI_KEY=""
# GitHub — raises the rate limit when matching contacts to GitHub profiles.
# Any classic token with no scopes will do.
# GITHUB_TOKEN=""
# Vercel Blob — where every logo and profile picture in the CRM is kept.
#
# The URLs these arrive on are somebody else's: LinkedIn signs theirs with an
# expiry a few weeks out, a brand CDN is a rate limit on a page that draws forty
# logos, and a company's own favicon is served by a company with no idea we are
# drawing it. So the bytes are copied once and the record points at our copy.
#
# Read by the agent, by the API — which writes a favicon and a signed-in user's
# Google avatar — and by the seed. Not by the Next.js app, which only needs to
# recognise one of our URLs to route it through the image optimizer.
#
# Without it, a contact's photograph is not stored at all, because a URL that
# works today and 404s next month is worse than initials and nobody can tell
# which it will be. Everything else — logos, favicons, avatars — keeps the
# origin's URL and renders as an ordinary hotlinked image.
# BLOB_READ_WRITE_TOKEN=""
# The model the agent runs on is reached through the Vercel AI Gateway. On
# Vercel this is handled by OIDC and needs nothing; elsewhere, set a key.
# Which model is a setting, not a variable — change it on the settings page.
# https://vercel.com/docs/ai-gateway
# AI_GATEWAY_API_KEY=""
# ── Optional: operations ─────────────────────────────────────────────────────
# Shared cache. Without it each instance caches in its own memory, which is
# correct — just not shared. Recommended in production once website tracking is
# on: the compiled tracking config, the collector's rate limit and the hourly
# cap on contacts created from forms are all counted here, and per-instance
# counters let a multi-instance deployment exceed both.
# REDIS_URL="redis://localhost:6379"
# CACHE_TTL_MS="60000"
# Bearer token guarding POST /internal/sync/google, the Gmail/Calendar cron
# route, and POST /internal/tracking/retention, the nightly sweep that deletes
# tracked page views older than 90 days. Both refuse to run without it. At
# least 16 characters.
# CRON_SECRET=""
# Log every SQL statement Prisma runs, at debug level, without bound
# parameters. Off by default: it buries every other line under a wall of
# SELECTs.
# PRISMA_LOG_QUERIES="true"
# ── Anonymous usage telemetry ────────────────────────────────────────────────
# This repo is MIT and cloned rather than installed, so there is no download
# count and no runtime signal. Once a day the API sends one event of counts —
# how many contacts exist in bands rather than exactly, which of the agent's
# tools were called, how the evidence ledger behaved, which optional keys are
# set as booleans — tied to a random UUID generated by the first migration.
#
# It is server-side only. There is no posthog-js anywhere, no autocapture and
# no session replay, because autocapture on a CRM would lift contact names and
# deal amounts out of your database. No name, address, company, subject line,
# amount, prompt or key is ever sent, and neither is your IP: every event
# carries $ip: null with geoip off.
#
# docs/telemetry.md names every event and every property that is sent, and
# lists what never is.
# Turn it off. "1" is the whole interface, and DO_NOT_TRACK=1 does the same.
# When either is set no client is created, so nothing can be sent later.
#
# There is no variable for where it goes: the project key and host are written
# into packages/telemetry, because a write-only key is not a secret and a
# variable would only suggest it were one. Change them there if you want the
# numbers in your own project.
# CRM_TELEMETRY_DISABLED="1"