Skip to content

Commit 726b67e

Browse files
cpcloudclaude
andauthored
feat(pro): add micasa pro encrypted multi-device sync (#791)
## Summary - **ULID primary keys**: migrate all entities from auto-increment uint to ULID strings for sync compatibility - **Oplog**: change tracking via `sync_oplog_entries` table with GORM hooks for create/update/delete/restore - **Encryption**: NaCl secretbox (XSalsa20-Poly1305) envelope encryption with household key generation and NaCl box key exchange - **Relay server** (`cmd/relay`): full HTTP relay with PgStore, SHA-256 token auth, invite flow with FOR UPDATE locking, blob storage (upload/download/dedup/quota), Stripe webhook verification, graceful shutdown - **Sync engine** (`internal/sync`): pull/push with LWW conflict resolution, blob upload/download with encryption, `blob_ref` stripping in apply - **CLI**: `pro init`, `pro join`, `pro status`, `pro storage`, `pro sync`, `pro invite`, `pro devices`, `pro conflicts` commands - **TUI background sync**: indicator (synced/syncing/offline/conflict glyphs), debounce on mutations, deferred reload during form editing - **Self-hosted relay**: `SELF_HOSTED=true` mode with subscription bypass, configurable blob quota, Docker Compose stack (postgres + relay + optional Caddy TLS) - **CASCADE oplog safety**: `HardDeleteMaintenance` with proper oplog entries for child ServiceLogEntries and document detachment, TUI hard-delete extended to maintenance tab - **~18.7k lines** across 118 files, ~1:1 production-to-test ratio 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a12dea3 commit 726b67e

125 files changed

Lines changed: 21458 additions & 1230 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: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,50 @@ jobs:
157157
files: coverage.txt
158158
token: ${{ secrets.CODECOV_TOKEN }}
159159

160+
pgtest:
161+
name: Postgres Integration
162+
needs: changes
163+
if: needs.changes.outputs.go == 'true'
164+
runs-on: ubuntu-latest
165+
concurrency:
166+
group: ci-pgtest-${{ github.ref }}
167+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
168+
services:
169+
postgres:
170+
image: postgres:17
171+
env:
172+
POSTGRES_USER: micasa
173+
POSTGRES_PASSWORD: testpass
174+
POSTGRES_DB: micasa_test
175+
ports:
176+
- 5432:5432
177+
options: >-
178+
--health-cmd "pg_isready -U micasa"
179+
--health-interval 5s
180+
--health-timeout 5s
181+
--health-retries 5
182+
steps:
183+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
184+
with:
185+
persist-credentials: false
186+
187+
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
188+
with:
189+
go-version: "1.26"
190+
191+
- name: Test relay (with Postgres)
192+
env:
193+
CGO_ENABLED: "1"
194+
RELAY_POSTGRES_DSN: "postgres://micasa:testpass@localhost:5432/micasa_test?sslmode=disable"
195+
run: go test -race -shuffle on -timeout 5m -coverprofile coverage-pg.txt ./internal/relay/
196+
197+
- name: Upload coverage
198+
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
199+
with:
200+
files: coverage-pg.txt
201+
flags: postgres
202+
token: ${{ secrets.CODECOV_TOKEN }}
203+
160204
benchmarks:
161205
name: Benchmarks (smoke)
162206
needs: changes
@@ -249,7 +293,7 @@ jobs:
249293
result:
250294
name: CI Result
251295
if: always()
252-
needs: [changes, test, benchmarks, nix-build, docs, semantic-release-dry-run]
296+
needs: [changes, test, pgtest, benchmarks, nix-build, docs, semantic-release-dry-run]
253297
runs-on: ubuntu-latest
254298
steps:
255299
- run: exit 1

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*.so
99
*.dylib
1010
/micasa
11+
/relay
1112

1213
# Test binary, built with `go test -c`
1314
*.test

AGENTS.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,13 @@ details; do not duplicate that detail here.
288288
cascading defaults across sections, no "this overrides that unless the
289289
other thing is set." If two pipelines need the same setting, they each
290290
get their own independent copy.
291+
- **No defensive casing variants**: We control the serialization protocol.
292+
Every struct that can appear in a JSON payload (oplog entries, API
293+
requests/responses) MUST have explicit `json:"snake_case"` tags on every
294+
field. Never write code that handles multiple casings of the same key
295+
(e.g. `delete(m, "id"); delete(m, "ID")`) -- that papers over an
296+
inconsistency instead of fixing it. If you see ambiguity, fix the
297+
source struct's tags.
291298
- **Deterministic ordering requires tiebreakers**: Every `ORDER BY` that
292299
could tie MUST include a tiebreaker (typically `id DESC`).
293300
- **Audit new deps before adding**: Review source for security issues

0 commit comments

Comments
 (0)