refactor: move supabase config to repo root, fix port and env setup
- Move supabase/ from packages/db/ to repo root for simpler CLI usage - Use custom ports (553xx) to avoid conflicts with other local Supabase instances - Add --env-mode=loose to turbo dev so root .env vars reach Next.js - Remove hardcoded --port 3000 from next dev (reads PORT env var instead) - Add .env.example with Supabase env var placeholders - Add supabase local state dirs to .gitignore Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
f1077ad1c8
commit
aa27e0dd7a
@@ -0,0 +1,43 @@
|
||||
# Supabase local development configuration
|
||||
# This file is used by `supabase start` for local development
|
||||
|
||||
project_id = "pascal-editor"
|
||||
|
||||
[api]
|
||||
enabled = true
|
||||
port = 55321
|
||||
schemas = ["public"]
|
||||
extra_search_path = ["public"]
|
||||
max_rows = 1000
|
||||
|
||||
[db]
|
||||
port = 55322
|
||||
shadow_port = 55320
|
||||
major_version = 17
|
||||
|
||||
[studio]
|
||||
enabled = true
|
||||
port = 55323
|
||||
|
||||
[inbucket]
|
||||
enabled = true
|
||||
port = 55324
|
||||
smtp_port = 55325
|
||||
pop3_port = 55326
|
||||
|
||||
[analytics]
|
||||
enabled = true
|
||||
port = 55328
|
||||
backend = "postgres"
|
||||
|
||||
[auth]
|
||||
enabled = true
|
||||
site_url = "http://localhost:3000"
|
||||
additional_redirect_urls = ["http://localhost:3000"]
|
||||
jwt_expiry = 3600
|
||||
enable_signup = true
|
||||
|
||||
[auth.email]
|
||||
enable_signup = true
|
||||
double_confirm_changes = false
|
||||
enable_confirmations = false
|
||||
@@ -0,0 +1,80 @@
|
||||
-- Better Auth tables (copied from working monorepo)
|
||||
-- Using auth_ prefix and snake_case columns
|
||||
|
||||
CREATE TYPE "public"."auth_user_roles" AS ENUM('user', 'admin');
|
||||
|
||||
CREATE TABLE "auth_accounts" (
|
||||
"id" text PRIMARY KEY NOT NULL,
|
||||
"user_id" text NOT NULL,
|
||||
"provider_id" text NOT NULL,
|
||||
"account_id" text NOT NULL,
|
||||
"password" text,
|
||||
"access_token" text,
|
||||
"refresh_token" text,
|
||||
"id_token" text,
|
||||
"access_token_expires_at" timestamp with time zone,
|
||||
"refresh_token_expires_at" timestamp with time zone,
|
||||
"scope" text,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE "auth_accounts" ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
CREATE TABLE "auth_jwks" (
|
||||
"id" text PRIMARY KEY NOT NULL,
|
||||
"public_key" text NOT NULL,
|
||||
"private_key" text NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE "auth_jwks" ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
CREATE TABLE "auth_sessions" (
|
||||
"id" text PRIMARY KEY NOT NULL,
|
||||
"user_id" text NOT NULL,
|
||||
"expires_at" timestamp with time zone,
|
||||
"token" text NOT NULL,
|
||||
"ip_address" text,
|
||||
"user_agent" text,
|
||||
"impersonated_by" text,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE "auth_sessions" ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
CREATE TABLE "auth_users" (
|
||||
"id" text PRIMARY KEY NOT NULL,
|
||||
"email" text NOT NULL,
|
||||
"email_verified" boolean DEFAULT false NOT NULL,
|
||||
"name" text NOT NULL,
|
||||
"image" text,
|
||||
"role" "auth_user_roles" DEFAULT 'user' NOT NULL,
|
||||
"banned" boolean DEFAULT false NOT NULL,
|
||||
"ban_reason" text,
|
||||
"ban_expires" timestamp with time zone,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE "auth_users" ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
CREATE TABLE "auth_verifications" (
|
||||
"id" text PRIMARY KEY NOT NULL,
|
||||
"value" text NOT NULL,
|
||||
"identifier" text NOT NULL,
|
||||
"expires_at" timestamp with time zone,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE "auth_verifications" ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
ALTER TABLE "auth_accounts" ADD CONSTRAINT "auth_accounts_user_id_auth_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."auth_users"("id") ON DELETE cascade ON UPDATE no action;
|
||||
|
||||
ALTER TABLE "auth_sessions" ADD CONSTRAINT "auth_sessions_user_id_auth_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."auth_users"("id") ON DELETE cascade ON UPDATE no action;
|
||||
|
||||
ALTER TABLE "auth_sessions" ADD CONSTRAINT "auth_sessions_impersonated_by_auth_users_id_fk" FOREIGN KEY ("impersonated_by") REFERENCES "public"."auth_users"("id") ON DELETE set null ON UPDATE no action;
|
||||
|
||||
CREATE UNIQUE INDEX "email_unique_index" ON "auth_users" USING btree (lower("email"));
|
||||
@@ -0,0 +1,165 @@
|
||||
-- Properties tables
|
||||
-- Simple property management without organizations
|
||||
|
||||
-- Properties addresses table (must be created first due to foreign key)
|
||||
CREATE TABLE IF NOT EXISTS properties_addresses (
|
||||
id TEXT PRIMARY KEY,
|
||||
street_number TEXT,
|
||||
route TEXT,
|
||||
route_short TEXT,
|
||||
neighborhood TEXT,
|
||||
city TEXT,
|
||||
county TEXT,
|
||||
state TEXT,
|
||||
state_long TEXT,
|
||||
postal_code TEXT,
|
||||
postal_code_suffix TEXT,
|
||||
country TEXT,
|
||||
country_long TEXT,
|
||||
latitude NUMERIC,
|
||||
longitude NUMERIC,
|
||||
raw_json JSONB,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
UNIQUE(street_number, route, city, state, postal_code)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_properties_addresses_city_state ON properties_addresses(city, state);
|
||||
|
||||
-- Properties table
|
||||
CREATE TABLE IF NOT EXISTS properties (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT,
|
||||
address_id TEXT UNIQUE REFERENCES properties_addresses(id) ON DELETE SET NULL,
|
||||
owner_id TEXT REFERENCES auth_users(id) ON DELETE SET NULL,
|
||||
details_json JSONB,
|
||||
metadata JSONB,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_properties_owner_id ON properties(owner_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_properties_address_id ON properties(address_id);
|
||||
|
||||
-- Properties models table (scene graphs)
|
||||
CREATE TABLE IF NOT EXISTS properties_models (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT,
|
||||
version INTEGER DEFAULT 1,
|
||||
description TEXT,
|
||||
draft BOOLEAN DEFAULT true,
|
||||
property_id TEXT REFERENCES properties(id) ON DELETE SET NULL,
|
||||
scene_graph JSONB,
|
||||
metadata JSONB,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
deleted_at TIMESTAMPTZ
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_properties_models_property_id ON properties_models(property_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_properties_models_version ON properties_models(property_id, version DESC);
|
||||
|
||||
-- Enable Row Level Security (RLS)
|
||||
ALTER TABLE properties ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE properties_addresses ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE properties_models ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- RLS Policies for properties table
|
||||
CREATE POLICY "Users can view their own properties"
|
||||
ON properties FOR SELECT
|
||||
USING (owner_id = current_setting('app.user_id', true)::TEXT OR owner_id IS NULL);
|
||||
|
||||
CREATE POLICY "Users can insert their own properties"
|
||||
ON properties FOR INSERT
|
||||
WITH CHECK (owner_id = current_setting('app.user_id', true)::TEXT OR owner_id IS NULL);
|
||||
|
||||
CREATE POLICY "Users can update their own properties"
|
||||
ON properties FOR UPDATE
|
||||
USING (owner_id = current_setting('app.user_id', true)::TEXT OR owner_id IS NULL);
|
||||
|
||||
CREATE POLICY "Users can delete their own properties"
|
||||
ON properties FOR DELETE
|
||||
USING (owner_id = current_setting('app.user_id', true)::TEXT OR owner_id IS NULL);
|
||||
|
||||
-- RLS Policies for properties_addresses table
|
||||
-- Addresses table doesn't have property_id, so we'll allow all authenticated users
|
||||
CREATE POLICY "Authenticated users can view all addresses"
|
||||
ON properties_addresses FOR SELECT
|
||||
USING (true);
|
||||
|
||||
CREATE POLICY "Authenticated users can insert addresses"
|
||||
ON properties_addresses FOR INSERT
|
||||
WITH CHECK (true);
|
||||
|
||||
CREATE POLICY "Authenticated users can update addresses"
|
||||
ON properties_addresses FOR UPDATE
|
||||
USING (true);
|
||||
|
||||
CREATE POLICY "Authenticated users can delete addresses"
|
||||
ON properties_addresses FOR DELETE
|
||||
USING (true);
|
||||
|
||||
-- RLS Policies for properties_models table
|
||||
CREATE POLICY "Users can view models of their own properties"
|
||||
ON properties_models FOR SELECT
|
||||
USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM properties
|
||||
WHERE properties.id = properties_models.property_id
|
||||
AND properties.owner_id = current_setting('app.user_id', true)::TEXT
|
||||
)
|
||||
);
|
||||
|
||||
CREATE POLICY "Users can insert models for their own properties"
|
||||
ON properties_models FOR INSERT
|
||||
WITH CHECK (
|
||||
EXISTS (
|
||||
SELECT 1 FROM properties
|
||||
WHERE properties.id = properties_models.property_id
|
||||
AND properties.owner_id = current_setting('app.user_id', true)::TEXT
|
||||
)
|
||||
);
|
||||
|
||||
CREATE POLICY "Users can update models of their own properties"
|
||||
ON properties_models FOR UPDATE
|
||||
USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM properties
|
||||
WHERE properties.id = properties_models.property_id
|
||||
AND properties.owner_id = current_setting('app.user_id', true)::TEXT
|
||||
)
|
||||
);
|
||||
|
||||
CREATE POLICY "Users can delete models of their own properties"
|
||||
ON properties_models FOR DELETE
|
||||
USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM properties
|
||||
WHERE properties.id = properties_models.property_id
|
||||
AND properties.owner_id = current_setting('app.user_id', true)::TEXT
|
||||
)
|
||||
);
|
||||
|
||||
-- Trigger to update updated_at timestamp
|
||||
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = NOW();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER update_properties_updated_at
|
||||
BEFORE UPDATE ON properties
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
CREATE TRIGGER update_properties_addresses_updated_at
|
||||
BEFORE UPDATE ON properties_addresses
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
CREATE TRIGGER update_properties_models_updated_at
|
||||
BEFORE UPDATE ON properties_models
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
@@ -0,0 +1,2 @@
|
||||
-- Add active_property_id to sessions table
|
||||
ALTER TABLE auth_sessions ADD COLUMN IF NOT EXISTS active_property_id TEXT;
|
||||
@@ -0,0 +1,13 @@
|
||||
-- Add community features to properties table
|
||||
ALTER TABLE properties ADD COLUMN IF NOT EXISTS is_private BOOLEAN NOT NULL DEFAULT true;
|
||||
ALTER TABLE properties ADD COLUMN IF NOT EXISTS views INTEGER NOT NULL DEFAULT 0;
|
||||
ALTER TABLE properties ADD COLUMN IF NOT EXISTS likes INTEGER NOT NULL DEFAULT 0;
|
||||
ALTER TABLE properties ADD COLUMN IF NOT EXISTS thumbnail_url TEXT;
|
||||
|
||||
-- Create indexes for community queries
|
||||
CREATE INDEX IF NOT EXISTS idx_properties_is_private ON properties(is_private) WHERE is_private = false;
|
||||
CREATE INDEX IF NOT EXISTS idx_properties_views ON properties(views DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_properties_likes ON properties(likes DESC);
|
||||
|
||||
-- Set existing properties to private (user opt-in to share)
|
||||
UPDATE properties SET is_private = true WHERE is_private IS NULL;
|
||||
@@ -0,0 +1,78 @@
|
||||
-- Drop existing RLS policies for properties
|
||||
DROP POLICY IF EXISTS "Users can view their own properties" ON properties;
|
||||
DROP POLICY IF EXISTS "Users can insert their own properties" ON properties;
|
||||
DROP POLICY IF EXISTS "Users can update their own properties" ON properties;
|
||||
DROP POLICY IF EXISTS "Users can delete their own properties" ON properties;
|
||||
|
||||
-- New RLS policy: Users can view their own properties OR public properties
|
||||
CREATE POLICY "Users can view own or public properties"
|
||||
ON properties FOR SELECT
|
||||
USING (
|
||||
owner_id = current_setting('app.user_id', true)::TEXT
|
||||
OR is_private = false
|
||||
OR owner_id IS NULL
|
||||
);
|
||||
|
||||
-- Keep other policies the same (insert/update/delete still require ownership)
|
||||
CREATE POLICY "Users can insert their own properties"
|
||||
ON properties FOR INSERT
|
||||
WITH CHECK (owner_id = current_setting('app.user_id', true)::TEXT OR owner_id IS NULL);
|
||||
|
||||
CREATE POLICY "Users can update their own properties"
|
||||
ON properties FOR UPDATE
|
||||
USING (owner_id = current_setting('app.user_id', true)::TEXT OR owner_id IS NULL);
|
||||
|
||||
CREATE POLICY "Users can delete their own properties"
|
||||
ON properties FOR DELETE
|
||||
USING (owner_id = current_setting('app.user_id', true)::TEXT OR owner_id IS NULL);
|
||||
|
||||
-- Drop existing RLS policies for models
|
||||
DROP POLICY IF EXISTS "Users can view models of their own properties" ON properties_models;
|
||||
DROP POLICY IF EXISTS "Users can insert models for their own properties" ON properties_models;
|
||||
DROP POLICY IF EXISTS "Users can update models of their own properties" ON properties_models;
|
||||
DROP POLICY IF EXISTS "Users can delete models of their own properties" ON properties_models;
|
||||
|
||||
-- Update models policy: Users can view models of their own properties OR public properties
|
||||
CREATE POLICY "Users can view models of own or public properties"
|
||||
ON properties_models FOR SELECT
|
||||
USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM properties
|
||||
WHERE properties.id = properties_models.property_id
|
||||
AND (
|
||||
properties.owner_id = current_setting('app.user_id', true)::TEXT
|
||||
OR properties.is_private = false
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
-- Keep other model policies the same
|
||||
CREATE POLICY "Users can insert models for their own properties"
|
||||
ON properties_models FOR INSERT
|
||||
WITH CHECK (
|
||||
EXISTS (
|
||||
SELECT 1 FROM properties
|
||||
WHERE properties.id = properties_models.property_id
|
||||
AND properties.owner_id = current_setting('app.user_id', true)::TEXT
|
||||
)
|
||||
);
|
||||
|
||||
CREATE POLICY "Users can update models of their own properties"
|
||||
ON properties_models FOR UPDATE
|
||||
USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM properties
|
||||
WHERE properties.id = properties_models.property_id
|
||||
AND properties.owner_id = current_setting('app.user_id', true)::TEXT
|
||||
)
|
||||
);
|
||||
|
||||
CREATE POLICY "Users can delete models of their own properties"
|
||||
ON properties_models FOR DELETE
|
||||
USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM properties
|
||||
WHERE properties.id = properties_models.property_id
|
||||
AND properties.owner_id = current_setting('app.user_id', true)::TEXT
|
||||
)
|
||||
);
|
||||
@@ -0,0 +1,9 @@
|
||||
-- Function to atomically increment view count
|
||||
CREATE OR REPLACE FUNCTION increment_property_views(property_id TEXT)
|
||||
RETURNS void AS $$
|
||||
BEGIN
|
||||
UPDATE properties
|
||||
SET views = views + 1
|
||||
WHERE id = property_id;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
@@ -0,0 +1,41 @@
|
||||
-- Create property_likes table to track user likes
|
||||
CREATE TABLE IF NOT EXISTS property_likes (
|
||||
id TEXT PRIMARY KEY,
|
||||
property_id TEXT NOT NULL REFERENCES properties(id) ON DELETE CASCADE,
|
||||
user_id TEXT NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
|
||||
-- Ensure a user can only like a property once
|
||||
UNIQUE(property_id, user_id)
|
||||
);
|
||||
|
||||
-- Enable RLS
|
||||
ALTER TABLE property_likes ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- RLS Policies
|
||||
-- Users can view all likes (to see like counts)
|
||||
CREATE POLICY "Anyone can view likes"
|
||||
ON property_likes FOR SELECT
|
||||
USING (true);
|
||||
|
||||
-- Users can insert their own likes
|
||||
CREATE POLICY "Users can create their own likes"
|
||||
ON property_likes FOR INSERT
|
||||
WITH CHECK (user_id = current_setting('app.user_id', true)::TEXT);
|
||||
|
||||
-- Users can delete their own likes
|
||||
CREATE POLICY "Users can delete their own likes"
|
||||
ON property_likes FOR DELETE
|
||||
USING (user_id = current_setting('app.user_id', true)::TEXT);
|
||||
|
||||
-- Create index for efficient querying
|
||||
CREATE INDEX IF NOT EXISTS idx_property_likes_property_id ON property_likes(property_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_property_likes_user_id ON property_likes(user_id);
|
||||
|
||||
-- Function to get like count for a property
|
||||
CREATE OR REPLACE FUNCTION get_property_like_count(property_id TEXT)
|
||||
RETURNS INTEGER AS $$
|
||||
BEGIN
|
||||
RETURN (SELECT COUNT(*)::INTEGER FROM property_likes WHERE property_likes.property_id = $1);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER STABLE;
|
||||
@@ -0,0 +1,247 @@
|
||||
-- Migration: Rename properties → projects
|
||||
-- This renames all property-related tables, columns, indexes, policies, and functions.
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- ============================================================
|
||||
-- 1. Drop existing RLS policies (they reference old table names)
|
||||
-- ============================================================
|
||||
|
||||
-- properties policies
|
||||
DROP POLICY IF EXISTS "Users can view own or public properties" ON properties;
|
||||
DROP POLICY IF EXISTS "Users can insert their own properties" ON properties;
|
||||
DROP POLICY IF EXISTS "Users can update their own properties" ON properties;
|
||||
DROP POLICY IF EXISTS "Users can delete their own properties" ON properties;
|
||||
|
||||
-- properties_addresses policies
|
||||
DROP POLICY IF EXISTS "Authenticated users can view all addresses" ON properties_addresses;
|
||||
DROP POLICY IF EXISTS "Authenticated users can insert addresses" ON properties_addresses;
|
||||
DROP POLICY IF EXISTS "Authenticated users can update addresses" ON properties_addresses;
|
||||
DROP POLICY IF EXISTS "Authenticated users can delete addresses" ON properties_addresses;
|
||||
|
||||
-- properties_models policies
|
||||
DROP POLICY IF EXISTS "Users can view models of own or public properties" ON properties_models;
|
||||
DROP POLICY IF EXISTS "Users can insert models for their own properties" ON properties_models;
|
||||
DROP POLICY IF EXISTS "Users can update models of their own properties" ON properties_models;
|
||||
DROP POLICY IF EXISTS "Users can delete models of their own properties" ON properties_models;
|
||||
|
||||
-- property_likes policies
|
||||
DROP POLICY IF EXISTS "Anyone can view likes" ON property_likes;
|
||||
DROP POLICY IF EXISTS "Users can create their own likes" ON property_likes;
|
||||
DROP POLICY IF EXISTS "Users can delete their own likes" ON property_likes;
|
||||
|
||||
-- ============================================================
|
||||
-- 2. Drop old indexes (before renaming tables)
|
||||
-- ============================================================
|
||||
|
||||
DROP INDEX IF EXISTS idx_properties_owner_id;
|
||||
DROP INDEX IF EXISTS idx_properties_address_id;
|
||||
DROP INDEX IF EXISTS idx_properties_is_private;
|
||||
DROP INDEX IF EXISTS idx_properties_views;
|
||||
DROP INDEX IF EXISTS idx_properties_likes;
|
||||
DROP INDEX IF EXISTS idx_properties_addresses_city_state;
|
||||
DROP INDEX IF EXISTS idx_properties_models_property_id;
|
||||
DROP INDEX IF EXISTS idx_properties_models_version;
|
||||
DROP INDEX IF EXISTS idx_property_likes_property_id;
|
||||
DROP INDEX IF EXISTS idx_property_likes_user_id;
|
||||
DROP INDEX IF EXISTS property_address_idx;
|
||||
DROP INDEX IF EXISTS property_owner_idx;
|
||||
DROP INDEX IF EXISTS property_is_private_idx;
|
||||
DROP INDEX IF EXISTS property_views_idx;
|
||||
DROP INDEX IF EXISTS property_likes_idx;
|
||||
|
||||
-- ============================================================
|
||||
-- 3. Drop old triggers (before renaming tables)
|
||||
-- ============================================================
|
||||
|
||||
DROP TRIGGER IF EXISTS update_properties_updated_at ON properties;
|
||||
DROP TRIGGER IF EXISTS update_properties_addresses_updated_at ON properties_addresses;
|
||||
DROP TRIGGER IF EXISTS update_properties_models_updated_at ON properties_models;
|
||||
|
||||
-- ============================================================
|
||||
-- 4. Rename tables
|
||||
-- ============================================================
|
||||
|
||||
ALTER TABLE properties_addresses RENAME TO projects_addresses;
|
||||
ALTER TABLE properties_models RENAME TO projects_models;
|
||||
ALTER TABLE property_likes RENAME TO projects_likes;
|
||||
ALTER TABLE properties RENAME TO projects;
|
||||
|
||||
-- ============================================================
|
||||
-- 5. Rename columns (property_id → project_id)
|
||||
-- ============================================================
|
||||
|
||||
ALTER TABLE projects_models RENAME COLUMN property_id TO project_id;
|
||||
ALTER TABLE projects_likes RENAME COLUMN property_id TO project_id;
|
||||
|
||||
-- Rename active_property_id in auth_sessions
|
||||
ALTER TABLE auth_sessions RENAME COLUMN active_property_id TO active_project_id;
|
||||
|
||||
-- ============================================================
|
||||
-- 6. Rename constraints
|
||||
-- ============================================================
|
||||
|
||||
-- Rename the unique constraint on projects_likes
|
||||
ALTER TABLE projects_likes RENAME CONSTRAINT "property_likes_pkey" TO "projects_likes_pkey";
|
||||
ALTER TABLE projects_likes RENAME CONSTRAINT "property_likes_property_id_fkey" TO "projects_likes_project_id_fkey";
|
||||
ALTER TABLE projects_likes RENAME CONSTRAINT "property_likes_property_id_user_id_key" TO "projects_likes_project_id_user_id_key";
|
||||
|
||||
-- ============================================================
|
||||
-- 7. Recreate indexes with new names
|
||||
-- ============================================================
|
||||
|
||||
CREATE INDEX project_address_idx ON projects(address_id);
|
||||
CREATE INDEX project_owner_idx ON projects(owner_id);
|
||||
CREATE INDEX project_is_private_idx ON projects(is_private) WHERE is_private = false;
|
||||
CREATE INDEX project_views_idx ON projects(views DESC);
|
||||
CREATE INDEX project_likes_idx ON projects(likes DESC);
|
||||
CREATE INDEX idx_projects_addresses_city_state ON projects_addresses(city, state);
|
||||
CREATE INDEX idx_projects_models_project_id ON projects_models(project_id);
|
||||
CREATE INDEX idx_projects_models_version ON projects_models(project_id, version DESC);
|
||||
CREATE INDEX idx_projects_likes_project_id ON projects_likes(project_id);
|
||||
CREATE INDEX idx_projects_likes_user_id ON projects_likes(user_id);
|
||||
|
||||
-- ============================================================
|
||||
-- 8. Recreate triggers on renamed tables
|
||||
-- ============================================================
|
||||
|
||||
CREATE TRIGGER update_projects_updated_at
|
||||
BEFORE UPDATE ON projects
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
CREATE TRIGGER update_projects_addresses_updated_at
|
||||
BEFORE UPDATE ON projects_addresses
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
CREATE TRIGGER update_projects_models_updated_at
|
||||
BEFORE UPDATE ON projects_models
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
-- ============================================================
|
||||
-- 9. Recreate RLS policies with new names and table references
|
||||
-- ============================================================
|
||||
|
||||
-- projects policies
|
||||
CREATE POLICY "Users can view own or public projects"
|
||||
ON projects FOR SELECT
|
||||
USING (
|
||||
owner_id = current_setting('app.user_id', true)::TEXT
|
||||
OR is_private = false
|
||||
OR owner_id IS NULL
|
||||
);
|
||||
|
||||
CREATE POLICY "Users can insert their own projects"
|
||||
ON projects FOR INSERT
|
||||
WITH CHECK (owner_id = current_setting('app.user_id', true)::TEXT OR owner_id IS NULL);
|
||||
|
||||
CREATE POLICY "Users can update their own projects"
|
||||
ON projects FOR UPDATE
|
||||
USING (owner_id = current_setting('app.user_id', true)::TEXT OR owner_id IS NULL);
|
||||
|
||||
CREATE POLICY "Users can delete their own projects"
|
||||
ON projects FOR DELETE
|
||||
USING (owner_id = current_setting('app.user_id', true)::TEXT OR owner_id IS NULL);
|
||||
|
||||
-- projects_addresses policies
|
||||
CREATE POLICY "Authenticated users can view all addresses"
|
||||
ON projects_addresses FOR SELECT
|
||||
USING (true);
|
||||
|
||||
CREATE POLICY "Authenticated users can insert addresses"
|
||||
ON projects_addresses FOR INSERT
|
||||
WITH CHECK (true);
|
||||
|
||||
CREATE POLICY "Authenticated users can update addresses"
|
||||
ON projects_addresses FOR UPDATE
|
||||
USING (true);
|
||||
|
||||
CREATE POLICY "Authenticated users can delete addresses"
|
||||
ON projects_addresses FOR DELETE
|
||||
USING (true);
|
||||
|
||||
-- projects_models policies
|
||||
CREATE POLICY "Users can view models of own or public projects"
|
||||
ON projects_models FOR SELECT
|
||||
USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM projects
|
||||
WHERE projects.id = projects_models.project_id
|
||||
AND (
|
||||
projects.owner_id = current_setting('app.user_id', true)::TEXT
|
||||
OR projects.is_private = false
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
CREATE POLICY "Users can insert models for their own projects"
|
||||
ON projects_models FOR INSERT
|
||||
WITH CHECK (
|
||||
EXISTS (
|
||||
SELECT 1 FROM projects
|
||||
WHERE projects.id = projects_models.project_id
|
||||
AND projects.owner_id = current_setting('app.user_id', true)::TEXT
|
||||
)
|
||||
);
|
||||
|
||||
CREATE POLICY "Users can update models of their own projects"
|
||||
ON projects_models FOR UPDATE
|
||||
USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM projects
|
||||
WHERE projects.id = projects_models.project_id
|
||||
AND projects.owner_id = current_setting('app.user_id', true)::TEXT
|
||||
)
|
||||
);
|
||||
|
||||
CREATE POLICY "Users can delete models of their own projects"
|
||||
ON projects_models FOR DELETE
|
||||
USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM projects
|
||||
WHERE projects.id = projects_models.project_id
|
||||
AND projects.owner_id = current_setting('app.user_id', true)::TEXT
|
||||
)
|
||||
);
|
||||
|
||||
-- projects_likes policies
|
||||
CREATE POLICY "Anyone can view likes"
|
||||
ON projects_likes FOR SELECT
|
||||
USING (true);
|
||||
|
||||
CREATE POLICY "Users can create their own likes"
|
||||
ON projects_likes FOR INSERT
|
||||
WITH CHECK (user_id = current_setting('app.user_id', true)::TEXT);
|
||||
|
||||
CREATE POLICY "Users can delete their own likes"
|
||||
ON projects_likes FOR DELETE
|
||||
USING (user_id = current_setting('app.user_id', true)::TEXT);
|
||||
|
||||
-- ============================================================
|
||||
-- 10. Replace functions with renamed versions
|
||||
-- ============================================================
|
||||
|
||||
-- Drop old functions
|
||||
DROP FUNCTION IF EXISTS increment_property_views(TEXT);
|
||||
DROP FUNCTION IF EXISTS get_property_like_count(TEXT);
|
||||
|
||||
-- Recreate with new names
|
||||
CREATE OR REPLACE FUNCTION increment_project_views(project_id TEXT)
|
||||
RETURNS void AS $$
|
||||
BEGIN
|
||||
UPDATE projects
|
||||
SET views = views + 1
|
||||
WHERE id = project_id;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
CREATE OR REPLACE FUNCTION get_project_like_count(project_id TEXT)
|
||||
RETURNS INTEGER AS $$
|
||||
BEGIN
|
||||
RETURN (SELECT COUNT(*)::INTEGER FROM projects_likes WHERE projects_likes.project_id = $1);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER STABLE;
|
||||
|
||||
COMMIT;
|
||||
Reference in New Issue
Block a user