Skip to content
ashton.aschenbrener
All projects

active project

SignalForge

A production-grade data intake platform. Drag-and-drop CSV/JSON upload, row-level validation against configurable Zod schemas, intelligent preprocessing (currency coercion, email normalization, string trimming), configurable deduplication, import preview with auto-fixed / needs-review / rejected / duplicate row classification, a durable audit trail preserving original and cleaned state, schema profile management, an analytics dashboard with quality metrics, and team workspaces with RBAC.

Next.js 16TypeScriptPostgresDrizzle ORMPapaParseZodClerkTailwind v4Vitest

Problem

What it solves.

Teams that ingest data from external sources spend hours cleaning CSVs, debugging validation errors, and tracking down duplicates. SignalForge turns that into a repeatable pipeline: upload, validate, preview, and commit — with full audit visibility.

What I built

The specific parts I implemented.

›Drag-and-drop CSV/JSON upload with PapaParse
›Row-level validation engine (Zod)
›Intelligent preprocessing (coercion, normalization, aliasing)
›Configurable deduplication strategies
›Import preview with 4-way row classification
›Durable audit trail (original + cleaned state)
›Schema profile management
›Analytics dashboard with quality metrics
›Team workspaces + RBAC (Owner, Admin, Member)

What I owned

My responsibility surface.

Product direction

Backend architecture & data model

Validation engine & deduplication logic

Full-stack implementation

Test + verification strategy

Architecture

How data moves through the system.

filecommitNext.js UI(dashboard, upload, records)Upload dropzone+ PapaParse parsePreprocessor(coerce, normalize, alias)Validation engine(Zod schemas)Dedup enginePostgres(Drizzle ORM)Schema profiles(configurable rules)Analyticsaggregator

Screenshots

What the system looks like.

Dashboard with import metrics: total imports, records stored, data quality, auto-fixed, needs-review, rejected and duplicatesImports page showing all import jobs with status, row counts, and timestampsNew import upload dropzone for CSV and JSON filesAnalytics dashboard with quality breakdown, error rates, and record distributionRecords view listing all committed records with search and filtering

Data model

What entities the system tracks.

ImportJob
- id
- profile_id
- file_name
- row_count
- status
- created_by
- created_at
Row
- id
- import_id
- data
- cleaned_data
- status
- errors
- duplicate_of
SchemaProfile
- id
- name
- rules
- transformations
- duplicate_keys
AuditEntry
- id
- import_id
- row_id
- action
- actor
- diff
- created_at

Failure handling

What happens when something breaks.

Malformed CSV or unparseable file

Dropzone rejects with a descriptive error; no partial writes to the database.

Row fails Zod validation

Row marked as rejected with per-field error details; import continues with remaining rows.

Duplicate row detected

Row classified as duplicate and linked to the original via duplicate_of; not committed as a new record.

Preprocessing coercion fails

Row moved to needs_review instead of silently dropping or corrupting data.

Verification

How I tested or evaluated it.

Eval harness

Cases, expected, actual.

Clean CSV imports without errors

pass
Input
Upload a well-formed CSV with 10 rows matching the active schema profile.
Expected
All 10 rows classified as valid and committed.
Actual
10/10 rows passed validation; import completed with 0 rejected, 0 needs-review.

Messy data is coerced or flagged

pass
Input
Upload CSV with mixed-format amounts ($1,200, 1200, '1,200.50'), inconsistent casing (USER@EXAMPLE.COM), and extra whitespace.
Expected
Rows with coercible values are auto-fixed; uncoercible rows move to needs-review.
Actual
8/10 rows auto-fixed (currency coerced, emails lowered, whitespace trimmed); 2 flagged needs-review for ambiguous values.

Duplicate rows detected at import time

pass
Input
Upload CSV where 3 rows are duplicates of previously committed records (matched on configured keys).
Expected
Duplicates classified and excluded from commit.
Actual
3 rows marked duplicate, linked to originals; 7 new rows committed.

Next improvements

Known gaps & next moves.