Commit graph

51 commits

Author SHA1 Message Date
Johannes Millan
726d877d17
fix(sync): point manual supersync image push at super-productivity org (#7871)
build-and-push.sh defaulted the image namespace to the deprecated ghcr.io/johannesjo/supersync — the source of the stale 7-day-token :latest image in #7865. Default to the super-productivity org instead, matching the CI workflow, docker-compose.yml and the Helm chart.

Since you cannot docker login as an org, split the image namespace (GHCR_NAMESPACE, defaulting to the org) from the GHCR login account (GHCR_USER), and fail fast if a push is attempted with no GHCR_USER set.

Refs #7865
2026-06-01 13:32:06 +02:00
Johannes Millan
06477e9fd9 feat(super-sync-server): add recover-user data-recovery script
Reconstructs a single user's AppDataComplete by replaying their op log up to a chosen serverSeq and decrypting E2E-encrypted payloads — the recovery path the server's restore endpoint cannot offer for encrypted accounts (it throws EncryptedOpsNotSupportedError). Read-only on the DB; documented in docs/backup-and-recovery.md. Unverified against real encrypted data — see the script header.
2026-05-22 19:18:40 +02:00
johannesjo
b83a6745e6 fix(supersync): prevent stale deploy image skew 2026-05-15 23:50:41 +02:00
Johannes Millan
3b0cb9b836 fix(supersync): address multi-agent review of CONCURRENTLY recovery
- Tighten recovery guard to the idempotent drop-then-create shape (require
  both DROP and CREATE INDEX CONCURRENTLY). A bare CREATE (20260511000000) is
  now refused by gate, deterministically — matching its documented fail-loud
  intent instead of relying on the CREATE erroring by accident. Reconciles
  README with the committed migration + migration-sql.spec.ts.
- Escape single quotes in print_manual_recovery so the printed escape-hatch
  commands are copy-pasteable for SQL containing quotes (e.g. the full-state
  WHERE op_type IN ('SYNC_IMPORT', ...) migration).
- Fix MIGRATE_LOG temp-file leak across retry attempts.
- Add an in-script per-step timeout (with_timeout) so the Dockerfile CMD /
  helm initContainer paths (no outer timeout) can't hang forever on a blocked
  concurrent build; 124 fails loudly.
- Harden parse_failing_migration: sentence-anchored P3009 parse + reject
  names outside the migration charset (path-traversal defence).
- Gate also accepts SQLSTATE 25001 (stable Postgres contract) not just the
  localizable English message.
- MAX_ATTEMPTS -> documented tight bound (6); fail_loudly wording fixed
  (was contradictory for the non-CONCURRENTLY case).
- Tests: bare-CREATE refusal, P3009 decoy-token parser hardening; trim
  migration-sql.spec.ts to the architectural-invariant subset (no hardcoded
  names) per 'test behavior not implementation'.

Full server suite: 36 files, 727 passed / 5 skipped.
2026-05-15 22:03:25 +02:00
Johannes Millan
3c41be964c fix(supersync): generic in-image CONCURRENTLY migration recovery
prisma migrate deploy wraps each migration in a transaction; CONCURRENTLY
index migrations fail it (P3018/25001) and later deploys then stick (P3009).
Recovery was duplicated and migration-name-hardcoded in the host deploy.sh
and the in-image migrate-deploy.sh. The host script self-updates only via a
best-effort git pull, so a stale host deploy.sh had no recovery branch for a
new CONCURRENTLY migration and failed the deploy (the reported incident).

- migrate-deploy.sh: single, name-agnostic recovery. Parses the failing
  migration from Prisma's own output, gates on the txn-block/P3009 signature
  AND the migration's own SQL containing INDEX CONCURRENTLY, runs that SQL
  out-of-band statement-by-statement, and only marks it applied if every
  statement succeeded; otherwise fails loudly with manual steps. Bounded
  retry loop; aborts instead of looping on re-failure.
- deploy.sh: ~290 lines of hardcoded host-side recovery removed; now invokes
  the in-image scripts/migrate-deploy.sh (always version-locked to
  prisma/migrations in the pulled image) and keeps only timeout/exit policy.
- tests: drive the script end-to-end via a fake npx (P3018, stuck P3009,
  non-CONCURRENTLY refusal, statement-failure, re-failure abort, genuine
  error passthrough, multi-migration chain); migration-sql.spec.ts updated
  to the new contract.
- prisma/migrations/README.md: authoring rules the recovery relies on.

Design: docs/plans/2026-05-15-generic-concurrently-migration-recovery-design.md
2026-05-15 21:43:49 +02:00
Johannes Millan
2d9988dd73
perf(sync): SuperSync server speed + correctness hardening (#7621)
* docs(sync): add super sync server perf plan

* perf(sync): implement supersync server perf phases

* fix(sync): bracket auth cache invalidation

* fix(sync): avoid empty replay state stringify

* fix(sync): harden supersync batch uploads

* fix super sync review findings

* fix(sync): guard payload bytes backfill rollout

* perf(sync): speed up payload_bytes backfill and index its scan

Raise the backfill batch size (DEFAULT 5->500, MAX 25->1000) so a
100M-row operations table backfills in minutes rather than tens of
hours. Add a CONCURRENTLY partial index on (user_id, id) WHERE
payload_bytes = 0: it drains to empty post-backfill so the boot-time
backfill self-check and the BOOL_OR quota probe stop doing a full
sequential scan to prove absence, and it makes the backfill's per-user
keyset paging a true index seek. Wire the new concurrent-index
migration into both deploy scripts' P3018 recovery path. Add
migration-SQL guard tests for the ADD COLUMN (metadata-only fast path)
and the new partial index.

* fix(sync): bound auth cache invalidation map and bracket every delete

The auth verification cache's invalidationVersions map grew one entry
per lifetime-invalidated user with no eviction (unbounded heap on a
long-lived single replica). Cap it at the same 10k LRU bound as the
entries map, re-inserting the just-invalidated user at the MRU tail so
the CAS race protection still holds for the only window that matters
(one DB round trip). Bracket the passkey/magic-link registration
cleanup deletes with pre+post invalidate to match the documented
convention, and invalidate on verifyEmail so a freshly-verified user
isn't denied for up to the cache TTL.

* perf(sync): skip the redundant exact replay-state measurement

The delta accounting is a proven over-estimate of the serialized state
size, so when the running bound stays within the cap the true size is
too and the final exact JSON.stringify is provably redundant. Skip it
in that case (still measure-and-throw whenever the bound does not prove
safety). This collapses the common small/incremental replay back to
zero expensive full stringifications, matching the old per-op loop
instead of regressing it. Name the entity-key JSON overhead constant
and document that assertReplayStateSize's return value is load-bearing.

* refactor(sync): split processOperationBatch into pipeline stages

Extract the 297-line batch upload method into a thin orchestrator plus
six named single-responsibility stage helpers (validate+clamp, intra-
batch dedupe, classify existing duplicates, conflict-detect, reserve
seq + insert, full-state clock). Behavior-preserving: every stage
writes terminal rejections into the shared results array by index and
the two empty-set guards short-circuit exactly as before. Also share
the timestamp clamp, the duplicate-op SELECT, and the merged
full-state clock persistence between the batch and legacy paths so
they cannot silently diverge.

* test(sync): pin batch error-code divergence and aggregate-once

Strengthen the intra-batch duplicate test to assert same-id /
different-content yields DUPLICATE_OPERATION (deliberate divergence
from the legacy INVALID_OP_ID), and document the divergence in the
plan. Replace the single-full-state aggregate test with two
full-state ops + a spy asserting _aggregatePriorVectorClock runs
exactly once and last-write-wins — the old test could not catch a
per-op-aggregate regression. Add a makeOp fixture factory. Correct
the plan's overstated replay-stringification numbers.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: johannesjo <1456265+johannesjo@users.noreply.github.com>
2026-05-15 17:24:16 +02:00
johannesjo
ca660a0585 fix(supersync): harden production server deploy 2026-05-13 02:10:46 +02:00
Johannes Millan
88961485fd fix(supersync): harden deploy database migration 2026-05-12 23:24:13 +02:00
Johannes Millan
e0cc783bba Merge branch 'master' into feat/carefully-review-all-super-sync-related-9daf6d
* master:
  fix(sync): restore InvalidFilePrefixError privacy log at app-shim site
  test(sync-providers): restore WebDAV parser namespace + server-format specs
  refactor(sync-providers): @xmldom/xmldom to devDeps + global DOMParser
  refactor(sync-providers): broaden WebDAV CORS heuristic for real browsers
  refactor(sync-providers): testWebdavConnection helper, drop adapter+api from barrel
  refactor(sync-providers): tighten WebDAV slice after multi-review
  refactor(sync-providers): move WebDAV + Nextcloud providers into package
  docs(sync-core-plan): fold Gemini review dissent into consensus
  refactor(sync-providers): promote shared log helpers
  docs(sync-core-plan): record WebDAV slice multi-review consensus
  docs(sync-core-plan): draft WebDAV slice design for multi-review
  docs(sync-core-plan): summarize Fifth Slice and renumber remaining
  fix(sync): harden supersync server edge cases
  fix reviewed calendar and duplicate edge cases
  test(electron): align TODAY filter spec with isTodayWithOffset impl
  refactor(sync-providers): tighten Dropbox port after review
  refactor(sync-providers): move Dropbox provider into package
  refactor(sync-providers): move provider error classes

# Conflicts:
#	packages/super-sync-server/src/sync/services/operation-download.service.ts
#	packages/super-sync-server/src/sync/sync.routes.ts
2026-05-12 22:35:37 +02:00
Johannes Millan
948d9c7db3 fix(sync): harden supersync server edge cases 2026-05-12 21:53:49 +02:00
Johannes Millan
40c354d4ef fix(supersync): scrub merge debris and align deploy defaults
- B11: Remove orphan deploy-db-scalar.mjs and dead RUN_POST_MIGRATION_INDEXES
  references in env.example and README. Rewrite README deploy section to
  match what scripts/deploy.sh actually does (drop false claims about
  empty migration SQL, failed-migration recovery, and optional index builds).
- B12: Default RUN_MIGRATIONS_ON_STARTUP to false in docker-compose.yml so
  the compose, Dockerfile ENV, and env.example agree on the safer default
  (manual deploy.sh runs migrations once before app restart). Update the
  migration-sql.spec assertion to match.
- I9: Wrap prisma migrate deploy in deploy.sh with a MIGRATION_TIMEOUT
  (default 900s). CREATE INDEX CONCURRENTLY can block on long-running
  transactions; on timeout (exit 124) the script now fails loudly with a
  clear error rather than hanging.
2026-05-12 21:26:32 +02:00
Johannes Millan
fb940c1d4a Merge branch 'master' into feat/our-latest-super-sync-server-update
Resolves conflicts in supersync after master's parallel work:
- Schema: adopt master's 4-col entity_sequence_index + partial restore-point
  index migration. Drops our out-of-band index hack — master's migration runs
  CREATE INDEX CONCURRENTLY directly.
- deploy.sh: take master's simpler 169-line version; keep our hardening
  (set -euo pipefail, guarded ${VAR:-}, diagnostic pipeline || true).
- snapshot.service.ts: keep our EncryptedOpsNotSupportedError, cache stale-
  overwrite guard (updateMany+create+P2002), invalidate corrupt cache,
  async gzip helpers, _resolveExpectedFirstSeq leading-gap acceptance,
  full-state reset semantics, Buffer.byteLength replay size check. Adopt
  master's REPLAY_OPERATION_SELECT, ReplayOperationRow type, and
  assertContiguousReplayBatch module-level helper.
- compressed-body-parser.ts: keep our invalid-json reason, single base64
  decode, and shared gzip.ts helper. Adopt master's improved
  isDecompressedPayloadTooLargeError check (covers 'Cannot create a Buffer
  larger than').
- operation-download.service.ts: take master's latestSeq==0 fast-path and
  conditional minSeq aggregate.
- local-rest-api-handler.service.ts: take master's shared
  isTaskInToday + isTodayWithOffset (offset-aware) over our private method.
- tests: align spec mocks with upsert + cacheSnapshotIfReplayable +
  REPLAY_OPERATION_SELECT, take master's migration-sql.spec.ts.

587/587 supersync tests pass; checkFile clean on all touched .ts files.
2026-05-12 20:40:26 +02:00
Johannes Millan
9b965f2c35 fix(supersync): address review findings on snapshot replay and body parsing
- Use upsert for userSyncState to avoid RecordNotFound on first-time users
- Reset (not merge) state on full-state ops; throw on malformed payloads
- Add typed EncryptedOpsNotSupportedError; stop leaking op count to clients
- Split JSON.parse vs decompress error paths (new invalid-json reason)
- Measure base64 transport size against decoded binary; decode once
- Guard concurrent cacheSnapshot writes against stale overwrite
- Move encryption-skip policy from route into cacheSnapshotIfReplayable
- Invalidate corrupt cached snapshot blobs instead of re-logging forever
- Use Buffer.byteLength for replay state size (was UTF-16 vs byte limit)
- Skip cache-replayability assert on the cache-hit fast-path
- Extract async gunzip/gzip into gzip.ts; stop blocking the event loop
- Replace inline tx structural types with Prisma.TransactionClient
- deploy.sh: set -euo pipefail with guarded vars and pipeline-safe diagnostics
2026-05-12 20:22:24 +02:00
Johannes Millan
d18515598e fix(supersync): tighten optional index checks 2026-05-12 18:10:30 +02:00
Johannes Millan
37891c4d9e fix(supersync): resolve deploy helper imports 2026-05-12 17:19:49 +02:00
Johannes Millan
212e6d6e4a fix(supersync): harden deploy recovery 2026-05-12 17:12:53 +02:00
Johannes Millan
6201b8493d fix supersync external db recovery 2026-05-12 16:31:03 +02:00
Johannes Millan
6af85b6892 fix supersync deploy migrations 2026-05-12 15:39:26 +02:00
johannesjo
2a802bfc72 perf(sync): speed up SuperSync uploads 2026-05-12 00:37:00 +02:00
Johannes Millan
78f64508db feat(sync-server): add active-users-quick monitor command
Avoids the operations table entirely (sync_devices + users only) so it
returns in milliseconds even when operations grows past 1 GB. Useful when
the standard active-users command is too slow on large prod DBs.
2026-04-21 15:03:42 +02:00
Johannes Millan
62f9f9cfd4 fix(sync-server): avoid per-user correlated scans in monitor usage
The showUsage query ran two correlated subqueries over the full
operations table once per user, each calling pg_column_size(payload)
on every row, then sorted all users before LIMIT 20. On a 1.85 GB
operations table with 3.6k users this effectively never returned.

Aggregate per-user size and count in a single CTE pass, then join.
One sequential scan instead of scans × users.
2026-04-20 18:51:12 +02:00
Johannes Millan
d32f7037a3 fix(sync): preserve own vector clock counter across full-state op resets
When a full-state op (SYNC_IMPORT/BACKUP_IMPORT) arrived from another
client, mergeRemoteOpClocks reset the local clock to a "minimal" form
but only preserved the current client's counter from the incoming op's
clock. If the current client had issued ops (e.g. GLOBAL_CONFIG) not
reflected in the incoming full-state op's clock, its counter was dropped,
causing subsequent ops to reuse the same counter value. Downstream clients
then saw these ops as EQUAL (duplicate) and skipped them silently.

Fix: take max(mergedClock[clientId], currentClock[clientId]) when
rebuilding the clock after a full-state op reset.

Also add __SP_E2E_BLOCK_WS_DOWNLOAD flag to WsTriggeredDownloadService
to allow E2E tests to block automatic WS-triggered downloads during
concurrent conflict scenarios.

Fix archive conflict test by blocking WS downloads on Client A during
the concurrent edit phase so it doesn't auto-receive B's rename via
WebSocket before archiving (restoring the intended conflict scenario).

Fix LWW singleton test to assert convergence rather than specific winner.
Fix renameTask helper to avoid Playwright/Angular re-render races.
Fix shepherd.js import paths that broke the Angular dev server build.
2026-04-01 15:41:13 +02:00
Johannes Millan
821a87ba71 chore(deps): upgrade prisma from 5.22.0 to 7.6.0
Migrate super-sync-server to Prisma v7:
- Switch generator from prisma-client-js to prisma-client with local output
- Add prisma.config.ts for datasource URL configuration
- Use PrismaPg driver adapter instead of built-in Rust engine
- Add @prisma/adapter-pg and pg dependencies
- Update all imports from @prisma/client to generated client path
- Fix Buffer→Uint8Array for Bytes fields (Prisma v6 breaking change)
- Update Dockerfile: prisma CLI version, copy prisma.config.ts
- Add DATABASE_URL validation in db.ts
- Add src/generated/ to .gitignore
2026-03-31 20:05:03 +02:00
Johannes Millan
e6b82f973a fix(sync-server): remove jq dependency from deploy script
Use docker compose Go templates instead of JSON+jq for container
status output in the failure path.
2026-03-27 17:55:49 +01:00
Johannes Millan
4ee5dd4ed7 fix(sync-server): use compiled JS for monitoring scripts in Docker
The production container runs as non-root user `supersync` without tsx
(dev dependency excluded via --omit=dev). Analysis and monitor-all
commands failed because they tried to use tsx/npx tsx which couldn't
write to node_modules. All scripts are already compiled to dist/ during
the Docker build, so use those directly.
2026-03-27 17:33:38 +01:00
Johannes Millan
602b8002e7 fix(sync-server): harden deploy with Caddyfile validation and container checks
- Pin Caddy image to 2.11-alpine to prevent breaking changes from
  floating tags
- Validate Caddyfile syntax before deploying to catch config errors
  early
- Check all container states after startup to detect crashes before
  waiting on the HTTPS health check
- Show logs from all services on failure, not just supersync
2026-03-23 13:34:05 +01:00
Johannes Millan
5aff8d0aae fix(monitoring): use Prisma.sql for conditional SQL fragments in analyze-storage
Prisma's $queryRaw tagged template treats ${} as parameterized values, not
raw SQL. Conditional fragments like `${userId ? \`WHERE ...\` : ''}` were
sent as string parameters, causing PostgreSQL syntax error 42601.
2026-03-23 13:03:31 +01:00
Johannes Millan
2d7656c5c8 fix(monitoring): mask PII, add types, fix sort and validation issues
Mask user emails by default (--unmask to reveal). Replace all any[]
query results with typed interfaces. Fix showUsageHistory sort that
compared formatted byte strings. Add parseIntArg validation for CLI
flags. Fix unbounded recursion in analyzePayload. Replace execSync with
execFileSync for DATA_DIR to prevent shell injection. Add --no-save flag
for usage command.
2026-03-23 10:52:57 +01:00
Johannes Millan
fe65d81635
Add active users monitoring command with engagement metrics (#6921)
* feat(sync): add active-users command to monitor CLI

Adds a new `active-users` command to the SuperSync monitor script that reports:
- Total registered and verified user counts
- Active users by time period (24h, 7d, 30d, 90d) based on device and sync activity
- New registration counts
- Recently active users table with device count and ops
- Users who never synced

Usage: npm run monitor -- active-users

https://claude.ai/code/session_014Tc5vtXW4Z8QZFMDFWKErP

* feat(sync): add engaged users metric to active-users report

Shows users who were active on 3+ distinct days in the last 2 weeks
with new sync operations, giving a measure of genuine recurring usage.

https://claude.ai/code/session_014Tc5vtXW4Z8QZFMDFWKErP

* docs(sync): add active-users to docker monitoring docs

Add missing active-users command to docker-monitor.sh case statement,
help text, and DOCKER-MONITORING.md guide.

https://claude.ai/code/session_014Tc5vtXW4Z8QZFMDFWKErP

* refactor(sync): improve active-users command from review feedback

- Fix timezone-unsafe DATE(): use AT TIME ZONE 'UTC' with explicit
  double precision cast for consistent day boundaries
- Replace correlated subquery with LEFT JOIN for ops_7d count
- Show total active count when LIMIT truncates the table
- Add --threshold and --limit CLI flags for flexibility
- Combine device/ops metrics into single line (connected / syncing)
- Add skipInQuick to run-all-monitoring.ts
- Update docker-monitor.sh header, help text, and DOCKER-MONITORING.md
  with active-users command, flags, and performance notes
- Clarify "never synced" output label

https://claude.ai/code/session_014Tc5vtXW4Z8QZFMDFWKErP

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-22 23:15:14 +01:00
Johannes Millan
2cc2760486 feat(i18n): complete translations and update locale files
Translate all missing keys to achieve full coverage (2086/2086)
for fr, pt-br, zh-tw, ro, ro-md, zh, es, de, and cs.
Also remove stale keys and include updated translations
for other locales. Remaining languages still have partial coverage.
2026-03-18 21:55:13 +01:00
Johannes Millan
7c0849e953 fix(sync-server): auto-pull latest code in deploy script
Adds git pull --ff-only before docker compose pull so scripts,
docker-compose.yml, and other repo files are updated on each deploy.
Falls back gracefully if pull fails.
2026-03-18 20:51:59 +01:00
Johannes Millan
1907df68d7 fix(sync-server): security hardening and GDPR log compliance
- Remove email addresses from all log messages (~18 locations) for GDPR
  compliance, replacing with userId where available
- Downgrade debug credential logs from info to debug level
- Remove options.user from passkey registration log (contained email in
  JSON payload)
- Add container security hardening to docker-compose.yml:
  - no-new-privileges on all containers
  - cap_drop: ALL on supersync and caddy
  - Memory limits (supersync 512m, postgres 1g, caddy 256m)
  - CPU limit on supersync (1.0)
- Add .health-alert/ to gitignore
- Add health-alert.sh cron script for container monitoring with
  OOM detection, disk checks, and email alerting
2026-03-18 20:48:51 +01:00
Johannes Millan
a01a511c25 feat(sync): add backup strategy with accounts-only dump and disaster recovery docs
- Add accounts-only pg_dump (users + passkeys) to backup script for
  lightweight disaster recovery when clients still have data
- Add pipefail to backup script to catch silent dump failures
- Add test endpoint to simulate partial server revert (ops-after/:serverSeq)
- Add 6 e2e tests covering all disaster recovery scenarios:
  complete data loss, partial revert, accounts-only restore (API + SQL),
  full dump restore + reset account, and all-clients-lost recovery
- Add backup-and-recovery.md with setup, recovery procedures, and
  decision tree
2026-03-18 20:15:45 +01:00
Johannes Millan
c9f41d090c build(supersync): add GitHub Actions workflow and update Docker config
- Add automated Docker build/push workflow for SuperSync server
- Update docker-compose.yml to use super-productivity org GHCR image
- Add --no-cache flag support to build-and-push.sh script
- Workflow triggers on SuperSync changes or manual dispatch
- Uses GitHub's built-in token (no personal token needed)
2026-01-23 21:42:44 +01:00
Johannes Millan
f7bf3e554a fix(supersync): use npx tsx instead of global install in docker monitor
Replace slow/hanging global tsx installation with npx tsx which is faster
and doesn't require installation. Falls back to npx if tsx not found.
2026-01-23 14:58:59 +01:00
Johannes Millan
554cc09608 feat(supersync): add production Docker monitoring wrapper and tooling
Add docker-monitor.sh wrapper script for running monitoring tools in
production Docker containers, with automatic tsx installation.

Changes:
- docker-monitor.sh: Wrapper script for all monitoring commands
  - Supports basic monitoring (stats, usage, ops, logs)
  - Supports analysis commands (user-deep-dive, large-ops, etc)
  - Auto-installs tsx in container when needed
  - Handles report extraction from container
- Dockerfile: Include TypeScript source files for tsx execution
- package.json: Add docker:monitor npm scripts
- DOCKER-MONITORING.md: Production Docker monitoring guide

New npm scripts:
- npm run docker:monitor -- <command>: Run any monitoring command
- npm run docker:monitor:usage: Quick storage check
- npm run docker:monitor:all: Full monitoring suite
- npm run docker🐚 Interactive shell

Usage:
  ./scripts/docker-monitor.sh usage
  ./scripts/docker-monitor.sh analyze user-deep-dive --user 29
  ./scripts/docker-monitor.sh monitor-all --save
  ./scripts/docker-monitor.sh get-reports ./reports
2026-01-23 14:31:24 +01:00
Johannes Millan
5027b31431 feat(supersync): add comprehensive storage monitoring and analysis toolkit
Add reusable investigation scripts for analyzing SuperSync storage patterns,
user behavior, and operation anomalies.

New scripts:
- analyze-storage.ts: 9 specialized analysis commands (operation sizes,
  timeline, types, large ops, rapid-fire detection, snapshots, user deep-dive,
  export, compare users)
- run-all-monitoring.ts: Complete monitoring suite runner with quick mode
  and save-to-file options
- MONITORING-README.md: Complete documentation with investigation workflows

New npm scripts:
- npm run analyze-storage -- <command>: Run specific analysis
- npm run monitor:all: Run complete monitoring suite
- npm run monitor:all:quick: Quick health check (skip deep analysis)
- npm run monitor:all:save: Save timestamped report to file

These tools provide structured workflows for investigating storage issues
like rapid-fire operations, unusually large operations, and sync loops.
2026-01-23 14:31:24 +01:00
Johannes Millan
a52b7716aa refactor(sync): remove tombstone system
Tombstones were used for tracking deleted entities but are no longer
needed with the operation log architecture. This removes:

- Tombstone table from Prisma schema
- Tombstone-related methods from SyncService
- Tombstone mocks and tests from all test files
- Database migration to drop tombstones table

The operation log now handles deletions through DEL operations,
making the separate tombstone tracking redundant.
2025-12-28 12:08:28 +01:00
Johannes Millan
78d4e4245a feat(sync-server): add operation analysis to monitor CLI
- Add 'ops' command to analyze operation payload sizes
- Show breakdown by entity type with count, total, avg, max sizes
- Display largest operation with payload structure analysis
- Enhance 'usage' command to show ops vs snapshot breakdown
- Show operation count, average size per user
2025-12-19 16:23:52 +01:00
Johannes Millan
90a8190cb8 refactor(sync-server): change usage-history to pivot table format
Shows users as rows with snapshot dates as columns for easier
comparison across time.
2025-12-19 16:19:49 +01:00
Johannes Millan
5917e0d052 feat(sync-server): add per-user growth table to usage-history
Shows each user's storage change between first and last snapshot,
sorted by growth (highest first).
2025-12-19 16:16:57 +01:00
Johannes Millan
a42f0025cb feat(sync-server): add usage history tracking
Each run of `npm run monitor -- usage` now saves a snapshot to
logs/usage-history.jsonl. New command `usage-history` shows past
snapshots with growth stats between runs.
2025-12-19 16:15:38 +01:00
Johannes Millan
754f7fb676 feat(sync-server): add disk space and table size monitoring
- Add disk space info to monitor stats (root filesystem, data dir)
- Add top 5 tables by size to database stats
- Add GHCR login to deploy.sh for private image pulls
2025-12-19 15:54:09 +01:00
Johannes Millan
f056e1224c feat(sync-server): add GHCR-based deployment workflow
Switch from server-side builds to pre-built images:
- Add build-and-push.sh for local builds to GHCR
- Update deploy.sh to pull from registry (30s vs 20min)
- Add docker-compose.build.yml for local build fallback
- Update docker-compose.yml to use registry image
- Add GHCR_USER/GHCR_TOKEN to env.example
- Add npm scripts: docker:build, docker:deploy, docker:backup
2025-12-19 15:24:20 +01:00
Johannes Millan
57766f29dd feat(sync-server): add deployment and monitoring scripts
Add production deployment tooling:
- docker-compose.monitoring.yml: Dozzle + Uptime Kuma stack
- scripts/deploy.sh: Git pull + rebuild with health check
- scripts/backup.sh: PostgreSQL dump with optional rclone upload
2025-12-19 14:26:12 +01:00
Johannes Millan
2c42cf65cb feat(super-sync-server): Add basic monitoring tool
This commit introduces a lightweight monitoring CLI tool for the super-sync-server.

Changes include:
- Enhanced logging:  now supports writing logs to a file () when  is set, enabling persistent log storage.
- New monitoring script:  provides commands for:
    - : Displays system vitals (CPU, RAM) and database connectivity/size.
    - : Shows top 20 users by data storage usage within the database.
    - : Allows tailing, searching, and filtering server logs from the file.
-  update: Added a  script to easily run the tool.
2025-12-12 20:48:40 +01:00
Johannes Millan
2a4dbd7ad0 fix(superSync): Update admin scripts and README for Postgres compatibility
Refactored 'delete-user.ts' and 'clear-data.ts' to use Prisma Client, aligning them with the current PostgreSQL architecture.
Updated 'packages/super-sync-server/README.md' to reflect the Docker-based, PostgreSQL setup and added documentation for the administrative scripts.
Removed '@types/better-sqlite3' from 'package.json' as it's no longer needed.
2025-12-12 20:48:40 +01:00
Johannes Millan
7201eebe85 fix(sync): wrap full-state operation payloads in appDataComplete
SYNC_IMPORT, BACKUP_IMPORT, and Repair operations contain full app state
in their payload. When these operations were downloaded by another client
and applied via applyOperations(), convertOpToAction() was spreading the
payload directly into the action. But reducers expect action.appDataComplete,
so they received undefined and fell back to empty/initial state.

This caused complete data loss (no projects, no tags, tasks in wrong project)
when syncing SYNC_IMPORT operations between clients.

Fix: Add extractFullStatePayload() that wraps the payload in appDataComplete
for full-state operation types, matching what loadAllData action expects.

Also clears file-based storage directories in the clear-data script.
2025-12-12 20:47:48 +01:00
Johannes Millan
27b4da775a fix(super-sync): ensure clear-data script checks for DB existence
Previously,  would silently create a new empty database if the configured  was incorrect or missing, leading to a confusing 'success' message (deleting 0 rows) while the actual data remained untouched. Now, the script verifies that  exists at the expected path before proceeding, and exits with an error if it's missing.
2025-12-12 20:46:26 +01:00
Johannes Millan
9a2f972e4e feat(syncServer): add script to clear sync data for users 2025-12-12 20:46:25 +01:00