Commit graph

24 commits

Author SHA1 Message Date
Johannes Millan
7eabbc34b9 fix(sync): make super-sync-server migrations buildable from scratch
The Prisma migration chain began with an ALTER on the operations table, so
a fresh database could not be initialized from migrations alone (the first
migration failed with no table to ALTER). Separately, the login_token /
login_token_expires_at columns and index existed in schema.prisma and were
used at runtime by src/auth.ts (magic-link login) but were never created by
any migration, so a migrate-only database crashed with
"column users.login_token does not exist".

- Add a 0_init baseline migration that creates the base tables (the
  pre-2025-12-12 shape), sorting before the first incremental migration so
  the existing ALTER migrations apply cleanly on top.
- Add 20260601000000_add_login_token to create the missing magic-link
  columns and index (IF NOT EXISTS, safe on installs that already have them
  from a prior db push).
- Add migration_lock.toml (provider = postgresql), the standard companion to
  a real migration baseline.
- Document baselining for existing databases: `migrate resolve --applied
  0_init` for installs with migration history, and resolving the whole chain
  for db-push installs with none (covers the Helm/Docker unattended paths).
- Add regression tests asserting the baseline exists and that every @map
  column in schema.prisma stays backed by a migration (guards the drift class
  that caused this bug, not just login_token).

Verified by replaying all migrations on a fresh Postgres: the chain applies
cleanly and the resulting schema matches schema.prisma exactly.

Closes #8187
2026-06-09 11:36:44 +02:00
felix bear
d82754faf2
feat(supersync): configure server bind host #7301 (#8108)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 12:12:49 +02:00
johannesjo
b83a6745e6 fix(supersync): prevent stale deploy image skew 2026-05-15 23:50:41 +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
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
d18515598e fix(supersync): tighten optional index checks 2026-05-12 18:10:30 +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
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
a335589dc6 refactor(sync): reduce vector clock DoS cap from 100 to 50 entries 2026-02-12 16:27:55 +01:00
tandy1000
551319293a
Update README to require PUBLIC_URL for configuration (#6300)
Mark PUBLIC_URL as required in the README.

I tried to run this locally and I got an error when I didn't define this in the .env, but no error for not defining the SMTP server which definitely seems to be needed.
2026-02-02 14:21:55 +01:00
Johannes Millan
0f8d2cbc42 chore: code review improvements for operation-logs branch
Phase 1 - Code Quality:
- Add clarifying comment in lww-update.meta-reducer.ts explaining
  Date.now() choice for LWW conflict resolution
- Document multi-instance deployment limitations in README.md
  (passkey challenges, snapshot locks)

Phase 2 - Testing:
- Add TODAY_TAG selector edge case tests (deleted/archived tasks)

Phase 3 - Minor Polish:
- Add createValidationErrorResponse() helper to hide Zod validation
  details in production (sync.routes.ts)
- Add database index @@index([userId, opType]) for faster restore
  point queries
2026-01-03 13:17:42 +01:00
Johannes Millan
51ed56ac57 docs(auth): add authentication architecture documentation
Explain design decisions and security trade-offs:
- Why stateless JWTs (not stored in DB)
- Why token versioning over blacklisting
- Why verification tokens are plain strings
- Why bcrypt with 12 rounds

Include security features table, token lifecycle diagram,
and configuration reference.
2025-12-28 11:50:42 +01:00
Johannes Millan
39d6e15446 docs: improve structure 2025-12-27 11:32:54 +01:00
Johannes Millan
b4ce9d5da6 docs: reorganize sync and operation-log documentation
Move scattered architecture docs into centralized locations:

- Move operation-log docs from src/app/core/persistence/operation-log/docs/
  to docs/op-log/
- Flatten docs/sync/sync/ nested structure to docs/sync/
- Move supersync-encryption-architecture.md from docs/ai/ to docs/sync/
- Copy pfapi sync README to docs/sync/pfapi-sync-overview.md
- Update all cross-references to use new paths

This improves discoverability and keeps architecture documentation
separate from source code.
2025-12-27 10:54:13 +01:00
Johannes Millan
642f8d3984 docs(sync): improve and consolidate operation log documentation
- Update hybrid-manifest-architecture.md status to Implemented
- Add documentation index (README.md) for operation-log docs
- Add index for docs/ai/sync/ with document categorization
- Replace duplicate docs with redirect stubs to canonical locations
- Add effect rules, multi-entity rules, and config constants to operation-rules.md
- Update vector-clocks.md with operation log integration section
- Expand super-sync-server README with API details and security features
- Update pfapi sync README with operation log integration info
2025-12-16 10:45:20 +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
75c66a243f feat(super-sync-server): fix docs, add tests, and optimize snapshots
- Rewrote README to clarify custom operation-log architecture (not WebDAV).
- Added Vitest and implemented comprehensive unit tests for SyncService.
- Implemented Incremental Snapshots to improve performance.
- Reduced stale device cleanup threshold to 30 days to reduce DB bloat.
- Increased max payload size to 20MB to support large initial imports.
- Added in-memory DB support for faster testing.
2025-12-12 20:46:23 +01:00
Johannes Millan
61c3758ad6 feat(syncServer): add user isolation, public URL configuration for email links and improve user registration flow 2025-12-12 20:46:04 +01:00
Johannes Millan
93c76d5cdb feat(syncServer): implement JWT authentication and user registration/login functionality 2025-12-12 20:46:04 +01:00
Johannes Millan
05b3e6a6cd feat(syncServer): enhance server configuration and improve error handling 2025-12-12 20:46:04 +01:00