~ knotless Search/
↑↓ move↵ open⇧↵ all results

grain.social/grain

photography-focused photo sharing platform

grain.social
1 collaborator
0
2
143 lines · 4.3 KB Raw History
# Grain hatk Template — MVP Design

## Goal

Rebuild grain-next (Lit Web Components + GraphQL/Quickslice) as a hatk-powered SvelteKit app, using hatk-template-teal as the scaffold. MVP: shell + auth + timeline with gallery cards, running end-to-end.

## Source Projects

- **hatk-template-teal** (`~/code/hatk-template-teal`): SvelteKit 5 + hatk scaffold for teal.fm music tracker. Provides the application shell, auth flow, component architecture, and build tooling.
- **grain-next** (`~/code/grain-next`): Lit Web Components PWA for Grain photo sharing. Provides lexicons, data models, and feature reference.

## Architecture

### Stack

- SvelteKit 5 + Svelte 5 (from teal template)
- hatk framework (XRPC endpoints, feeds, OAuth, SQLite)
- TanStack Svelte Query (client-side data fetching/caching)
- Vite build tooling

### Key Translation

| grain-next                | hatk-template-grain          |
| ------------------------- | ---------------------------- |
| Lit Web Components        | Svelte 5 components          |
| GraphQL via Quickslice    | hatk XRPC + feeds            |
| Client-side SPA router    | SvelteKit file-based routing |
| Custom query/record cache | TanStack Svelte Query        |
| Quickslice OAuth          | hatk OAuth                   |

## Project Setup

1. Copy hatk-template-teal structure wholesale into hatk-template-grain.
2. Replace `lexicons/fm/teal/` with `lexicons/social/grain/` (copied from grain-next).
3. Keep `lexicons/app/bsky/`, `lexicons/com/atproto/`, `lexicons/dev/hatk/`.
4. Regenerate types with `npx hatk generate types`.
5. Update `hatk.config.ts`:
   - `signalCollections: ["social.grain.actor.profile"]`
   - OAuth scopes for all Grain collections (request upfront).
6. Update `package.json` name/description.

## Styling

Keep teal's dark theme and CSS variables unchanged. Tweak later.

## Routes (MVP)

```
app/routes/
├── +layout.svelte          # Shell (3-column, from teal)
├── +layout.server.ts       # Session parsing
├── +layout.ts              # Query client setup
├── +page.svelte            # Timeline (gallery cards)
├── +page.ts                # Timeline feed query
├── oauth/callback/         # OAuth redirect
└── profile/[did]/          # Profile page (placeholder)
```

## Server (MVP)

```
server/
├── feeds/
│   └── recent.ts           # Recent galleries feed
└── xrpc/                   # Empty for now
```

## Components

### Keep from teal (as-is)

- `Shell.svelte` — 3-column layout
- `Sidebar.svelte` — left nav (logo, home, auth)
- `SidebarRight.svelte` — right sidebar (strip trending artists/genres, keep search bar placeholder)
- `Avatar.svelte`, `Button.svelte`, `Skeleton.svelte`, `Modal.svelte` — generic atoms
- `AuthBar.svelte`, `LoginModal.svelte` — auth organisms

### Replace

| teal                    | grain                           |
| ----------------------- | ------------------------------- |
| `PlayCard.svelte`       | `GalleryCard.svelte`            |
| `ScrobbleModal.svelte`  | Remove                          |
| `BookmarkButton.svelte` | Remove                          |
| `FeedTabs.svelte`       | Simplify to single "Recent" tab |

### GalleryCard.svelte

Displays:

- Thumbnail grid (first ~4 photos from gallery)
- Gallery title
- Author chip (avatar + handle)
- Photo count

## Feed: Recent Galleries

**Server (`server/feeds/recent.ts`):**

- Query `social.grain.gallery` ordered by `created_at DESC`
- Hydrate with author profile (`social.grain.actor.profile`)
- Join `social.grain.gallery.item` for photo refs, then `social.grain.photo` for blobs/aspect ratios
- Cursor-based pagination

**Client:**

- `+page.ts` calls `dev.hatk.getFeed` with feed `recent`
- TanStack Query caches + paginates
- `+page.svelte` renders `GalleryCard` list

## Auth

Identical to teal's hatk OAuth flow. Update scopes to:

```
atproto
repo:social.grain.gallery
repo:social.grain.gallery.item
repo:social.grain.photo
repo:social.grain.actor.profile
repo:social.grain.graph.follow
repo:social.grain.favorite
repo:social.grain.comment
```

## hatk.config.ts

```typescript
signalCollections: ["social.grain.actor.profile"];
```

## What's Deferred

- Comments, favorites, notifications
- Search / explore
- Gallery create/edit UI
- Photo upload
- EXIF extraction
- Profile editing
- Follow/unfollow
- Rich text / facets
- PWA / service worker
- Custom accent color / branding