Skip to content

Commit c74bd6c

Browse files
committed
seed local supabase media
1 parent 0ad6181 commit c74bd6c

18 files changed

Lines changed: 231 additions & 10 deletions

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,10 @@ Use local Studio, `psql`, or the hosted Supabase dashboard for browsing rows and
145145

146146
- Bucket configuration lives in `supabase/config.toml`
147147
- Local reset data lives in `supabase/seed.sql`
148-
- Local placeholder static assets live in `supabase/storage/static/`
148+
- Local bucket objects live in `supabase/storage/`
149+
- Local bucket policies are backfilled via SQL migrations so local uploads behave like the hosted project
150+
- `npm run supabase:reset` rebuilds the database and re-uploads seeded local media
151+
- `npm run supabase:seed-buckets` re-uploads local bucket media without resetting the database
149152

150153
Keep all local and preview data sanitized. Do not export or commit production data.
151154

docs/supabase-local-first.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ What this does:
3434
- A PR branch that changes `supabase/**` gets its own Supabase preview branch.
3535
- That preview branch runs migrations and bucket config from Git.
3636
- Seed data comes from `supabase/seed.sql`, not from production data.
37+
- Local bucket objects come from `supabase/storage/`, not from production storage.
3738

3839
### 2. Require the Supabase PR Check in GitHub
3940

@@ -78,6 +79,7 @@ npm install
7879
cp .env.example .env.local
7980
npm run supabase:start
8081
npm run supabase:reset
82+
npm run supabase:seed-buckets
8183
npm run supabase:env
8284
```
8385

@@ -117,10 +119,13 @@ The seed also creates:
117119
- 3 public listings
118120
- 1 chat thread
119121
- 2 chat messages
122+
- seeded profile avatars and listing photos in local Supabase Storage
120123
- a sample static bucket object at `static/promo-kit.zip`
121124

122125
The demo data is synthetic and safe to keep in Git.
123126

127+
When `NEXT_PUBLIC_SUPABASE_URL` points at `http://127.0.0.1:54331`, avatar and listing-photo uploads also go to the local Supabase buckets rather than production.
128+
124129
## Fresh Computer Setup
125130

126131
Use this when setting up Peels on a new machine.
@@ -158,9 +163,10 @@ npm run dev
158163
2. Make schema changes locally.
159164
3. Add or edit SQL migrations under `supabase/migrations/`.
160165
4. Rebuild from scratch with `npm run supabase:reset`.
161-
5. Run `npm run dev`.
162-
6. Test the flow locally.
163-
7. Commit app and migration changes together.
166+
5. Re-upload only local bucket media with `npm run supabase:seed-buckets` when you do not need a full DB reset.
167+
6. Run `npm run dev`.
168+
7. Test the flow locally.
169+
8. Commit app and migration changes together.
164170

165171
Use local Studio, `psql`, or the hosted dashboard for browsing rows. Use the CLI for schema lifecycle.
166172

next.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ const uniqueStorageRemotePatterns = storageRemotePatterns.filter(
5757
)
5858
);
5959

60+
const shouldAllowLocalStorageImages =
61+
process.env.NEXT_PUBLIC_SUPABASE_URL?.includes("127.0.0.1") ||
62+
process.env.NEXT_PUBLIC_SUPABASE_URL?.includes("localhost") ||
63+
false;
64+
6065
/** @type {import('next').NextConfig} */
6166
const nextConfig = {
6267
// Configure `pageExtensions` to include markdown and MDX files
@@ -69,6 +74,7 @@ const nextConfig = {
6974
// https://nextjs.org/docs/app/api-reference/components/image#caching-behavior
7075
// Can be safetly increased as all user-generated imagery use uniques slugs
7176
minimumCacheTTL: 2678400, // 31 days (default value is `60`, i.e. one minute)
77+
dangerouslyAllowLocalIP: shouldAllowLocalStorageImages,
7278
// Define where remote images can be pulled from
7379
remotePatterns: uniqueStorageRemotePatterns,
7480
},

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"supabase:status": "supabase status",
1111
"supabase:env": "supabase status -o env",
1212
"supabase:reset": "supabase db reset",
13+
"supabase:seed-buckets": "supabase seed buckets --yes",
1314
"supabase:diff": "supabase db diff",
1415
"format": "prettier --write .",
1516
"format:check": "prettier --check ."

supabase/config.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,16 +91,19 @@ file_size_limit = "50MiB"
9191
public = true
9292
file_size_limit = "10MiB"
9393
allowed_mime_types = ["image/png", "image/jpeg", "image/webp"]
94+
objects_path = "./storage/avatars"
9495

9596
[storage.buckets.listing_avatars]
9697
public = true
9798
file_size_limit = "10MiB"
9899
allowed_mime_types = ["image/png", "image/jpeg", "image/webp"]
100+
objects_path = "./storage/listing_avatars"
99101

100102
[storage.buckets.listing_photos]
101103
public = true
102104
file_size_limit = "50MiB"
103105
allowed_mime_types = ["image/png", "image/jpeg", "image/webp"]
106+
objects_path = "./storage/listing_photos"
104107

105108
[storage.buckets.static]
106109
public = true
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
begin;
2+
3+
-- Backfill Storage RLS policies that already exist in the hosted project but
4+
-- were not captured in the initial public-schema baseline pull.
5+
6+
do $$
7+
begin
8+
if not exists (
9+
select 1
10+
from pg_policies
11+
where schemaname = 'storage'
12+
and tablename = 'objects'
13+
and policyname = 'Allow authenticated changes 1oj01fe_0'
14+
) then
15+
execute $policy$
16+
create policy "Allow authenticated changes 1oj01fe_0"
17+
on storage.objects
18+
for update
19+
to authenticated
20+
using ((bucket_id = 'avatars') and (auth.role() = 'authenticated'))
21+
$policy$;
22+
end if;
23+
24+
if not exists (
25+
select 1
26+
from pg_policies
27+
where schemaname = 'storage'
28+
and tablename = 'objects'
29+
and policyname = 'Allow authenticated changes 1oj01fe_1'
30+
) then
31+
execute $policy$
32+
create policy "Allow authenticated changes 1oj01fe_1"
33+
on storage.objects
34+
for insert
35+
to authenticated
36+
with check ((bucket_id = 'avatars') and (auth.role() = 'authenticated'))
37+
$policy$;
38+
end if;
39+
40+
if not exists (
41+
select 1
42+
from pg_policies
43+
where schemaname = 'storage'
44+
and tablename = 'objects'
45+
and policyname = 'Allow authenticated deletes 1oj01fe_0'
46+
) then
47+
execute $policy$
48+
create policy "Allow authenticated deletes 1oj01fe_0"
49+
on storage.objects
50+
for delete
51+
to authenticated
52+
using ((bucket_id = 'avatars') and (auth.role() = 'authenticated'))
53+
$policy$;
54+
end if;
55+
56+
if not exists (
57+
select 1
58+
from pg_policies
59+
where schemaname = 'storage'
60+
and tablename = 'objects'
61+
and policyname = 'Allow authenticated list 1oj01fe_0'
62+
) then
63+
execute $policy$
64+
create policy "Allow authenticated list 1oj01fe_0"
65+
on storage.objects
66+
for select
67+
to authenticated
68+
using (bucket_id = 'avatars')
69+
$policy$;
70+
end if;
71+
72+
if not exists (
73+
select 1
74+
from pg_policies
75+
where schemaname = 'storage'
76+
and tablename = 'objects'
77+
and policyname = 'Anyone can view listing avatars'
78+
) then
79+
execute $policy$
80+
create policy "Anyone can view listing avatars"
81+
on storage.objects
82+
for select
83+
using (bucket_id = 'listing_avatars')
84+
$policy$;
85+
end if;
86+
87+
if not exists (
88+
select 1
89+
from pg_policies
90+
where schemaname = 'storage'
91+
and tablename = 'objects'
92+
and policyname = 'Anyone can view listing photos'
93+
) then
94+
execute $policy$
95+
create policy "Anyone can view listing photos"
96+
on storage.objects
97+
for select
98+
using (bucket_id = 'listing_photos')
99+
$policy$;
100+
end if;
101+
102+
if not exists (
103+
select 1
104+
from pg_policies
105+
where schemaname = 'storage'
106+
and tablename = 'objects'
107+
and policyname = 'Users can delete their own listing avatars'
108+
) then
109+
execute $policy$
110+
create policy "Users can delete their own listing avatars"
111+
on storage.objects
112+
for delete
113+
to authenticated
114+
using (bucket_id = 'listing_avatars')
115+
$policy$;
116+
end if;
117+
118+
if not exists (
119+
select 1
120+
from pg_policies
121+
where schemaname = 'storage'
122+
and tablename = 'objects'
123+
and policyname = 'Users can delete their own listing photos'
124+
) then
125+
execute $policy$
126+
create policy "Users can delete their own listing photos"
127+
on storage.objects
128+
for delete
129+
to authenticated
130+
using (bucket_id = 'listing_photos')
131+
$policy$;
132+
end if;
133+
134+
if not exists (
135+
select 1
136+
from pg_policies
137+
where schemaname = 'storage'
138+
and tablename = 'objects'
139+
and policyname = 'Users can update their own listing avatars'
140+
) then
141+
execute $policy$
142+
create policy "Users can update their own listing avatars"
143+
on storage.objects
144+
for update
145+
to authenticated
146+
using (bucket_id = 'listing_avatars')
147+
with check (auth.role() = 'authenticated')
148+
$policy$;
149+
end if;
150+
151+
if not exists (
152+
select 1
153+
from pg_policies
154+
where schemaname = 'storage'
155+
and tablename = 'objects'
156+
and policyname = 'Users can update their own listing photos'
157+
) then
158+
execute $policy$
159+
create policy "Users can update their own listing photos"
160+
on storage.objects
161+
for update
162+
to authenticated
163+
using (bucket_id = 'listing_photos')
164+
with check (auth.role() = 'authenticated')
165+
$policy$;
166+
end if;
167+
168+
if not exists (
169+
select 1
170+
from pg_policies
171+
where schemaname = 'storage'
172+
and tablename = 'objects'
173+
and policyname = 'Users can upload their own listing avatars'
174+
) then
175+
execute $policy$
176+
create policy "Users can upload their own listing avatars"
177+
on storage.objects
178+
for insert
179+
to authenticated
180+
with check ((bucket_id = 'listing_avatars') and (auth.role() = 'authenticated'))
181+
$policy$;
182+
end if;
183+
184+
if not exists (
185+
select 1
186+
from pg_policies
187+
where schemaname = 'storage'
188+
and tablename = 'objects'
189+
and policyname = 'Users can upload their own listing photos'
190+
) then
191+
execute $policy$
192+
create policy "Users can upload their own listing photos"
193+
on storage.objects
194+
for insert
195+
to authenticated
196+
with check ((bucket_id = 'listing_photos') and (auth.role() = 'authenticated'))
197+
$policy$;
198+
end if;
199+
end
200+
$$;
201+
202+
commit;

supabase/seed.sql

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ values
132132
(
133133
'2c9ae20c-2469-4e60-84b3-39268697717c',
134134
'Avery',
135-
null,
135+
'demo/skate.jpg',
136136
false,
137137
'http://127.0.0.1:3000',
138138
'local-seed',
@@ -144,7 +144,7 @@ values
144144
(
145145
'9a0c62fc-bf50-4f45-ba6c-5b9051c2712a',
146146
'Riley',
147-
null,
147+
'demo/sunflowers.jpg',
148148
false,
149149
'http://127.0.0.1:3000',
150150
'local-seed',
@@ -189,11 +189,11 @@ values
189189
extensions.st_setsrid(extensions.st_makepoint(151.1569, -33.9110), 4326)::extensions.geography,
190190
array['Fruit and vegetable scraps', 'Coffee grounds', 'Tea leaves', 'Egg shells'],
191191
array['Plastic bags', 'Meat', 'Dairy'],
192-
array[]::text[],
192+
array['demo/garden.jpg', 'demo/caddy.jpg', 'demo/tumbler.jpg'],
193193
array['https://www.peels.app/about'],
194194
true,
195195
'community',
196-
null,
196+
'demo/farm.jpg',
197197
-33.9110,
198198
151.1569,
199199
'AU',
@@ -208,11 +208,11 @@ values
208208
extensions.st_setsrid(extensions.st_makepoint(151.1645, -33.9063), 4326)::extensions.geography,
209209
array['Coffee grounds', 'Fruit scraps'],
210210
array['Packaging', 'Glass'],
211-
array[]::text[],
211+
array['demo/wheelbarrow.jpg'],
212212
array['https://www.peels.app/faq'],
213213
true,
214214
'business',
215-
null,
215+
'demo/brewery.jpg',
216216
-33.9063,
217217
151.1645,
218218
'AU',
41.9 KB
Loading
59.1 KB
Loading
36.9 KB
Loading

0 commit comments

Comments
 (0)