hub features

This commit is contained in:
wass08
2026-02-16 13:43:19 +09:00
parent 5d17fecf94
commit 66e8453db3
22 changed files with 1869 additions and 43 deletions
@@ -19,11 +19,19 @@ export const properties = pgTable(
.references(() => users.id, { onDelete: 'set null' }),
detailsJson: t.jsonb('details_json'),
metadata: t.jsonb('metadata'),
// Community features
isPrivate: t.boolean('is_private').notNull().default(true),
views: t.integer('views').notNull().default(0),
likes: t.integer('likes').notNull().default(0),
thumbnailUrl: t.text('thumbnail_url'),
...timestampsColumns,
}),
(t) => [
index('property_address_idx').on(t.addressId),
index('property_owner_idx').on(t.ownerId),
index('property_is_private_idx').on(t.isPrivate),
index('property_views_idx').on(t.views),
index('property_likes_idx').on(t.likes),
],
).enableRLS()
@@ -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;