scrt.link is a secure secret-sharing platform. Users create encrypted secrets (text, files) that can be shared via one-time links. The platform supports end-to-end encryption, team workspaces, white-label deployments, Stripe subscriptions, and a public API.
- Framework: SvelteKit 2 (Svelte 5) with TypeScript strict mode
- Styling: Tailwind CSS 4 + shadcn-svelte (bits-ui)
- Database: PostgreSQL via Drizzle ORM
- Forms: sveltekit-superforms + Zod 4 + formsnap
- Auth: Custom session-based (Lucia pattern) + Google OAuth (Arctic)
- i18n: Paraglide.js (7 locales: en, de, fr, es, pt, ru, zh-CN)
- Email: Brevo (@getbrevo/brevo) + vanilla inline-CSS templates
- Payments: Stripe subscriptions
- Storage: AWS S3 + Imgix CDN
- Testing: Vitest (unit/browser) + Playwright (e2e)
- Package manager: pnpm (monorepo)
- Deployment: Vercel (primary) or Docker
packages/core/ # Shared crypto & key management utilities (@scrt-link/core)
packages/client/ # Public npm client module for API
src/ # Main SvelteKit application
pnpm run dev # Dev server (port 5173)
pnpm run db:start # Start Postgres in Docker (port 5433)
pnpm run db:push # Apply schema changes
pnpm run db:studio # Drizzle Studio (port 4983)
pnpm test:unit # Vitest unit tests
pnpm test:e2e # Playwright e2e tests
pnpm check # Svelte type checking
pnpm build # Production buildsrc/lib/server/db/schema.ts- Database schema (Drizzle)src/lib/server/auth.ts- Session validation & auth logicsrc/lib/server/form/actions.ts- All server form action handlerssrc/lib/validators/formSchemas.ts- Zod schemas for all formssrc/lib/components/ui/- shadcn-svelte UI componentssrc/lib/components/forms/- Form components (signin, password, etc.)src/lib/client/key-manager.ts- In-memory master key store (browser)packages/core/src/key-management.ts- Crypto functions (PBKDF2, AES-GCM, wrap/unwrap)
(app)/(default)/- Main app pages with full navbar/layout(app)/(minimal)/- Auth pages (login, signup, set-password) with minimal layoutapi/v1/- REST API endpointswhite-label/- Custom domain routes
- Define Zod schema in
formSchemas.ts(functions for i18n) - Server action in
actions.ts: validate withsuperValidate(), operate, return{ form }ormessage() - Client uses
superForm()withzod4Client()validators - For async crypto before submit: use
dataType: 'json'+onSubmitwithjsonData() - Set
applyAction: falsewhen usingdataType: 'json'(superforms bug with message updates)
- Session tokens (30-day, SHA-256 hashed) stored in
auth-sessioncookie event.locals.userandevent.locals.sessionset inhooks.server.ts- Route protection via
-guard.*files (svelte-guard) - Email verification with OTP codes
- Password -> PBKDF2 (600k iterations) -> PDK (never stored)
- PDK wraps Master Key (AES-GCM) -> stored encrypted on server
- Recovery Key (32 bytes, Crockford base32) also wraps Master Key
- Master key held in memory only (
key-manager.ts), cleared on tab close - Password changes re-wrap MK with new PDK (MK never changes)
- Import messages:
import { m } from '$lib/paraglide/messages.js' - Usage:
m.message_key()orm.message_key({ param: value }) - Redirects: use
redirectLocalized()from$lib/i18n
- Use
isRateLimited(event)helper from$lib/server/rate-limit - Automatically skipped in development mode
- Returns
message(form, { status: 'error', ... })on limit
Key tables: user, user_encryption_key, session, organization, membership, secret, api_key, white_label_site
Schema changes: edit schema.ts then pnpm run db:push
- Unit tests:
*.spec.ts(Node),*.browser.spec.ts(Chromium via Vitest browser) - E2E tests:
e2e/directory with Playwright - CI: GitHub Actions on Vercel preview deployments
- Never modify translation files (
messages/*.json) unless explicitly adding new keys tomessages/en.json. Prettier converts Unicode escapes (\u00e9) to UTF-8 characters which creates noisy diffs. Only touchen.jsonfor new keys. - Always translate new keys: After adding keys to
messages/en.json, invoke/translate-keysto translate them into the other locales. Runpnpm cleanup-translation-keysto remove keys no longer referenced insrc/.
Key env vars: POSTGRES_URL, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, BREVO_API, BREVO_MQL_LIST_ID, PUBLIC_STRIPE_PUBLISHABLE_KEY, STRIPE_SECRET_KEY, PUBLIC_S3_ENDPOINT, S3_ACCESS_KEY
Adapters: Vercel (default) or Node (ADAPTER=node for Docker)