Starting with a new company
Signalysis was a new company that needed direction for its website. I created a clean, easy-to-use experience that made a complex financial research product approachable. The goal was a clear path from learning what the product does to exploring its data and becoming a customer.
The business reports a very satisfied customer and approximately $5,000 in current monthly sales. My work centered on the website and user experience. The technical description below is grounded in the current repository and explains the wider system supporting that experience, without claiming I independently built every subsystem.
The actual application stack
The project uses Next.js App Router conventions and React components with TypeScript, while Vinext/Vite and Wrangler provide the Cloudflare build and deployment path. Server components and route handlers establish access boundaries; client components power interactive market research and charts.
Supabase handles authentication and PostgreSQL-backed state, Stripe handles subscriptions and hosted billing, and Lightweight Charts renders market data. Coinbase and Yahoo Finance are provider dependencies in the documented market-data pipeline. The public site presents live watchlist access, paid analysis, a research library, and explanatory tools. The live product shows that visitor-facing structure.
Information hierarchy for a technical product
Financial interfaces can overwhelm users when price, indicators, reference levels, and model outputs arrive as undifferentiated numbers. The interface separates trend, momentum, pattern, reference levels, and model context. Each element needs a unit, timeframe, loading state, and explanation of what it represents.
The free-to-paid journey is explicit: users can explore public material, create an account, use a watchlist, and unlock deeper analysis through a subscription. An analysis failure must be distinguishable from a neutral market reading. A missing price is not zero, and indicator agreement is not prediction accuracy.
Market-data normalization and analysis boundaries
The documented API targets 300 selected-timeframe candles and requires at least 210 so a 200-period moving average is not computed from insufficient history. Crypto requests prefer Coinbase with Yahoo as a secondary source. Provider failure produces an unavailable response rather than synthetic prices.
The 30-minute fallback aggregates complete 5-minute candles using first open, highest high, lowest low, last close, and summed volume. Ordering, timestamp deduplication, and complete interval coverage are prerequisites for valid aggregation.
Illustrative, simplified code explaining the implementation pattern. This is not a copy of private production source.
// Illustrative complete-bucket aggregation.
function aggregateThirtyMinutes(bars: Candle[]): Candle {
const sorted = [...bars].sort((a, b) => a.time - b.time);
if (sorted.length !== 6) throw new Error("Incomplete bucket");
for (let i = 1; i < sorted.length; i++) {
if (sorted[i].time - sorted[i - 1].time !== 300)
throw new Error("Non-contiguous candles");
}
return {
time: sorted[0].time,
open: sorted[0].open,
high: Math.max(...sorted.map(bar => bar.high)),
low: Math.min(...sorted.map(bar => bar.low)),
close: sorted[5].close,
volume: sorted.reduce((sum, bar) => sum + bar.volume, 0)
};
}The server supplies protected candle data, while client-side calculations and chart interactions support exploration. Indicator definitions remain explicit: RSI uses Wilder smoothing; MACD uses 12/26 EMAs and a 9-period signal; the project’s ATR-style range is an arithmetic mean rather than Wilder-recursive ATR. Those differences matter to accurate labeling.
Authentication, billing, and usage enforcement
Cookie-based Supabase SSR clients support server-rendered account flows. Identity verification is separate from subscription authorization. The repository checks plan-authorized timeframes, active or recognized billing status, and a daily usage RPC before exposing metered market analysis.
The production metering path fails closed when enforcement is unavailable. A browser badge or user-editable profile field cannot grant paid access. Server-side Stripe validation and restricted database operations enforce the business boundary. User-specific responses must not be served from a shared public cache.
The source documents row-level-secured usage counters and versioned legal acceptance records. Billing and credentials stay behind server boundaries; the interface exposes remaining usage and account state rather than implementation secrets.
Responsive rendering and data integrity
Chart initialization and teardown belong to the client lifecycle. Container resize handling must update the chart without recreating subscriptions unnecessarily. A symbol or timeframe change needs to cancel or discard older results so delayed data cannot overwrite the current selection.
Illustrative, simplified code explaining the implementation pattern. This is not a copy of private production source.
let requestVersion = 0;
async function selectMarket(symbol: string, interval: string) {
const version = ++requestVersion;
setAnalysisState({ kind: "loading", symbol, interval });
try {
const candles = await marketApi.fetchCandles(symbol, interval);
if (version !== requestVersion) return;
validateCandleSeries(candles);
setAnalysisState({ kind: "ready", symbol, interval, candles });
} catch (error) {
if (version === requestVersion)
setAnalysisState({ kind: "unavailable", symbol, interval });
}
}Validation includes numeric values, monotonic timestamps, candle high/low relationships, and enough data for the selected calculation. Playwright authentication journeys and accessibility checks complement linting and production builds. Provider failures, session expiration, exhausted usage, and billing redirects require distinct test cases.
Result
Current monthly sales reported by the company in the project account.
The result was an easy-to-use website for a company that began without a clear direction, and a very satisfied customer. The reported monthly sales reflect the broader product and business; no financial return for end users or exclusive revenue attribution to the interface is implied.