chore: dependency upgrades, Better Auth migration, and performance improvements#98
Closed
elasticjava wants to merge 27 commits into
Closed
chore: dependency upgrades, Better Auth migration, and performance improvements#98elasticjava wants to merge 27 commits into
elasticjava wants to merge 27 commits into
Conversation
- CORS: restrict allowed origin to FRONTEND_URL instead of wildcard - auth: add secure and sameSite=lax flags to OAuth state/code_verifier cookies - server: clear boardSettings cache in emptyBoard to prevent stale data - server: replace direct state mutation in userJoin with immutable pattern - client: remove leftover debug code - schema: add comment explaining dual roleEnum declaration - deps: update Angular ecosystem to 21.2.x, Nx to 22.5.4, and minor packages - chore: add .mcp.json to gitignore
- All @tiptap/* packages updated from 3.0.0-beta.16 to 3.20.1
- Added @tiptap/suggestion@3.20.1 (required peer dep for extension-mention)
- Remove tippyOptions from custom BubbleMenu addOptions (not part of API)
- Fix setContent call: pass { emitUpdate: false } matching new SetContentOptions type
- Fix server.connection() cookies type: Record<string, string | undefined>
(cookie@1.x parse() now returns string | undefined for missing keys)
… → 0.31.9 - drizzle.config.ts: replace driver/breakpoints with defineConfig + dialect (driver: 'pg' and breakpoints removed in drizzle-kit 0.20+)
- Replace lucia, @lucia-auth/adapter-postgresql, arctic with better-auth - Configure Better Auth with Drizzle adapter mapped to existing DB tables (accounts as user table, account_session as session table) - Add Better Auth required columns: emailVerified, createdAt, updatedAt to accounts; token, timestamps, ipAddress, userAgent to account_session - Add oauth_accounts table for OAuth provider account linking - Add verification table for future email/OTP flows - Enable account linking for smooth Google OAuth migration - Replace Lucia session validation with Better Auth getSession API - Replace OAuth callback handler with Better Auth wildcard route (/api/auth/* mounted in Fastify with scoped content-type parser) - Replace lucia.invalidateUserSessions with getAuth().api.revokeUserSessions - Remove parse() from init-server.ts: socket cookie header passed directly - Migration 0008: clears old Lucia sessions, migrates Google links to oauth_accounts Breaking change: existing sessions invalidated; users must re-authenticate.
- DB connection pool: postgres max=20, idle_timeout=30s, connect_timeout=10s - Validator Map: replace O(n) array.find() with O(1) Map.get() per message - Socket.IO: pingTimeout=15s/pingInterval=10s for faster dead conn detection - Socket.IO: maxHttpBufferSize=5MB for large board state transfers - client close(): findIndex short-circuit instead of full map() scan
- StickyNotePadComponent: visueller zettelstapel in der toolbar — klick aktiviert platziermodus, drag-to-drop erstellt zettel direkt an der abwurfposition (miro-tear-off-feeling) - tastenkürzel N zum aktivieren des notizmodus hinzugefügt - ghost-note-vorschau während des ziehens (position:fixed, rotiert) - drei DDD-templates: event-storming, bounded-context-canvas, aggregate-design-canvas (nick tune / virtual DDD) - cypress E2E-projekt (apps/web-e2e) mit 5 test-suiten: note-creation, templates, toolbar, collaboration, ddd-workflows
…board-toolbar - DOM-Kopplung entfernt: board-boundary-check aus StickyNotePadComponent in BoardToolbarComponent verschoben (Trennung der Zuständigkeiten) - NgZone.runOutsideAngular für mousemove-tracking, re-entry nur für Signal-Updates - DOCUMENT-Token statt direktem document-Zugriff (SSR-kompatibel) - totes AppModule-Export-Artefakt entfernt - togglePinned: !this.pinned() statt ternary - #darken: unterstützt nun auch 3-stellige Hex-Codes (#abc)
- text-color bug: contrastColor() statt hardcoded #000 (wcag-kontrast) - focus-indikatoren: :focus-visible mit outline (wcag 2.1 aa) - links: text-decoration underline (wcag 1.4.1) - ws-disconnect: reconnect-banner statt auto-redirect zu / - touch-support: touchstart/move/end in board-move-service - pinch-zoom: 2-finger-zoom im board-zoom-service - e2e: 6 spec-dateien, 45 tests, alle gruen
- 5-phasen-plan: canvas-renderer, yjs-crdt, rust-backend, ux-exzellenz, enterprise - architektur-ziel: canvas 2d + r-tree + yjs + rust/axum + flatbuffers - wettbewerbsanalyse: miro, figjam, excalidraw, tldraw - performance-kpis: 60fps bei 500 nodes, 50+ concurrent users, <20ms latenz
…beitet - Yjs CRDT vor Canvas Renderer priorisiert (Datenverlust = kritischster Bug) - Canvas Full → Canvas Hybrid (DOM-Overlay fuer TipTap, wie tldraw) - Rust Backend gestrichen (Node.js + y-websocket reicht fuer 50-100 User) - FlatBuffers gestrichen (Yjs y-protocols reicht) - Phase 0 eingefuehrt (Baseline + Quick Wins: DOM-Viewport-Culling, Dark Mode) - Feature-Flag Cutover statt Dual-Write Migration - Realistische Ziele (50-100 statt 500+ concurrent Users) - Fehlende Aspekte ergaenzt (S3, GDPR, WS Rate Limiting, Bundle Size) - User-Feedback-Checkpoints nach jeder Phase
- NodesComponent filtert Nodes nach Viewport-Sichtbarkeit - Board-Koordinaten werden aus zoom/position berechnet - 200px Buffer verhindert Pop-in am Viewport-Rand - Fokussierte Nodes werden immer gerendert (kein Verschwinden bei Drag) - Nodes ohne width/height bekommen Default 300px - Keine externen Dependencies (kein rbush noetig bei <1000 Nodes) - E2E: zoomToFit() Command fuer Template-Tests hinzugefuegt - Alle 45 E2E-Tests gruen
- CSS Custom Properties für Dark Mode via prefers-color-scheme und data-theme - Semantische Variablen: --board-bg, --board-dot, --toolbar-bg, --toolbar-border, --dialog-bg - Hardcoded Farben durch CSS-Variablen ersetzt (Toolbar, Panel, Text, Header) - Invertierte Graustufen für Dark Mode (--grey-10 bis --grey-90) - Performance-Monitor: FPS, DOM-Nodes, Memory (debug.perf(), ?perf=1)
- throttleTime(2000) → debounceTime(2000): erst nach 2s Ruhe persistieren - Ephemere User-Daten (cursor, connected) vor Persist filtern - distinctUntilChanged mit JSON-Vergleich: nur bei echten Änderungen schreiben - emptyBoard: ebenfalls User-Nodes vor letztem Persist entfernen
…oration - YjsBoardService: Angular-Service mit Y.Doc, WebsocketProvider, IndexedDB-Offline - y-websocket Server: Fastify WS-Upgrade auf /yjs/:boardId mit Auth + Access-Check - DB-Migration: board_yjs BYTEA + use_yjs Boolean fuer Feature-Flag Cutover - Automatische JSON→Yjs Migration beim ersten Board-Zugriff - Awareness-Protocol fuer Live-Cursors vorbereitet - 3s Debounce-Persist nach Yjs-Updates
… zoom 3 CSS-Stufen: LOD 0 (>50% Zoom) volle Details, LOD 1 (20-50%) kein Text, LOD 2 (<20%) nur farbige Rechtecke. content-visibility: auto fuer browser-natives rendering-culling.
…sserungen - ? oeffnet keyboard-shortcuts-hilfe-dialog mit allen shortcuts - png-export-button im header (canvas-basiert, 2x aufloesung) - node-enter-animation (scale-in) fuer visuelles feedback - prefers-reduced-motion respektierung global - responsive toolbar-positionierung fuer mobile (768px breakpoint)
- websocket rate-limiting (60 msg/s pro verbindung) im yjs-server - /health endpoint fuer container-monitoring - security-header (x-content-type-options, x-frame-options, referrer-policy) - docker-compose health-checks fuer db, api mit ordentlichem depends_on
…ache - Protocol Buffers Schema (board, node, viewport, common) mit buf v2 - Connect-Fastify Integration neben bestehendem tRPC - Auth-Interceptor mit Cookie-basierter Session-Validierung - Huffman-Tree-inspirierte Viewport-Klassifizierung (Hot/Warm/Cold) - Angular Client: Transport, ViewportSync mit Debounce/AbortController - OPFS-primärer KV-Store mit IndexedDB-Fallback - @tapiz/proto Pfad-Alias für saubere Imports
…-härtung - XSS: DOMPurify für innerHTML in NoteHeightCalculator und SafeHtmlPipe - Validierung: URL-Protokoll-Einschränkung (http/https), Array-Limits für votes/emojis/drawing - Auth: BETTER_AUTH_SECRET Startup-Validierung - Security-Headers: CSP, HSTS, Permissions-Policy - DB: Pool von 20→50 mit max_lifetime, Transactions für createBoard/deleteBoard - Yjs: LRU-Cache (200 Docs, 10min TTL), Heartbeat für tote WebSocket-Verbindungen - N+1 Query: getBoardAdmins optimiert (direkte DB-Abfrage statt team-db Hilfsfunktion) - tRPC: v11-Kompatibilität (getRawInput, Client-Upgrade) - Docker: Postgres auf 127.0.0.1 gebunden
…ests - applyAction: O(1) Patch statt O(n) map() — nur geändertes Node wird kopiert - syncNodeBox: redundanten Array-Spread bei setState entfernt (doppelte Kopie) - Performance-Test: 100 Patches auf 500 Nodes in <50ms, Referenz-Identität geprüft - DB-Migration 0009: Indizes für accounts_boards, starreds, team_members, boards, notifications - Validierungs-Tests: 16 Tests für note.validator (Array-Limits) und image.validator (URL-Protokoll) - Test-Infrastruktur: vitest für board-commons Library aufgesetzt
- 7 DB-Tests: createBoard/deleteBoard Transactions, getBoardAdmins, haveAccess - 7 viewport-sync Tests: Hot/Warm/Cold-Klassifizierung, Zoom, Performance (500 Nodes <10ms) - Gesamtzahl Tests: 19 sync-node-box + 16 Validierung + 14 API = 49 neue Tests
Axum + Tokio + Yrs (Yjs-CRDT) + DashMap für lock-free Concurrency. - Auth: Session-Validierung direkt gegen Better Auth DB - Yjs: RoomManager mit LRU-Cache (200 Docs, 10min TTL), periodischer Persistenz (30s) - Presence: Cursor/Viewport-Broadcasting mit Heartbeat-Cleanup - Viewport: Spatial-Klassifizierung (hot/warm/cold) für Node-Culling - WebSocket: Ping/Pong Heartbeat (30s), Broadcast via tokio::sync::broadcast - Release-Binary: 4.7MB (LTO, strip, codegen-units=1)
- R*-Tree (rstar): O(log n) viewport-queries statt O(n) brute-force - SpatialManager pro Board, hot/warm/cold node-klassifizierung - Bulk-load 10k Nodes <100ms, Query <5ms (Performance-Test) - vectis-crdt: domain-spezifisches CRDT für Whiteboard-Strokes - Deterministische Z-Order via RGA/YATA-Sequenz - LWW-Register pro Property (Color, Width, Opacity, Transform) - Awareness-Protokoll mit 15s Cursor-TTL - Snapshot-Persistenz und Cross-Replica-Konvergenz - 13 Unit-Tests (7 Spatial + 6 CRDT)
- SpatialIndexService: rbush-basierter R-tree für O(log n) Queries
- bulkLoad bei Node-State-Änderungen, queryViewport bei Zoom/Pan
- Ersetzt O(n) Array-Filter in NodesComponent
- Viewport-Query REST-Endpoint im Rust-Backend
- POST /api/board/{id}/viewport-query → hot/warm Node-IDs
- Angular effect() hält Index synchron mit Board-State
…ion limits - Graceful Shutdown: SIGTERM/SIGINT persistiert alle dirty Rooms vor dem Exit - Rate Limiting: Token-Bucket pro Connection (120 Yjs-Ops/s, 30 Cursor/s) - Connection Limits: MAX_CONNECTIONS_PER_BOARD (default 100), 503 bei Überschreitung - Metrics: Prometheus-kompatibel /metrics (active_connections, active_rooms) - Message Size Limits: 512KB Yjs, 64KB Presence - Connection Counter: AtomicU64 für globales Connection-Tracking - 15 Unit-Tests (2 neue Rate-Limit-Tests)
Owner
|
Hi, and thanks for your interest in Tapiz. At the moment, I can’t accept this PR in its current form. If you want to propose new features for Tapiz, please open a separate issue for each feature first and wait for approval, so I can decide whether it is appropriate for the project. Once a feature/fix has been discussed and approved, you can then open a PR for it. Also, PRs should be limited to a single feature only, and all commits and comments must be written in English. Thanks for understanding. |
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
This PR brings the dependency stack up to date, replaces the deprecated Lucia auth library with Better Auth, and includes targeted performance improvements for high-concurrency collaborative sessions.
Changes
Security & Stability Fixes (
fix(api))origin: truewithorigin: process.env['FRONTEND_URL']— only the configured frontend origin is allowed for tRPC REST endpoints (Socket.IO already had its own restricted CORS)secureandsameSite: 'lax'to OAuth state/code_verifier cookies in productionemptyBoard()now also clears theboardSettingscache to prevent stale read-only settings persisting after a board closesuserJoin()uses spread instead of in-place array mutationsetTimeout(() => socket.conn.close())fromclient.tsTipTap
3.0.0-beta.16→3.20.1(chore(deps))All 20
@tiptap/*packages updated from beta to stable 3.x.API fixes:
tippyOptions: {}from customBubbleMenu.addOptions()— the project uses@floating-ui/dominstead of tippy, so this field is not part of the typesetContentnow passes{ emitUpdate: false }matching the newSetContentOptionstype (prevents potential update loops)@tiptap/suggestion@^3.20.1as explicit dependency (required peer dep forextension-mention@3.x)server.connection()cookie type:Record<string, string | undefined>matchingcookie@1.xparse return typeDrizzle
0.28.6→0.45.1+ drizzle-kit0.19.13→0.31.9(chore(deps))drizzle.config.ts: replaced deprecateddriver: 'pg'+breakpointswithdefineConfig()+dialect: 'postgresql'drizzle-kit upto upgrade migration snapshot formatAuth: Lucia v3 → Better Auth 1.5 (
feat(auth))Lucia v3 was officially deprecated in March 2025. This PR replaces it with Better Auth (MIT).
Design: Better Auth is configured with its Drizzle adapter mapped to the existing database tables (
accountsas user table,account_sessionas session table), preserving all foreign key relationships to boards, teams, and invitations without breaking changes.Schema additions (migration
0008):accounts:email_verified,created_at,updated_ataccount_session:token(unique),created_at,updated_at,ip_address,user_agentoauth_accounts: stores OAuth provider account links (replacesaccounts.google_id)verification: for future email OTP / magic link flowsMigration safety:
accounts.google_id→oauth_accountsOther changes:
arcticand@lucia-auth/adapter-postgresqlremoved/api/auth/callback/google) is now handled automatically by Better Auth via a Fastify wildcard route (/api/auth/*) with a scoped content-type parserauth.api.getSession()with 5-minute cookie cache — eliminates per-request DB session lookups in tRPC contextlucia.invalidateUserSessions→getAuth().api.revokeUserSessionsin logout/account deletionPerformance: high-concurrency boards (
perf(api))Targeted optimizations for scenarios with many simultaneous users on a single board:
postgres({ max: 20, idle_timeout: 30 })Array.find()per incoming board messagepingTimeout: 15s / pingInterval: 10smaxHttpBufferSize: 5MBclose()optimizationfindIndex+ targeted splice instead of fullmap()scan over all board nodesNote: cursor moves already bypass full validation via the existing
broadcastmessage type — no change needed there.Test Plan
sync-node-box,webvitest suites)apiandwebproduction builds succeed with no TypeScript errorsFor manual verification after deploying migration
0008: