diff --git a/src/backend/main.py b/src/backend/main.py
index 06f56bf..a9d2f1d 100644
--- a/src/backend/main.py
+++ b/src/backend/main.py
@@ -6,7 +6,17 @@
from fastapi.responses import FileResponse
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
-from fastapi.templating import Jinja2Templates
+from dotenv import load_dotenv
+import posthog
+
+load_dotenv()
+
+POSTHOG_API_KEY = os.environ.get("VITE_PUBLIC_POSTHOG_KEY")
+POSTHOG_HOST = os.environ.get("VITE_PUBLIC_POSTHOG_HOST")
+
+if POSTHOG_API_KEY:
+ posthog.project_api_key = POSTHOG_API_KEY
+ posthog.host = POSTHOG_HOST
from db import init_db
from config import STATIC_DIR, ASSETS_DIR
@@ -33,7 +43,6 @@ async def lifespan(_: FastAPI):
allow_headers=["*"],
)
-print("ASSETS_DIR", ASSETS_DIR)
app.mount("/assets", StaticFiles(directory=ASSETS_DIR), name="assets")
@app.get("/")
diff --git a/src/backend/requirements.txt b/src/backend/requirements.txt
index 9cec4fc..a222b75 100644
--- a/src/backend/requirements.txt
+++ b/src/backend/requirements.txt
@@ -6,4 +6,5 @@ asyncpg
python-dotenv
PyJWT
requests
-sqlalchemy
\ No newline at end of file
+sqlalchemy
+posthog
diff --git a/src/backend/routers/canvas.py b/src/backend/routers/canvas.py
index 18b93a1..5beaeef 100644
--- a/src/backend/routers/canvas.py
+++ b/src/backend/routers/canvas.py
@@ -1,11 +1,12 @@
import json
import jwt
from typing import Dict, Any
-from fastapi import APIRouter, HTTPException, Depends
+from fastapi import APIRouter, HTTPException, Depends, Request
from fastapi.responses import JSONResponse
from dependencies import SessionData, require_auth
from db import store_canvas_data, get_canvas_data
+import posthog
canvas_router = APIRouter()
@@ -19,14 +20,49 @@ def get_default_canvas_data():
detail=f"Failed to load default canvas: {str(e)}"
)
+@canvas_router.get("/default")
+async def get_default_canvas(auth: SessionData = Depends(require_auth)):
+ try:
+ with open("default_canvas.json", "r") as f:
+ canvas_data = json.load(f)
+ return canvas_data
+ except Exception as e:
+ return JSONResponse(
+ status_code=500,
+ content={"error": f"Failed to load default canvas: {str(e)}"}
+ )
+
@canvas_router.post("")
-async def save_canvas(data: Dict[str, Any], auth: SessionData = Depends(require_auth)):
+async def save_canvas(data: Dict[str, Any], auth: SessionData = Depends(require_auth), request: Request = None):
access_token = auth.token_data.get("access_token")
decoded = jwt.decode(access_token, options={"verify_signature": False})
user_id = decoded["sub"]
success = await store_canvas_data(user_id, data)
if not success:
raise HTTPException(status_code=500, detail="Failed to save canvas data")
+ # PostHog analytics: capture canvas_saved event
+ try:
+ app_state = data.get("appState", {})
+ width = app_state.get("width")
+ height = app_state.get("height")
+ zoom = app_state.get("zoom", {}).get("value")
+ api_path = str(request.url.path) if request else None
+ full_url = None
+ if request:
+ full_url = str(request.base_url).rstrip("/") + str(request.url.path)
+ posthog.capture(
+ distinct_id=user_id,
+ event="canvas_saved",
+ properties={
+ "pad_width": width,
+ "pad_height": height,
+ "pad_zoom": zoom,
+ "$current_url": full_url,
+ }
+ )
+ except Exception as e:
+ print(f"Error capturing canvas_saved event: {str(e)}")
+ pass
return {"status": "success"}
@canvas_router.get("")
diff --git a/src/backend/routers/user.py b/src/backend/routers/user.py
index e4e89fb..ebe6223 100644
--- a/src/backend/routers/user.py
+++ b/src/backend/routers/user.py
@@ -1,5 +1,6 @@
import jwt
from fastapi import APIRouter, Depends
+import posthog
from dependencies import SessionData, require_auth
@@ -11,6 +12,19 @@ async def get_user_info(auth: SessionData = Depends(require_auth)):
access_token = token_data.get("access_token")
decoded = jwt.decode(access_token, options={"verify_signature": False})
+
+ # Identify user in PostHog (mirrors frontend identify)
+ posthog.identify(
+ distinct_id=decoded["sub"],
+ properties={
+ "email": decoded.get("email", ""),
+ "username": decoded.get("preferred_username", ""),
+ "name": decoded.get("name", ""),
+ "given_name": decoded.get("given_name", ""),
+ "family_name": decoded.get("family_name", ""),
+ "email_verified": decoded.get("email_verified", False)
+ }
+ )
return {
"id": decoded["sub"], # Unique user ID
@@ -20,4 +34,4 @@ async def get_user_info(auth: SessionData = Depends(require_auth)):
"given_name": decoded.get("given_name", ""),
"family_name": decoded.get("family_name", ""),
"email_verified": decoded.get("email_verified", False)
- }
+ }
\ No newline at end of file
diff --git a/src/frontend/excalidraw-patch.js b/src/frontend/excalidraw-patch.js
deleted file mode 100644
index b8065fa..0000000
--- a/src/frontend/excalidraw-patch.js
+++ /dev/null
@@ -1,35 +0,0 @@
-// Patch Excalidraw to allow same-origin for all embedded content
-(function() {
-
- // Patch at the prototype level to affect all future iframe instances
- const patchIframePrototype = () => {
- try {
- const originalSetAttribute = HTMLIFrameElement.prototype.setAttribute;
-
- // Override the setAttribute method for iframes
- HTMLIFrameElement.prototype.setAttribute = function(name, value) {
- if (name === 'sandbox' && !value.includes('allow-same-origin')) {
- value = value + ' allow-same-origin';
- console.debug("Intercepted iframe setAttribute for sandbox, added allow-same-origin");
- }
-
- return originalSetAttribute.call(this, name, value);
- };
-
- console.debug("Patched HTMLIFrameElement.prototype.setAttribute");
- } catch (e) {
- console.error("Failed to patch iframe prototype:", e);
- }
- };
-
- // Initialize immediately if document is already loaded
- if (document.readyState === 'complete' || document.readyState === 'interactive') {
- patchIframePrototype();
- } else {
- // Otherwise wait for the DOM to be ready
- window.addEventListener('DOMContentLoaded', patchIframePrototype);
- }
-
- // Also initialize on load to be sure
- window.addEventListener('load', patchIframePrototype);
-})();
diff --git a/src/frontend/index.html b/src/frontend/index.html
index 649859c..c9f0a91 100644
--- a/src/frontend/index.html
+++ b/src/frontend/index.html
@@ -21,7 +21,6 @@
window.ExcalidrawLib = ExcalidrawLib;
-