managarten/apps/uload/CLAUDE.md
Till JS 22a73943e1 chore: complete ManaCore → Mana rename (docs, go modules, plists, images)
Final cleanup of references missed in previous rename commits:

- Dockerfiles: PUBLIC_MANA_CORE_AUTH_URL → PUBLIC_MANA_AUTH_URL
- Go modules: github.com/manacore/* → github.com/mana/* (7 go.mod files)
- launchd plists: com.manacore.* → com.mana.* (14 files renamed + content)
- Image assets: *_Manacore_AI_Credits* → *_Mana_AI_Credits* (11 files)
- .env.example files: ManaCore brand strings → Mana
- .prettierignore: stale apps/manacore/* paths → apps/mana/*
- Markdown docs (CLAUDE.md, /docs/*): mana-core-auth → mana-auth, etc.

Excluded from rename: .claude/, devlog/, manascore/ (historical content),
client testimonials, blueprints, npm package refs (@mana-core/*).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 12:26:10 +02:00

128 lines
3.9 KiB
Markdown

# uLoad — URL Shortener & Link Management
**Live:** https://ulo.ad
## Architecture
uLoad uses a **local-first** architecture with a lightweight Hono/Bun server for redirects and analytics.
```
Browser → IndexedDB (Links, Tags, Folders)
↕ sync
mana-sync → PostgreSQL
Browser → /r/:code → Hono Server → PostgreSQL (redirect + click tracking)
```
## Project Structure
```
apps/uload/
├── apps/
│ ├── web/ # SvelteKit web app (local-first)
│ ├── server/ # Hono/Bun redirect & analytics server
│ └── landing/ # Astro marketing page
├── packages/
│ └── uload-database/ # Shared Drizzle schema
└── package.json
```
## Tech Stack
| Layer | Technology |
|-------|-----------|
| **Web** | SvelteKit 2, Svelte 5 (runes), Tailwind CSS 4 |
| **Server** | Hono + Bun |
| **Data** | Local-first (Dexie.js + mana-sync) |
| **Database** | PostgreSQL via Drizzle ORM |
| **Auth** | mana-auth (Better Auth + EdDSA JWT) |
| **Landing** | Astro 5 |
| **PWA** | @vite-pwa/sveltekit |
| **i18n** | svelte-i18n (DE/EN) |
## Commands
```bash
# Development
pnpm dev:uload:web # SvelteKit dev server
pnpm dev:uload:server # Hono/Bun server (port 3070)
pnpm dev:uload:landing # Landing page
pnpm dev:uload:local # Web + Sync + Server (no auth)
pnpm dev:uload:full # Everything incl. auth
# Build & Deploy
pnpm --filter @uload/web build
pnpm --filter @uload/landing build
pnpm deploy:landing:uload # Deploy landing to Cloudflare Pages
# Type Check
pnpm --filter @uload/web check
pnpm --filter @uload/server type-check
pnpm --filter @mana/uload-database type-check
```
## Ports
| Service | Dev Port | Prod Port |
|---------|----------|-----------|
| Web | 5173 | 5029 |
| Server | 3070 | 3041 |
| Landing | 4321 | Cloudflare Pages |
## Hono Server Routes
| Route | Auth | Description |
|-------|------|-------------|
| `GET /health` | No | Health check |
| `GET /r/:code` | No | Redirect + click tracking |
| `GET /public/u/:username` | No | Public user profile + links |
| `GET /api/v1/analytics/:linkId` | JWT | Click stats |
| `GET /api/v1/analytics/:linkId/timeline` | JWT | Clicks over time |
| `GET /api/v1/analytics/:linkId/devices` | JWT | Device breakdown |
| `GET /api/v1/analytics/:linkId/referrers` | JWT | Top referrers |
| `GET /api/v1/analytics/:linkId/countries` | JWT | Country breakdown |
| `POST /api/v1/stripe/checkout` | JWT | Stripe session (stub) |
| `POST /api/v1/stripe/webhook` | No | Stripe webhook (stub) |
| `POST /api/v1/email/send-invitation` | JWT | Team invite (stub) |
## Local-First Collections
| Collection | Fields |
|-----------|--------|
| `links` | shortCode, originalUrl, title, isActive, clickCount, utmSource/Medium/Campaign, folderId |
| `tags` | name, slug, color, icon, isPublic, usageCount |
| `folders` | name, color, order |
| `linkTags` | linkId, tagId |
## Web App Pages
| Route | Description |
|-------|-------------|
| `/my/links` | Link management (CRUD, QR, UTM, bulk) |
| `/my/tags` | Tag management |
| `/my/analytics/[id]` | Per-link analytics dashboard |
| `/settings` | Account & data settings |
| `/pricing` | Subscription plans (static) |
| `/u/[username]` | Public user profile |
| `/login` | Login (shared-auth-ui) |
| `/register` | Register (shared-auth-ui) |
## Docker
```bash
# Build
./scripts/mac-mini/build-app.sh uload-web
./scripts/mac-mini/build-app.sh uload-server
# Services in docker-compose.macmini.yml:
# - uload-server (port 3041, Bun)
# - uload-web (port 5029, Node)
```
## Key Patterns
- **Svelte 5 Runes**: Use `$state`, `$derived`, `$effect` — never `$:`
- **Local-first**: All CRUD via `linkCollection.insert/update/delete` (IndexedDB)
- **Analytics**: Fetched from Hono server, not local (server-only click data)
- **Auth**: `authStore` from `@mana/shared-auth-ui`, `AuthGate` with guest mode
- **Sync**: Starts on login via `uloadStore.startSync()`, stops on logout