I Built a Mission Engineering Platform and It’s Live — Here’s How It Works
So I shipped a thing. It’s called SMAD Portal, and it’s a web app for spacecraft mission engineering. If you’ve ever had the pleasure of managing requirements in Excel, tracking a mass budget across three different Google Sheets, or assembling a PDR review package from a dozen scattered documents — this is for you. Or rather, against all of that.
The name comes from SMAD (Space Mission Analysis & Design), the textbook that every systems engineer in aerospace has dog-eared on their desk. The app tries to be what that book would look like if it were a living, collaborative web tool instead of 900 pages of paper.
It’s live now, and I want to walk through the technical side of how it’s built — because I think the stack and some of the architectural choices are interesting even if you don’t care about orbit mechanics.
The Scope (It Got Big)
What started as “I’ll build a simple requirements tracker” turned into… well, a lot. The portal currently has 142+ pagesand 111 Vue components. Here’s the feature rundown:
Orbit design and maneuver planning with a reference orbit library. Spacecraft sizing and configuration. Full mass, power, thermal, and delta-V budgets broken down by subsystem. Link budget analysis and antenna design. Requirements management with hierarchical trees and a traceability matrix that actually works. Risk registers. FMEA. Phase gate tracking across all eight standard review gates — SRR, SDR, PDR, CDR, TRR, FRR, ORR, and Decommissioning Review. Trade studies. Cost budgeting with earned value management. An AI-assisted requirements generator. A constellation optimizer. And a one-click review package PDF export that pulls it all together.
Yeah. Scope creep is real and I leaned into it.
The Stack
Nuxt 3.21 with Vue 3 in TypeScript strict mode, built on Vite 7. Pinia 3 for state management. Supabase on the backend — Postgres with Row-Level Security, PostgREST for the data API, GoTrue for auth. Stripe for billing (but it’s optional — keep reading). Testing with Vitest and happy-dom.
Some fun extras: NASA’s OpenMCT 2.2.4 is bundled in for telemetry visualization. PDFMake generates review package PDFs server-side. Sentry for error tracking. And the font — Poppins — is bundled locally via @fontsource/poppins. Zero CDN calls. This matters because some of my target users are behind air-gapped networks on classified programs and can’t reach out to Google Fonts.
The Look: Dark-Only, On Purpose
No light mode. This was intentional from day one, and I know that’s a spicy take.
The reasoning: mission engineers work in operations centers and lab environments where dark UIs are standard. I wanted SMAD Portal to feel like it belongs next to a NASA Open MCT dashboard — not like another SaaS app that got its color palette from a Dribbble shot.
The design system uses a deep navy background (#0d0f2b — not pure black, which looks lifeless on most monitors), semi-transparent card layering at rgba(255, 255, 255, 0.03), and an accent blue (#4f60fa) everywhere. All typography is in pixels, never rem. Aerospace UIs are data-dense, and I didn’t want cascading font inheritance doing anything unpredictable. Every size is explicit, every layout is predictable.
Tables use font-variant-numeric: tabular-nums so your mass budget columns actually line up. Small detail, huge difference when you’re scanning numbers.
RBAC That Actually Fits Aerospace Teams
This was one of the more fun engineering problems. Aerospace teams don’t fit neatly into a single role hierarchy. Your thermal lead on Mission A might just be a reviewer on Mission B. A company admin needs org-wide powers, but shouldn’t automatically get engineering permissions on every mission.
So I built a two-layer RBAC system.
Layer one is portal-level: member, engineer, lead_engineer, systems_engineer, program_manager, company_admin. These come from your profile and gate things like “can you create missions” or “can you use AI features.”
Layer two is per-mission, with twelve roles: owner, chief_engineer, mission_engineer, subsystem_lead, systems_engineer, program_manager, quality_assurance, safety_officer, test_engineer, document_author, reviewer, and viewer. Each role maps to specific capabilities, and you can hold different roles on different missions.
Server-side, three functions handle it: requireAuth() validates the JWT, requirePortalCap() checks portal capabilities, requireMissionCap() checks mission-level access. Client-side, the useRBAC() composable does synchronous portal checks and async mission checks with a per-mission cache (keyed by userId:missionId) to kill the N+1 problem.
The best part: Supabase RLS enforces the same logic at the database layer with custom Postgres functions. The application code never writes .eq('user_id', ...) on a query. The database just handles it.
The Traceability Engine
This is the feature I’m most proud of. Requirements traceability in aerospace is supposed to flow from stakeholder needs, through requirements, to risks and verification items, and ultimately to phase gate review items. It’s a directed acyclic graph, and in practice, everyone just draws arrows in PowerPoint and hopes for the best.
SMAD Portal models this with five junction tables: stakeholder_need_requirements, requirement_risks, requirement_verifications, verification_phase_gates, and risk_phase_gates. Each link stores a rationale and full audit metadata. A LinkedItemsPanel component (24KB of Vue — it’s a beast) handles the UI for creating and navigating connections across all five directions.
The payoff: you’re in a PDR and someone asks “which requirements does this risk trace to, and are the verification items complete?” One click. Not forty-five minutes of spreadsheet archaeology.
Air-Gap Mode: One Env Var
Here’s something I’m really happy about architecturally. Aerospace deployment is split between cloud-happy teams and ITAR/classified programs where software can’t phone home. SMAD Portal handles both with a single environment variable.
STRIPE_ENABLED=true: standard three-tier SaaS — Starter ($29/mo), Professional ($79/mo), Enterprise (contact sales). Feature gates in a centralized tier-features.ts map routes to required tiers.
STRIPE_ENABLED=false: site-license mode. Every user gets Enterprise. Pricing pages redirect to the portal. Stripe routes return 503 (not 404 — deliberate, so the client can show a useful message). Billing UI disappears. The whole thing runs behind Docker with Kong routing to self-hosted GoTrue and PostgREST.
Zero code changes between modes. I’m unreasonably proud of this.
It’s Live — Go Check It Out
The app is up and running. The core is solid: auth, RBAC, billing, the design system, the full traceability engine, 142+ pages of mission engineering tools. I’m still actively building — deeper OpenMCT integration, a smarter AI advisor, and more self-hosted hardening are all in progress.
If you’re building spacecraft and still fighting spreadsheets, come take a look. And if you’re an engineer who just likes poking at how things are built, I hope this walkthrough was interesting. I’m always happy to talk shop.