Thalos is an escrow orchestration layer built on the Stellar network. It connects transparently with the Trustless Work protocol to offer programmable agreements and milestone-based payments, simple and secure, designed for end users who need to protect their transactions without dealing with blockchain complexity.
Thalos is a platform that lets freelancers, businesses, and everyday users create escrow agreements in minutes. You define milestones, fund the escrow, and funds are released only when both parties agree the work is done. No intermediaries, no trust required -- the Stellar network handles settlement in seconds.
Key features:
- Programmable escrow agreements with milestone-based releases
- Wallet-based authentication (no passwords, no accounts to manage)
- Real-time dashboards for personal and business accounts
- Built-in dispute resolution workflows
- Bilingual interface (English / Spanish)
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| Language | TypeScript 5 |
| Styling | Tailwind CSS 4, shadcn/ui |
| Blockchain | Stellar SDK, Stellar Wallets Kit, Freighter API |
| Escrows | Trustless Work API |
| Charts | Recharts |
| Deployment | Vercel |
- Node.js >= 18
- pnpm (recommended) or npm
- A Stellar wallet browser extension (Freighter, xBull, LOBSTR, etc.)
git clone https://github.com/Thalos-Infrastructure/ThalosFrontend.git
cd ThalosFrontendThalos is a platform that lets freelancers, businesses, and everyday users create escrow agreements in minutes. You define milestones, fund the escrow, and funds are released only when both parties agree the work is done. No intermediaries, no trust required -- the Stellar network handles settlement in seconds.
Key features:
- Programmable escrow agreements with milestone-based releases
- Wallet-based authentication (no passwords, no accounts to manage)
- Real-time dashboards for personal and business accounts
- Built-in dispute resolution workflows
- Bilingual interface (English / Spanish)
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| Language | TypeScript 5 |
| Styling | Tailwind CSS 4, shadcn/ui |
| Blockchain | Stellar SDK, Stellar Wallets Kit, Freighter API |
| Escrows | Trustless Work API |
| Charts | Recharts |
| Deployment | Vercel |
- Node.js >= 18
- pnpm (recommended) or npm
- A Stellar wallet browser extension (Freighter, xBull, LOBSTR, etc.)
git clone https://github.com/Thalos-Infrastructure/ThalosFrontend.git
cd ThalosFrontendpnpm installOr with npm:
npm installCopy .env.example to .env.local and fill in real values. .env*.local
are gitignored and must never be committed. See .env.example for the full, commented list;
the required ones are:
| Variable | Description |
|---|---|
NEXT_PUBLIC_SUPABASE_URL |
Supabase project URL (same project as the backend). |
NEXT_PUBLIC_SUPABASE_ANON_KEY |
Supabase anon/public key (Dashboard → Project Settings → API). |
SUPABASE_SERVICE_ROLE_KEY |
Supabase service role key (server-side only — keep secret). |
JWT_SECRET |
App JWT signing secret (HS256). Must be identical to the backend's JWT_SECRET. |
NEXT_PUBLIC_API_URL |
Base URL of the NestJS backend, including /v1 (e.g. http://localhost:3001/v1 in dev). Points to the backend host, not the frontend site. |
Everything else (email, Stellar/UI, Trustless Work) is optional and documented in .env.example.
NEXT_PUBLIC_*values are inlined at build time — changing them requires a rebuild/redeploy.
pnpm devThe app will be available at http://localhost:3000.
pnpm build
pnpm startThalosFrontend/
├── app/
│ ├── page.tsx # Landing page
│ ├── about/page.tsx # About Thalos
│ ├── admin/page.tsx # Admin dashboard
│ └── dashboard/
│ ├── personal/page.tsx # Personal account dashboard
│ └── business/page.tsx # Business account dashboard
├── components/ # UI components
├── hooks/ # Custom React hooks
├── lib/
│ ├── config.ts # Global constants
│ ├── i18n.tsx # Internationalization (EN/ES)
│ ├── stellar-wallet.tsx # Wallet context provider
│ ├── stellar-wallet-kit.ts # Stellar Wallets Kit initialization
│ ├── agreementActions.ts # Escrow agreement operations via Trustless Work
│ └── utils.ts # Utility functions
└── public/ # Static assets
Thalos uses the Stellar Wallets Kit to provide a unified connection modal. Supported wallets include Freighter, xBull, LOBSTR, Albedo, Rabet, and WalletConnect.
- Click Sign In from the navbar.
- Select your account type (Personal or Enterprise).
- Click Login with Wallet and choose your wallet from the modal.
- Approve the connection in your wallet extension.
Your connected address is used for all escrow operations: funding agreements as a payer, or receiving released funds as a payee.
Thalos orchestrates escrow agreements through the Trustless Work protocol on Stellar. The platform handles the complexity; you just define the terms.
- Create -- Define an agreement with milestones, amounts, and counterparties.
- Fund -- Lock USDC into the escrow smart contract.
- Release -- Funds are released as each milestone is completed and approved.
- Dispute -- If something goes wrong, the built-in dispute flow protects both parties.
All transactions are signed client-side by your Stellar wallet. Thalos never holds your keys or your funds.
| Command | Description |
|---|---|
pnpm dev |
Start development server |
pnpm build |
Production build |
pnpm start |
Start production server |
pnpm lint |
Run ESLint |
All rights reserved by Thalos.
The canonical AuthUser type is defined in lib/auth/types.ts and is the single source of truth for the authenticated user shape across both server and client.
type AuthWallet = {
publicKey: string; // Stellar public key of the custodial wallet
provider: string; // wallet origin, e.g. "embedded"
};
type AuthUser = {
id: string; // auth_users UUID — never empty
email: string; // verified email — never empty
name: string | null; // optional display name; null if not provided
avatarUrl: string | null; // OAuth avatar URL; null for email flows
wallet: AuthWallet | null; // null if the user has no custodial wallet
};| Field | Type | Guarantee |
|---|---|---|
id |
string |
Non-empty UUID; session is rejected if absent |
email |
string |
Non-empty email; session is rejected if absent |
name |
string | null |
Explicit null (never undefined) to preserve JSON serialization round-trips |
avatarUrl |
string | null |
Extracted from user_metadata.avatar_url or picture in the OAuth flow; null for email login and registration |
wallet.provider |
string |
Normalizes the legacy server type field to provider at the hydration layer |
wallet.publicKey |
string |
Strictly validated as a non-empty string; absent or null keys map to wallet: null |
normalizeAuthUser(raw: unknown): AuthUser | null converts any network response or localStorage blob into the canonical contract. Returns null if id or email are absent, falsy, or not strings — preventing identity-less sessions from reaching the store. All authentication entry points pass network data through this function before calling login().
| File | Event | Normalized |
|---|---|---|
components/sign-in-panel.tsx |
Email login and registration | normalizeAuthUser(data.user) |
components/social-auth-modal.tsx |
Email login and registration | normalizeAuthUser(data.user) |
app/auth/callback/success/page.tsx |
OAuth callback (Google) | normalizeAuthUser(data.user) |
lib/auth-provider.tsx |
Hydration from localStorage |
normalizeAuthUser(JSON.parse(...)) |