-
Notifications
You must be signed in to change notification settings - Fork 0
Code Modifications
This page covers all the necessary code changes required to make TableSlayer work in a self-hosted environment. These modifications fixed critical bugs and ensure proper integration with your services. These changes have all been implemented in this codebase :)
This fixes the "foreign key constraint" error when users sign up with Google OAuth.
File: apps/web/src/lib/server/user/index.ts
Location: Around line 407, in the createOrUpdateGoogleUser function
Change From:
await db.insert(usersTable).values({
id: userId,
name,
email,
googleId,
emailVerified: true,
passwordHash: null
});Change To:
await db.insert(usersTable).values({
id: userId,
name,
email,
googleId,
emailVerified: true,
passwordHash: null,
avatarFileId: null // Add this line - critical fix!
});This makes the avatarFileId field nullable to prevent constraint errors.
File: apps/web/src/lib/db/app/schema.ts
Location: Around line 22, in the usersTable definition
Change From:
avatarFileId: integer('avatar_file_id')
.references(() => filesTable.id, { onDelete: 'cascade' })
.notNull()
.default(1),Change To:
avatarFileId: integer('avatar_file_id')
.references(() => filesTable.id, { onDelete: 'cascade' }),After making the schema change, generate a migration:
cd apps/web
pnpm run generateThis creates a migration file that makes avatarFileId nullable.
This ensures fog of war, annotations, and other properties sync properly between admin UI and playfield.
File: apps/web/src/routes/(app)/[party]/play/+page@.svelte
Location: Around line 114, in the Y.js data processing section
Ensure these properties are included:
stageProps = {
...yjsSceneData.stageProps,
// Force player mode
mode: 1,
// Build scene from scratch
scene: {
autoFit: true,
offset: { x: 0, y: 0 },
rotation: 0,
zoom: stageProps.scene?.zoom || 1
},
// Don't allow active layer (fog tools, etc)
activeLayer: MapLayerType.None,
// Filter markers to remove DM-only ones
marker: {
...yjsSceneData.stageProps.marker,
markers: (yjsSceneData.stageProps.marker?.markers || []).filter((m: Marker) => m.visibility !== 1)
},
// Include fog of war data for proper synchronization
fogOfWar: {
...yjsSceneData.stageProps.fogOfWar
},
// Include annotations for proper synchronization
annotations: {
...yjsSceneData.stageProps.annotations
},
// Include map settings for proper synchronization
map: {
...yjsSceneData.stageProps.map
},
// Include display settings for proper synchronization
display: {
...yjsSceneData.stageProps.display
},
// Include grid settings for proper synchronization
grid: {
...yjsSceneData.stageProps.grid
}
};The hardcoded URLs have been replaced with configurable ones. Verify these files use environment variables properly:
Files to check:
-
apps/web/src/lib/server/oauth.ts- OAuth callback URLs -
apps/web/src/lib/server/file/transform.ts- File transformation URLs -
apps/web/src/lib/utils/generateR2Url.ts- R2 URL generation
These should now use placeholders like https://your-domain.com and https://your-r2-domain.com that get replaced by environment variables.
The repository includes memory optimizations for better production performance.
These are already configured in your repo:
-
package.json: Start script uses 4GB Node.js heap -
DockerfileWeb: Runtime environment includes memory settings -
docker-compose.yml: Container memory limits set to 6GB
File: DockerfileWeb (repository root)
This file is already configured with:
- Node.js 22 base image
- 4GB memory allocation for builds
- Production environment variables
- Proper monorepo build handling
File: apps/web/deployment/docker-compose.yml
This file includes:
- Health checks for monitoring
- Memory limits (6GB container, 4GB guaranteed)
- Volume mounts for logs
- Network isolation
File: apps/web/deployment/.env.example
Create a .env.example file with these variables (values will be filled in during configuration):
# Database Configuration
TURSO_API_TOKEN=your_turso_api_token
TURSO_APP_DB_AUTH_TOKEN=your_turso_db_auth_token
TURSO_APP_DB_URL=libsql://your-db-name.aws-eu-west-1.turso.io
# Email Configuration
RESEND_TOKEN=your_resend_api_key
DEV_EMAIL=your-email@yourdomain.com
# Cloudflare R2 Configuration
CLOUDFLARE_ACCOUNT_ID=your_cloudflare_account_id
CLOUDFLARE_R2_ACCESS_KEY=your_r2_access_key
CLOUDFLARE_R2_SECRET_KEY=your_r2_secret_key
CLOUDFLARE_R2_BUCKET_NAME=your-bucket-name
CLOUDFLARE_R2_PUBLIC_URL=https://files.yourdomain.com
PUBLIC_CLOUDFLARE_R2_URL=https://files.yourdomain.com
# Application Configuration
BASE_URL=https://yourdomain.com
BODY_SIZE_LIMIT=20M
# Google OAuth Configuration
GOOGLE_CLIENT_SECRET=your_google_client_secret
GOOGLE_CLIENT_ID=your_google_client_id
# PartyKit Configuration
PUBLIC_PARTYKIT_HOST=your-partykit-deployment.partykit.dev
# Optional: Stripe Configuration (use dummy values if not using payments)
STRIPE_API_KEY=sk_test_dummy_key_for_build_purposes
STRIPE_WEBHOOK_KEY=
STRIPE_PRICE_ID_LIFETIME=
STRIPE_PRICE_ID_MONTHLY=
STRIPE_PRICE_ID_YEARLY=Since the codebase contains hardcoded asset URLs, you have several options:
Most dynamic assets will work with proper environment configuration:
PUBLIC_CLOUDFLARE_R2_URL=https://files.yourdomain.comIf you want complete control, use find/replace to update all hardcoded URLs:
# In your repository
find . -type f \( -name "*.svelte" -o -name "*.ts" -o -name "*.js" \) \
-exec sed -i 's/https:\/\/files\.tableslayer\.com/https:\/\/files.yourdomain.com/g' {} \;Set up a proxy or CDN to serve the original assets without code changes.
See Asset Configuration for detailed guidance.
After making all code modifications, verify your changes:
cd apps/web
pnpm run check
pnpm run tscpnpm run build# Generate migration to see changes
pnpm run generate
# Check migration file looks correct
cat drizzle/migrations/latest_migration.sql# Create a self-hosting branch
git checkout -b self-hosting
# Stage all changes
git add .
# Commit with descriptive message
git commit -m "Apply self-hosting modifications
- Fix Google OAuth avatarFileId constraint error
- Make avatarFileId nullable in schema
- Fix real-time sync for fog/annotations
- Update hardcoded URLs for self-hosting
- Add memory optimizations
- Add production Docker configuration"Problem: Type errors after schema changes
Solution: Run pnpm run tsc to check specific errors and fix imports
Problem: Build fails with memory errors
Solution: Memory optimizations are included, ensure Docker has enough resources allocated
Problem: Package installation fails
Solution: Delete node_modules and pnpm-lock.yaml, then run pnpm install
Problem: Migration doesn't reflect changes
Solution: Delete existing migration files and regenerate with pnpm run generate
Before deployment, test critical functionality:
# Start local development
cd apps/web
pnpm run dev
# Test in browser:
# - User signup with Google OAuth
# - Scene creation and editing
# - Real-time sync between tabs# Build production version
pnpm run build
# Test production build locally
pnpm run startOnce all code modifications are complete and tested, proceed to Configuration to set up your production environment variables.