Document storage + auto-sync, propagation deletes, quotas + Profile tab#53
Merged
Conversation
…le tab Garage data (vehicles/setups/templates/types/notes) now auto-syncs to the cloud while signed in, as its own free "documents" tier (5 MB) separate from log blobs (20 MB). Limits are enforced server-side. - garageEvents.ts: host pub/sub; the doc-store modules emit put/delete after each write. cloud-sync's autoSync.ts subscribes (lazy, started in setup), debounces, and incrementally upserts/deletes the one changed cloud record; reconciles (pull→push docs) on sign-in. Stays off the initial bundle. - Propagation deletes: removing a vehicle/setup while signed in deletes the cloud record too; the Karts/Setups delete UI shows a loud "deletes from every device + the cloud" warning when signed in. - Tiers + server enforcement (migration): quota_limits table (single source of truth), enforce_sync_quota BEFORE trigger on sync_records, and a sync_storage_usage() RPC for the meter. tiers.ts holds the advisory client mirror + usage math (unit-tested). - Profile tab (new PanelSlot.Profile, far right): cloud-sync contributes a StoragePanel with per-tier usage meters + an account scratch pad. https://claude.ai/code/session_01K4mWVsXnwhtEi92FVBVhB3
Coverage SummaryLines: 14.72% (1538/10448) · Statements: 14.02% · Functions: 10.65% · Branches: 10.82% Per-file coverage
|
27 tasks
Reserve "tier" for future subscription tiers. The storage-class concept (documents vs logs) is now "storage type" throughout: storageTypes.ts (StorageType/storageTypeForStore/StorageTypeUsage), the quota_limits.storage_type column + sync_storage_type() helper, and the sync_storage_usage() RPC column. No behavioural change. Migration is unmerged, so the column rename is safe. https://claude.ai/code/session_01K4mWVsXnwhtEi92FVBVhB3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Turns garage data into a free, auto-synced "documents" storage type — separate
from log blobs — with server-enforced limits and a new Profile tab to see usage.
Auto-sync (documents storage type)
src/lib/garageEvents.ts: the doc-store modules(
vehicleStorage,setupStorage,templateStorage,noteStorage) emit{ store, key, put|delete }after each write.cloud-sync/autoSync.tssubscribes (when signed in), debounces, andincrementally upserts (put) / deletes (delete) the single changed cloud
record; reconciles (pull docs → push docs) on sign-in. Started in the
plugin
setupvia a dynamic import, so the sync engine stays off the initialbundle (verified).
Anonymous → cloud account migration
pullDocs(cloud → local) thenpushDocs(local → cloud). For a new account the cloud is empty, so the pull is a
no-op and the push uploads all the anon user's local setups/vehicles/templates
into their new account — automatic, no extra step. (Runs on every signed-in
load, so it self-heals.)
same id → cloud wins on the pull (local edit could be overwritten). No
collisions on a fresh account. Timestamp-merge is the follow-up (tracked on BETA → main [ON HOLD — do not merge] #41).
Propagation deletes
Karts/Setups delete confirm shows a loud "deletes from every device and the
cloud" warning when signed in (normal copy when signed out).
Storage types + server-side enforcement
documents= all structured stores (5 MB, free, auto-synced);logs= fileblobs (20 MB, opt-in). Migration
..._storage_quotas.sqladds:quota_limitstable (storage_type,max_bytes) — single source of truth(client meter + trigger read it).
enforce_sync_quotaBEFORE INSERT/UPDATE trigger onsync_records— rejectsover-limit writes (
quota_exceeded);sync_storage_type()helper.sync_storage_usage()RPC — per-type(used, limit)for the meter.storageTypes.tsholds the advisory client mirror + usage math (unit-tested).Client checks are advisory; the DB trigger is the real gate.
Profile tab
PanelSlot.Profile, self-gating like Coach).cloud-sync contributes
StoragePanel— per-type usage meters + an accountscratch pad (display name/avatar are placeholders for now).
Notes / follow-ups (tracked on #41)
pushDocsis a single batch upsert, so if local docsexceed the limit the whole batch is rejected (saved locally, not synced) —
could be chunked/partial later.
Test plan
npm run lint/npm run typecheck/npm run test:run(328; +6 storage-type tests) /npm run buildindexchunkhttps://claude.ai/code/session_01K4mWVsXnwhtEi92FVBVhB3