Developer Guide

Running WindoM locally

Option A - Extension Only Recommended to start#

This gets the extension running in Chrome with no backend needed. Clock, weather, todos, backgrounds, quotes, quick links, and the focus timer all work out of the box. Google Calendar and Spotify require the full stack setup below.

Prerequisites#

Steps#

1

Clone the repository.

git clone https://github.com/YehudaBriskman/WindoM.git cd WindoM
2

Install dependencies for the extension.

cd web npm install
3

Build the extension.

npm run build

This creates a web/dist/ folder - that is your built extension.

4

Load the extension in Chrome.

  1. Open Chrome and go to chrome://extensions
  2. Enable Developer mode (toggle in the top right)
  3. Click Load unpacked
  4. Select the web/dist folder
5

Open a new tab. WindoM should appear.

Dev mode with hot reload - run npm run dev instead of build, then load the web/ project root folder (not dist/) as the unpacked extension at chrome://extensions. Changes reload automatically via HMR.

Option B - Full Stack Optional#

Required if you want Google Calendar sync or Spotify integration. This runs a local backend with a Postgres database using Docker.

Prerequisites#

  • Everything from Option A
  • Docker Desktop
  • A Google Cloud project with OAuth credentials (for Calendar)
  • A Spotify Developer app (for Spotify)

Steps#

1

Copy the example environment file.

cp backend/.env.example backend/.env

Then open backend/.env and fill in the values. See the Environment Reference below for what each one means.

2

Generate secure secrets for JWT and token encryption.

node -e "const c=require('crypto'); console.log('JWT_ACCESS_SECRET='+c.randomBytes(32).toString('base64')); console.log('REFRESH_TOKEN_SECRET='+c.randomBytes(32).toString('base64')); console.log('TOKEN_ENC_KEY_BASE64='+c.randomBytes(32).toString('base64'));"

Copy the output into your .env file.

3

Start the backend and database with Docker.

docker-compose up --build

The API will be running at http://localhost:8080. The database runs at port 5433.

4

Build the extension pointing at your local backend.

cd web npm install npm run build

The default backend URL is already http://localhost:8080 so no changes are needed.

5

Load web/dist as an unpacked extension in Chrome (same as Option A, step 4).

OAuth redirect URIs - add these to your OAuth app consoles before testing:
  • Google Cloud Console → Authorized redirect URIs:
    http://localhost:8080/auth/google/callback
    http://localhost:8080/oauth/google/callback
  • Spotify Developer Dashboard → Redirect URIs:
    http://localhost:8080/oauth/spotify/callback

Environment Reference#

All variables go in backend/.env. The ones marked optional are only needed for specific features.

VariableDescriptionRequired
PORTPort the backend listens on. Default: 8080No
DATABASE_URLPostgres connection string. When using Docker Compose this is set automatically.Yes
JWT_ACCESS_SECRETRandom secret used to sign access tokens. Generate with openssl rand -base64 32Yes
REFRESH_TOKEN_SECRETRandom secret used to sign refresh tokens. Generate separately from the above.Yes
TOKEN_ENC_KEY_BASE6432 random bytes base64-encoded. Used to encrypt OAuth tokens at rest.Yes
GOOGLE_CLIENT_IDOAuth 2.0 Client ID from Google Cloud Console.For Google features
GOOGLE_CLIENT_SECRETOAuth 2.0 Client Secret from Google Cloud Console.For Google features
GOOGLE_REDIRECT_URICallback URL for Google Sign-in. Example: http://localhost:8080/auth/google/callbackFor Google features
GOOGLE_OAUTH_REDIRECT_URICallback URL for Google Calendar OAuth. Example: http://localhost:8080/oauth/google/callbackFor Calendar
SPOTIFY_CLIENT_IDClient ID from your Spotify Developer app.For Spotify
SPOTIFY_CLIENT_SECRETClient Secret from your Spotify Developer app.For Spotify
SPOTIFY_REDIRECT_URICallback URL for Spotify OAuth. Example: http://localhost:8080/oauth/spotify/callbackFor Spotify
CORS_ALLOWED_ORIGINSComma-separated list of allowed origins. Include your extension ID and localhost ports.Yes
EXTENSION_REDIRECT_BASEThe chromiumapp.org URL for your extension. Used as the OAuth redirect base for the Chrome identity flow.For Google features
SMTP_HOSTSMTP server. Defaults to smtp.gmail.com, so leaving it unset preserves the Gmail behaviour. Any provider works - Resend is smtp.resend.com, Brevo is smtp-relay.brevo.com.No
SMTP_PORTDefaults to 465, which uses implicit TLS. Port 587 negotiates STARTTLS instead; the code follows the port, so the two stay consistent.No
SMTP_USERSMTP username. Not required to be an email address - several providers use a plain login, such as the literal resend. If this and SMTP_PASS are unset, emails are printed to the console instead of sent.No
SMTP_PASS16-character Google App Password for the SMTP account. Generate at myaccount.google.com → Security → 2-Step Verification → App Passwords.No
FROM_EMAILThe "From" address shown on outbound emails. Defaults to noreply@windom.app. On Gmail it must be SMTP_USER or a verified alias of it; dedicated providers only require the domain to be verified with them.No
APP_URLPublic base URL of the backend. Used to build email verification and password-reset links. Example: http://localhost:8080.No
Finding your extension ID - load the extension as unpacked in Chrome, then go to chrome://extensions. The ID is shown under the extension name. Use it in CORS_ALLOWED_ORIGINS as chrome-extension://YOUR_ID and in EXTENSION_REDIRECT_BASE as https://YOUR_ID.chromiumapp.org.

Example .env for local development#

DATABASE_URL note - when running with docker-compose up, the DATABASE_URL is automatically overridden to point to the db container (port 5432 internally). You only need to set it manually if you run the backend directly on your host, in which case use port 5433 - the host-mapped port Docker Compose exposes.
PORT=8080
NODE_ENV=development
DATABASE_URL=postgresql://windom:windom@localhost:5433/windom
JWT_ACCESS_SECRET=your-generated-secret-here
REFRESH_TOKEN_SECRET=your-other-generated-secret-here
TOKEN_ENC_KEY_BASE64=your-generated-key-here
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
GOOGLE_REDIRECT_URI=http://localhost:8080/auth/google/callback
GOOGLE_OAUTH_REDIRECT_URI=http://localhost:8080/oauth/google/callback
SPOTIFY_CLIENT_ID=your-spotify-client-id
SPOTIFY_CLIENT_SECRET=your-spotify-client-secret
SPOTIFY_REDIRECT_URI=http://localhost:8080/oauth/spotify/callback
CORS_ALLOWED_ORIGINS=chrome-extension://YOUR_EXTENSION_ID,http://localhost:3000,http://localhost:5173
EXTENSION_REDIRECT_BASE=https://YOUR_EXTENSION_ID.chromiumapp.org
# Email - optional. If omitted, verification/reset emails are printed to the console.
# SMTP_USER=you@yourdomain.com
# SMTP_PASS=your-16-char-app-password
# FROM_EMAIL=noreply@windom.app
# APP_URL=http://localhost:8080