diff --git a/README.md b/README.md
index 2206ca3..8c4f5ff 100644
--- a/README.md
+++ b/README.md
@@ -58,3 +58,102 @@ Optional environment variables:
- `npm run check` - Type check with svelte-check
- `npm run lint` - Check formatting and linting
- `npm run format` - Auto-format code with prettier
+
+## Database Management
+
+### Quick Start
+
+Sync remote production database to local development:
+
+```bash
+# This backs up both databases first, then copies remote to local
+npm run db:backup:sync
+```
+
+### Prerequisites
+
+1. PostgreSQL client tools must be installed (`pg_dump`, `psql`)
+ ```bash
+ # macOS
+ brew install postgresql
+
+ # Ubuntu/Debian
+ sudo apt-get install postgresql-client
+ ```
+
+2. Set environment variables in `.env` or `.env.local`:
+ ```bash
+ # Required for local database operations
+ DATABASE_URL="postgresql://user:password@localhost:5432/dbname"
+
+ # Required for remote database operations (use one of these)
+ REMOTE_DATABASE_URL="postgresql://user:password@remote-host:5432/dbname"
+ DATABASE_URL_PRODUCTION="postgresql://user:password@remote-host:5432/dbname"
+ ```
+
+### Backup Commands
+
+```bash
+# Backup local database
+npm run db:backup:local
+
+# Backup remote database
+npm run db:backup:remote
+
+# Sync remote to local (recommended for daily development)
+npm run db:backup:sync
+
+# List all backups
+npm run db:backups
+```
+
+### Restore Commands
+
+```bash
+# Restore a backup to local database (interactive)
+npm run db:restore
+
+# Restore specific backup to local
+npm run db:restore ./backups/backup_file.sql.gz
+
+# Restore to remote (requires typing "RESTORE REMOTE" for safety)
+npm run db:restore ./backups/backup_file.sql.gz remote
+```
+
+### Common Workflows
+
+#### Daily Development
+Start your day by syncing the production database to local:
+```bash
+npm run db:backup:sync
+```
+
+#### Before Deploying Schema Changes
+Always backup the remote database:
+```bash
+npm run db:backup:remote
+```
+
+#### Recover from Mistakes
+```bash
+# See available backups
+npm run db:backups
+
+# Restore a specific backup
+npm run db:restore ./backups/local_20240615_143022.sql.gz
+```
+
+### Backup Storage
+
+All backups are stored in `./backups/` with timestamps:
+- Local: `local_YYYYMMDD_HHMMSS.sql.gz`
+- Remote: `remote_YYYYMMDD_HHMMSS.sql.gz`
+
+### Safety Features
+
+1. **Automatic backups** before sync operations
+2. **Confirmation prompts** for all destructive operations
+3. **Extra protection** for remote restore (requires typing full phrase)
+4. **Compressed storage** with gzip
+5. **Timestamped filenames** prevent overwrites
+6. **Automatic migrations** after local restore
diff --git a/src/lib/components/MasonryPhotoGrid.svelte b/src/lib/components/MasonryPhotoGrid.svelte
index 9ed0c32..a6d72c3 100644
--- a/src/lib/components/MasonryPhotoGrid.svelte
+++ b/src/lib/components/MasonryPhotoGrid.svelte
@@ -4,11 +4,9 @@
import type { PhotoItem as PhotoItemType } from '$lib/types/photos'
const {
- photoItems,
- albumSlug
+ photoItems
}: {
photoItems: PhotoItemType[]
- albumSlug?: string
} = $props()
// Responsive column configuration
@@ -55,7 +53,7 @@
class="photo-masonry"
>
{#snippet children({ item })}
-
+
{/snippet}
diff --git a/src/lib/components/PhotoItem.svelte b/src/lib/components/PhotoItem.svelte
index a3bc512..70b0607 100644
--- a/src/lib/components/PhotoItem.svelte
+++ b/src/lib/components/PhotoItem.svelte
@@ -4,11 +4,9 @@
import { goto } from '$app/navigation'
const {
- item,
- albumSlug // For when this is used within an album context
+ item
}: {
item: PhotoItem
- albumSlug?: string
} = $props()
let imageLoaded = $state(false)
@@ -16,20 +14,11 @@
function handleClick() {
if (isAlbum(item)) {
// Navigate to album page using the slug
- goto(`/photos/${item.slug}`)
+ goto(`/albums/${item.slug}`)
} else {
- // For individual photos, check if we have album context
- if (albumSlug) {
- // Navigate to photo within album
- const mediaId = item.id.replace(/^(media|photo)-/, '') // Support both prefixes
- goto(`/photos/${albumSlug}/${mediaId}`)
- } else {
- // Navigate to individual photo page using the media ID
- const mediaId = item.id.replace(/^(media|photo)-/, '') // Support both prefixes
- // Include the album slug as a 'from' parameter if we're in an album context
- const url = albumSlug ? `/photos/p/${mediaId}?from=${albumSlug}` : `/photos/p/${mediaId}`
- goto(url)
- }
+ // Navigate to individual photo page using the media ID
+ const mediaId = item.id.replace(/^(media|photo)-/, '') // Support both prefixes
+ goto(`/photos/${mediaId}`)
}
}
diff --git a/src/lib/components/ThreeColumnPhotoGrid.svelte b/src/lib/components/ThreeColumnPhotoGrid.svelte
index 2c9d347..216d8b5 100644
--- a/src/lib/components/ThreeColumnPhotoGrid.svelte
+++ b/src/lib/components/ThreeColumnPhotoGrid.svelte
@@ -4,11 +4,9 @@
import { goto } from '$app/navigation'
const {
- photoItems,
- albumSlug
+ photoItems
}: {
photoItems: PhotoItemType[]
- albumSlug?: string
} = $props()
// Function to determine if an image is ultrawide (aspect ratio > 2:1)
@@ -98,18 +96,12 @@
function handleClick(item: PhotoItemType) {
if (isAlbum(item)) {
// Navigate to album page using the slug
- goto(`/photos/${item.slug}`)
+ goto(`/albums/${item.slug}`)
} else {
// For individual photos, check if we have album context
- if (albumSlug) {
- // Navigate to photo within album
- const mediaId = item.id.replace(/^(media|photo)-/, '') // Support both prefixes
- goto(`/photos/${albumSlug}/${mediaId}`)
- } else {
- // Navigate to individual photo page using the media ID
- const mediaId = item.id.replace(/^(media|photo)-/, '') // Support both prefixes
- goto(`/photos/p/${mediaId}`)
- }
+ // Always navigate to individual photo page using the media ID
+ const mediaId = item.id.replace(/^(media|photo)-/, '') // Support both prefixes
+ goto(`/photos/${mediaId}`)
}
}
diff --git a/src/lib/components/UniverseAlbumCard.svelte b/src/lib/components/UniverseAlbumCard.svelte
index aff89c2..42e1e7a 100644
--- a/src/lib/components/UniverseAlbumCard.svelte
+++ b/src/lib/components/UniverseAlbumCard.svelte
@@ -37,7 +37,7 @@
showThumbnails={slideshowItems.length > 1}
maxThumbnails={6}
totalCount={album.photosCount}
- showMoreLink="/photos/{album.slug}"
+ showMoreLink="/albums/{album.slug}"
/>
{/if}
@@ -45,7 +45,7 @@