ATlast — you'll never need to find your favorites on another platform again. Find your favs in the ATmosphere.
atproto
1# Contributing to ATlast
2
3Thank you for your interest in contributing! This guide will help you get started with local development.
4
5## Two Development Modes
6
7We support two development modes:
8
9🎨 **Mock Mode** (No backend required)
10**Best for:** Frontend development, UI/UX work, design changes
11
12🔧 **Full Mode** (Complete backend)
13**Best for:** Backend development, API work, OAuth testing, database changes
14
15**Requirements:**
16- PostgreSQL database (local or Neon)
17- OAuth keys
18- Environment configuration
19
20---
21
22## Mock Mode Starting Guide
23
24Perfect for frontend contributors who want to jump in quickly!
25
261. Clone and Install
27```bash
28git clone <repo-url>
29cd atlast
30pnpm install
31```
32
332. Create .env.local
34```bash
35# .env.mock
36VITE_LOCAL_MOCK=true
37VITE_ENABLE_OAUTH=false
38VITE_ENABLE_DATABASE=false
39```
40
413. Start Development
42```bash
43pnpm run dev:mock
44```
45
464. Open Your Browser
47Go to `http://localhost:5173`
48
495. "Login" with Mock User
50Enter any handle - it will create a mock session.
51
526. Upload Test Data
53Upload your TikTok or Instagram data file. The mock API will generate fake matches for testing the UI.
54
55---
56
57## Full Mode Starting Guide
58
59For contributors working on backend features, OAuth, or database operations.
60
61### Prerequisites
62
63- Node.js 18+
64- pnpm (install with `npm install -g pnpm`)
65- PostgreSQL (or Neon account)
66- OpenSSL (for key generation)
67
681. Clone and Install
69```bash
70git clone <repo-url>
71cd atlast
72pnpm install
73```
74
752. Database Setup
76
77 **Option A: Neon (Recommended)**
78 1. Create account at https://neon.tech
79 2. Create project "atlast-dev"
80 3. Copy connection string
81
82 **Option B: Local PostgreSQL**
83 ```bash
84 # macOS
85 brew install postgresql@15
86 brew services start postgresql@15
87 createdb atlast_dev
88
89 # Ubuntu
90 sudo apt install postgresql
91 sudo systemctl start postgresql
92 sudo -u postgres createdb atlast_dev
93 ```
94
953. Generate OAuth Keys
96```bash
97# Generate private key
98openssl ecparam -name prime256v1 -genkey -noout -out private-key.pem
99
100# Extract public key
101openssl ec -in private-key.pem -pubout -out public-key.pem
102
103# View private key (copy for .env)
104cat private-key.pem
105```
106
1074. Extract Public Key JWK
108```bash
109node -e "
110const fs = require('fs');
111const jose = require('jose');
112const pem = fs.readFileSync('public-key.pem', 'utf8');
113jose.importSPKI(pem, 'ES256').then(key => {
114 return jose.exportJWK(key);
115}).then(jwk => {
116 console.log(JSON.stringify(jwk, null, 2));
117});
118"
119```
120
1215. Update netlify/functions/jwks.ts
122
123 Replace `PUBLIC_JWK` with the output from step 4.
124
1256. Create .env
126
127```bash
128VITE_LOCAL_MOCK=false
129VITE_API_BASE=/.netlify/functions
130
131# Database (choose one)
132NETLIFY_DATABASE_URL=postgresql://user:pass@host/db # Neon
133# NETLIFY_DATABASE_URL=postgresql://localhost/atlast_dev # Local
134
135# OAuth (paste your private key)
136OAUTH_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nYOUR_KEY_HERE\n-----END PRIVATE KEY-----"
137
138# Local URLs (MUST use 127.0.0.1 for OAuth)
139URL=http://127.0.0.1:8888
140DEPLOY_URL=http://127.0.0.1:8888
141DEPLOY_PRIME_URL=http://127.0.0.1:8888
142CONTEXT=dev
143```
144
1457. Initialize Database
146```bash
147pnpm run init-db
148```
149
1508. Start Development Server
151```bash
152npx netlify-cli dev --filter @atlast/web
153# Or use the alias:
154pnpm run dev
155```
156
1579. Test OAuth
158
159 1. Open `http://127.0.0.1:8888` (NOT localhost)
160 2. Enter your real Bluesky handle
161 3. Authorize the app
162 4. You should be redirected back and logged in
163
164---
165
166## Project Structure
167
168**Monorepo using pnpm workspaces:**
169
170```
171atlast/
172├── packages/
173│ ├── web/ # Frontend React app
174│ │ ├── src/
175│ │ │ ├── assets/ # Logo
176│ │ │ ├── components/ # UI components (React)
177│ │ │ ├── pages/ # Page components
178│ │ │ ├── hooks/ # Custom hooks
179│ │ │ ├── lib/
180│ │ │ │ ├── api/ # API client (real + mock)
181│ │ │ │ ├── parsers/ # File parsing logic
182│ │ │ │ └── config.ts # Environment config
183│ │ │ └── types/ # TypeScript types
184│ │ └── package.json
185│ ├── functions/ # Netlify serverless functions
186│ │ ├── src/
187│ │ │ ├── core/ # Middleware, types, config
188│ │ │ ├── infrastructure/ # Database, OAuth, cache
189│ │ │ ├── services/ # Business logic
190│ │ │ ├── repositories/ # Data access layer
191│ │ │ └── utils/ # Shared utilities
192│ │ └── package.json
193│ ├── extension/ # Browser extension
194│ │ ├── src/
195│ │ │ ├── content/ # Content scripts, scrapers
196│ │ │ ├── popup/ # Extension popup UI
197│ │ │ ├── background/ # Service worker
198│ │ │ └── lib/ # Extension utilities
199│ │ └── package.json
200│ └── shared/ # Shared types (future)
201├── pnpm-workspace.yaml
202└── netlify.toml
203```
204
205### UI Color System
206
207| **Element** | **Light Mode** | **Dark Mode** | **Notes** |
208|:---:|:---:|:---:|:---:|
209| Text Primary | purple-950 | cyan-50 | Headings, labels |
210| Text Secondary | purple-750 | cyan-250 | Body text, descriptions |
211| Text Tertiary | purple-600 | cyan-400 | Metadata, hints, icons |
212| Borders (Rest) | cyan-500/30 | purple-500/30 | Cards, inputs default |
213| Borders (Hover) | cyan-400 | purple-400 | Interactive hover |
214| Borders (Active/Selected) | cyan-500 | purple-500 | Active tabs, selected items |
215| Backgrounds (Primary) | white | slate-900 | Modal/card base |
216| Backgrounds (Secondary) | purple-50 | slate-900 (nested sections) | Nested cards, sections |
217| Backgrounds (Selected) | cyan-50 | purple-950/30 | Selected platform cards |
218| Buttons Primary | orange-600 | orange-600 | CTAs |
219| Buttons Primary Hover | orange-500 | orange-500 | CTA hover |
220| Buttons Secondary | slate-600 | slate-700 | Cancel, secondary actions |
221| Buttons Secondary Hover | slate-700 | slate-600 | Secondary hover |
222| Interactive Selected | bg-cyan-50 border-cyan-500 | bg-purple-950/30 border-purple-500 | Platform selection cards |
223| Accent/Badge | orange-500 | orange-500 (or amber-500) | Match counts, checkmarks, progress |
224| Progress Complete | orange-500 | orange-500 | Completed progress bars |
225| Progress Incomplete | cyan-500/30 | purple-500/30 | Incomplete progress bars |
226| Success/Green | green-100/800 | green-900/300 | Followed status |
227| Error/Red | red-600 | red-400 | Logout, errors |
228
229### UI Color System: Patterns
230**Disabled States**:
231- Light: Reduce opacity to 50%, use purple-500/50
232- Dark: Reduce opacity to 50%, use cyan-500/50
233
234**Success/Match indicators**:
235Both modes: amber-* or orange-* backgrounds with accessible text contrast
236
237**Tab Navigation**:
238- Inactive: Use text secondary colors
239- Active border: orange-500 (light), amber-500 (dark)
240- Active text: orange-650 (light), amber-400 (dark)
241
242**Gradient Banners**:
243- Both modes: from-amber-* via-orange-* to-pink-* (keep dramatic, adjust shades for mode)
244
245---
246
247## Task Workflows
248
249### Adding a New Social Platform Parser
250
2511. Add parsing rules to `packages/web/src/lib/parsers/platformDefinitions.ts`
2522. Follow existing patterns (TikTok, Instagram)
2533. Test with real data export file
2544. Update platform selection UI if needed
255
256### Adding a New API Endpoint
257
2581. Create `packages/functions/src/your-endpoint.ts`
2592. Add authentication check using `withAuthErrorHandling()` middleware
2603. Update `packages/web/src/lib/api/adapters/RealApiAdapter.ts`
2614. Update `packages/web/src/lib/api/adapters/MockApiAdapter.ts`
2625. Use in components via `apiClient.yourMethod()`
263
264### Working with the Extension
265
266```bash
267cd packages/extension
268pnpm install
269pnpm run build # Build for Chrome
270pnpm run build:prod # Build for production
271
272# Load in Chrome:
273# 1. Go to chrome://extensions
274# 2. Enable Developer mode
275# 3. Click "Load unpacked"
276# 4. Select packages/extension/dist/chrome/
277```
278
279### Styling Changes
280
281- Use Tailwind utility classes
282- Follow dark mode pattern: `class="bg-white dark:bg-gray-800"`
283- Test in both light and dark modes
284- Mobile-first responsive design
285- Check accessibility (if implemented) is retained
286
287---
288
289## Submitting Changes
290
291### Before Submitting
292
293- [ ] Test in mock mode: `pnpm run dev:mock`
294- [ ] Test in full mode (if backend changes): `npx netlify-cli dev --filter @atlast/web`
295- [ ] Check both light and dark themes
296- [ ] Test mobile responsiveness
297- [ ] No console errors
298- [ ] Code follows existing patterns
299- [ ] Run `pnpm run build` successfully
300
301### Pull Request Process
302
3031. Fork the repository
3042. Create a feature branch: `git checkout -b feature/your-feature`
3053. Make your changes
3064. Commit with clear messages
3075. Push to your fork
3086. Open a Pull Request
309
310### PR Description Should Include
311
312- What changes were made
313- Why these changes are needed
314- Screenshots (for UI changes)
315- Testing steps
316- Related issues
317
318---
319
320## Resources
321
322- [AT Protocol Docs](https://atproto.com)
323- [Bluesky API](https://docs.bsky.app)
324- [React Documentation](https://react.dev)
325- [Tailwind CSS](https://tailwindcss.com)
326- [Netlify Functions](https://docs.netlify.com/functions/overview)
327
328---
329
330Thank you for contributing to ATlast!