← All Projects

Aion Security

A domain reconnaissance and dependency scanning platform.

Python FastAPI Next.js PostgreSQL OSV.dev API
Aion Security screenshot

Seeing how exposed a domain looks from the outside normally means juggling a handful of separate tools: one for SSL/TLS, another for HTTP security headers, another for email spoofing protection, blacklists, exposed files, cookies, and DNS hygiene. Each has its own output to interpret. Aion Security puts those checks in one place. A free, instant scan grades a domain from A to F across each category and overall. Optional monitoring adds scan history, alerts when a grade regresses, and monthly PDF reports. A companion dependency scanner checks npm, Yarn, pip, and Composer lockfiles against OSV.dev, with no signup required.

The backend is a Python FastAPI service served by Uvicorn, using SQLAlchemy over PostgreSQL. JSONB columns store the raw scan results. The frontend is a separate Next.js (App Router), React, and TypeScript app styled with Tailwind CSS. Every scan goes through a single run_full_scan() function, so the free scan, scheduled re-scans, and PDF reports all agree on one canonical result shape. A grading module then turns raw findings into per-category and weighted overall A-F grades. Authentication is delegated entirely to Clerk. The backend verifies Clerk session tokens and stays in sync with Clerk Billing through signed webhooks, so it never stores a password. Subscription tiers unlock more monitored domains, Slack alerts (delivered through plain incoming webhooks), and monthly reports generated with ReportLab. Public endpoints are rate limited with slowapi. Scheduled workers handle the recurring work: a daily worker re-scans monitored domains on their configured cadence, another emails monthly reports, and a third refreshes a curated security-news feed from trusted RSS sources every four hours.

The first production deploy returned a 500 on every page. Next.js's Proxy layer (the renamed Middleware) turned out to make a real HTTP request back into the app itself, and the way the server was configured to listen broke that internal call. Fixing the server configuration resolved it, and the whole episode went into the deployment runbook so it never has to be rediscovered. Schema drift was the second lesson. SQLAlchemy's create_all() only creates missing tables; it never alters existing ones. Adding a new subscription tier meant an ALTER TYPE against a native Postgres enum, and forgetting it would have made every webhook write fail. Each model change now ships with its migration documented and applied by hand before deploying. A third was a silent dependency break. A routine pip install pulled a new major version of the webhook-verification library that changed what its verify call returns, turning every Clerk webhook into a 500. The dependency is now pinned below that version, with a comment explaining why. To keep changes like that from slipping through, the backend test suite runs entirely against a temporary SQLite file with no Postgres, Clerk, SMTP, or network dependency, and runs on every push in CI.

Visit Site