Skip to content

Commit 1967eee

Browse files
authored
Release ZenNotes 1.1.0
Monorepo foundation, self-hosted web/server support, remote desktop workspaces, security hardening, CI fixes, and release prep.
1 parent 58af119 commit 1967eee

235 files changed

Lines changed: 12986 additions & 2122 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ jobs:
1717
build:
1818
name: Build (${{ matrix.os }})
1919
runs-on: ${{ matrix.os }}
20+
env:
21+
GOCACHE: ${{ runner.temp }}/go-build-cache
2022
strategy:
2123
fail-fast: false
2224
matrix:
@@ -34,6 +36,12 @@ jobs:
3436
node-version: 22
3537
cache: npm
3638

39+
- name: Set up Go
40+
uses: actions/setup-go@v6
41+
with:
42+
go-version-file: apps/server/go.mod
43+
cache-dependency-path: apps/server/go.sum
44+
3745
- name: Install dependencies
3846
run: npm ci
3947

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
node_modules
22
out
33
dist
4+
.turbo
5+
apps/*/.turbo
6+
apps/web/dist
7+
apps/server/bin
48
.DS_Store
59
*.log
610
.env
@@ -11,3 +15,4 @@ dist
1115
.idea
1216
.claude/
1317
*.tsbuildinfo
18+
data/

Dockerfile

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# syntax=docker/dockerfile:1.7
2+
3+
# ZenNotes self-hosted build from the monorepo.
4+
#
5+
# Stages:
6+
# 1. web-build -> npm workspace install + Vite build for apps/web
7+
# 2. server-build -> Go build for apps/server with the web bundle embedded
8+
# 3. runtime -> minimal image with only the server binary
9+
10+
FROM node:22-alpine AS web-build
11+
WORKDIR /app
12+
13+
COPY package.json package-lock.json turbo.json tsconfig.base.json tsconfig.json tailwind.config.js postcss.config.js ./
14+
COPY apps/web/package.json apps/web/package.json
15+
COPY packages/app-core/package.json packages/app-core/package.json
16+
COPY packages/bridge-contract/package.json packages/bridge-contract/package.json
17+
COPY packages/shared-domain/package.json packages/shared-domain/package.json
18+
COPY packages/shared-ui/package.json packages/shared-ui/package.json
19+
COPY apps/desktop/package.json apps/desktop/package.json
20+
COPY apps/server/package.json apps/server/package.json
21+
22+
RUN npm ci --no-audit --no-fund --loglevel=error
23+
24+
COPY apps apps
25+
COPY packages packages
26+
27+
RUN npm run build --workspace @zennotes/web
28+
29+
FROM golang:1.22-alpine AS server-build
30+
WORKDIR /app
31+
32+
COPY apps/server/go.mod apps/server/go.sum ./apps/server/
33+
WORKDIR /app/apps/server
34+
RUN go mod download
35+
36+
WORKDIR /app
37+
COPY apps/server apps/server
38+
COPY --from=web-build /app/apps/web/dist/ /app/apps/server/web/dist/
39+
40+
ENV CGO_ENABLED=0 \
41+
GOOS=linux \
42+
GOFLAGS=-trimpath
43+
44+
WORKDIR /app/apps/server
45+
RUN go build -ldflags="-s -w" -o /out/zennotes-server ./cmd/zennotes-server
46+
47+
FROM scratch
48+
LABEL org.opencontainers.image.title="ZenNotes" \
49+
org.opencontainers.image.description="Self-hosted ZenNotes web/server bundle from the monorepo." \
50+
org.opencontainers.image.source="https://github.com/ZenNotes/zennotes"
51+
52+
COPY --from=server-build /out/zennotes-server /zennotes-server
53+
54+
ENV ZENNOTES_BIND=0.0.0.0:7878 \
55+
ZENNOTES_CONFIG_PATH=/data/server.json \
56+
ZENNOTES_DEFAULT_VAULT_PATH=/workspace \
57+
ZENNOTES_BROWSE_ROOTS=/workspace
58+
59+
USER 65532:65532
60+
61+
EXPOSE 7878
62+
VOLUME ["/workspace", "/data"]
63+
64+
ENTRYPOINT ["/zennotes-server"]

Makefile

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
IMAGE ?= zennotes-selfhosted:local
2+
PORT ?= 7878
3+
CONTENT_ROOT ?= ./vault
4+
DATA ?= ./data
5+
APP_URL ?= http://localhost:$(PORT)
6+
ALLOW_INSECURE_NOAUTH ?= 0
7+
COMPOSE := $(shell docker compose version >/dev/null 2>&1 && echo "docker compose" || echo "docker-compose")
8+
OPEN_BROWSER := $(shell command -v open 2>/dev/null || command -v xdg-open 2>/dev/null)
9+
10+
.PHONY: help install dev desktop web-dev server-dev web-stack \
11+
build desktop-build web-build server-build \
12+
up down restart logs status open rebuild nuke clean
13+
14+
help:
15+
@echo ""
16+
@echo " Setup"
17+
@echo " make install — install npm workspace dependencies"
18+
@echo ""
19+
@echo " Local development"
20+
@echo " make desktop — run the Electron desktop app in dev mode"
21+
@echo " make web-dev — run the Vite web client in dev mode"
22+
@echo " make server-dev — run the Go server in dev mode"
23+
@echo " make web-stack — run server + web dev together"
24+
@echo ""
25+
@echo " Local builds"
26+
@echo " make build — build the full monorepo"
27+
@echo " make desktop-build — build the Electron desktop app"
28+
@echo " make web-build — build apps/web"
29+
@echo " make server-build — build apps/server with the latest embedded web bundle"
30+
@echo ""
31+
@echo " Docker"
32+
@echo " make up — build and start the self-hosted server"
33+
@echo " make down — stop the container"
34+
@echo " make restart — restart the container"
35+
@echo " make logs — follow logs"
36+
@echo " make status — show compose status"
37+
@echo " make open — open the app in your browser"
38+
@echo " make rebuild — force a full rebuild"
39+
@echo " make nuke — tear down and remove local image/build output"
40+
@echo " make clean — remove local web/server build output"
41+
@echo ""
42+
@echo " Useful Docker vars"
43+
@echo " CONTENT_ROOT=~/iCloud Drive/Obsidian — host folder used as the live vault root"
44+
@echo " PORT=7878 — host port"
45+
@echo " ALLOW_INSECURE_NOAUTH=1 — opt out of generated auth token (not recommended)"
46+
@echo ""
47+
48+
install:
49+
npm ci
50+
51+
dev: desktop
52+
53+
desktop:
54+
npm run dev:desktop
55+
56+
web-dev:
57+
npm run dev:web
58+
59+
server-dev:
60+
npm run dev:server
61+
62+
web-stack:
63+
npm run dev:web-stack
64+
65+
build:
66+
npm run build
67+
68+
desktop-build:
69+
npm run build --workspace @zennotes/desktop
70+
71+
web-build:
72+
npm run build --workspace @zennotes/web
73+
74+
up:
75+
@mkdir -p "$(CONTENT_ROOT)" "$(DATA)"
76+
@ABS_CONTENT_ROOT="$$(cd "$(CONTENT_ROOT)" && pwd)"; \
77+
ABS_DATA="$$(cd "$(DATA)" && pwd)"; \
78+
AUTH_TOKEN=""; \
79+
if [ "$(ALLOW_INSECURE_NOAUTH)" != "1" ]; then \
80+
AUTH_TOKEN_FILE="$$ABS_DATA/auth-token"; \
81+
if [ ! -f "$$AUTH_TOKEN_FILE" ]; then \
82+
node -e "process.stdout.write(require('node:crypto').randomBytes(32).toString('hex'))" > "$$AUTH_TOKEN_FILE"; \
83+
chmod 600 "$$AUTH_TOKEN_FILE"; \
84+
fi; \
85+
AUTH_TOKEN="$$(cat "$$AUTH_TOKEN_FILE")"; \
86+
fi; \
87+
ZENNOTES_IMAGE="$(IMAGE)" \
88+
ZENNOTES_HOST_PORT="$(PORT)" \
89+
ZENNOTES_HOST_CONTENT_ROOT="$$ABS_CONTENT_ROOT" \
90+
ZENNOTES_CONTAINER_CONTENT_ROOT="$$ABS_CONTENT_ROOT" \
91+
ZENNOTES_CONTAINER_DEFAULT_VAULT_PATH="$$ABS_CONTENT_ROOT" \
92+
ZENNOTES_BROWSE_ROOTS="$$ABS_CONTENT_ROOT" \
93+
ZENNOTES_ALLOWED_ORIGINS="http://localhost:$(PORT),http://127.0.0.1:$(PORT)" \
94+
ZENNOTES_AUTH_TOKEN="$$AUTH_TOKEN" \
95+
ZENNOTES_ALLOW_INSECURE_NOAUTH="$(ALLOW_INSECURE_NOAUTH)" \
96+
ZENNOTES_HOST_DATA="$$ABS_DATA" \
97+
ZENNOTES_CONTAINER_UID="$$(id -u)" \
98+
ZENNOTES_CONTAINER_GID="$$(id -g)" \
99+
$(COMPOSE) up --build -d
100+
@printf "\nZenNotes is running at $(APP_URL)\n\n"
101+
ifneq ($(ALLOW_INSECURE_NOAUTH),1)
102+
@printf "Auth token: $(DATA)/auth-token\n\n"
103+
endif
104+
ifneq ($(strip $(OPEN_BROWSER)),)
105+
@$(OPEN_BROWSER) $(APP_URL) >/dev/null 2>&1 || true
106+
endif
107+
108+
down:
109+
@$(COMPOSE) down
110+
111+
restart:
112+
@$(COMPOSE) restart zennotes 2>/dev/null || $(MAKE) --no-print-directory up
113+
114+
logs:
115+
@$(COMPOSE) logs -f
116+
117+
status:
118+
@$(COMPOSE) ps
119+
120+
open:
121+
ifneq ($(strip $(OPEN_BROWSER)),)
122+
@$(OPEN_BROWSER) $(APP_URL)
123+
else
124+
@echo "Open $(APP_URL) manually."
125+
endif
126+
127+
rebuild:
128+
@mkdir -p "$(CONTENT_ROOT)" "$(DATA)"
129+
@ABS_CONTENT_ROOT="$$(cd "$(CONTENT_ROOT)" && pwd)"; \
130+
ABS_DATA="$$(cd "$(DATA)" && pwd)"; \
131+
AUTH_TOKEN=""; \
132+
if [ "$(ALLOW_INSECURE_NOAUTH)" != "1" ]; then \
133+
AUTH_TOKEN_FILE="$$ABS_DATA/auth-token"; \
134+
if [ ! -f "$$AUTH_TOKEN_FILE" ]; then \
135+
node -e "process.stdout.write(require('node:crypto').randomBytes(32).toString('hex'))" > "$$AUTH_TOKEN_FILE"; \
136+
chmod 600 "$$AUTH_TOKEN_FILE"; \
137+
fi; \
138+
AUTH_TOKEN="$$(cat "$$AUTH_TOKEN_FILE")"; \
139+
fi; \
140+
ZENNOTES_IMAGE="$(IMAGE)" \
141+
ZENNOTES_HOST_PORT="$(PORT)" \
142+
ZENNOTES_HOST_CONTENT_ROOT="$$ABS_CONTENT_ROOT" \
143+
ZENNOTES_CONTAINER_CONTENT_ROOT="$$ABS_CONTENT_ROOT" \
144+
ZENNOTES_CONTAINER_DEFAULT_VAULT_PATH="$$ABS_CONTENT_ROOT" \
145+
ZENNOTES_BROWSE_ROOTS="$$ABS_CONTENT_ROOT" \
146+
ZENNOTES_ALLOWED_ORIGINS="http://localhost:$(PORT),http://127.0.0.1:$(PORT)" \
147+
ZENNOTES_AUTH_TOKEN="$$AUTH_TOKEN" \
148+
ZENNOTES_ALLOW_INSECURE_NOAUTH="$(ALLOW_INSECURE_NOAUTH)" \
149+
ZENNOTES_HOST_DATA="$$ABS_DATA" \
150+
ZENNOTES_CONTAINER_UID="$$(id -u)" \
151+
ZENNOTES_CONTAINER_GID="$$(id -g)" \
152+
$(COMPOSE) build --no-cache
153+
@$(MAKE) --no-print-directory up
154+
155+
nuke:
156+
@$(COMPOSE) down --rmi local --volumes || true
157+
@rm -rf apps/web/dist apps/server/bin apps/server/web/dist $(DATA)
158+
159+
server-build: web-build
160+
npm run build --workspace @zennotes/server
161+
162+
clean:
163+
rm -rf apps/web/dist apps/server/bin apps/server/web/dist

0 commit comments

Comments
 (0)