A survey application that started life as a Nuxt starter and grew into a typed full-stack app with authentication, survey workflows, results reporting, and a repeatable CI/CD pipeline.
The frontend uses Nuxt UI for the interactive shell. Nitro powers API routes under server/api/, while Prisma owns the schema, migrations, seed data, and the generated client. Shared helpers and table logic live in focused folders so UI and server concerns stay separated.
Frontend
Nuxt UI pages, components, composables, and the shared table logic reused across home, admin, and search.
Server
Nitro API routes, middleware, plugins, and request helpers under server/utils/ — input is validated server-side.
Data
Prisma schema, versioned migrations, seed scripts, and a generated client consumed by server routes.
Docs & DX
Public docs under pages/Documentation/, Scalar-rendered OpenAPI, i18n keys, and a preview pipeline for emails.
Feature highlights
What the recent work focused on
A few areas where the codebase moved in meaningful chunks rather than incremental fixes — the cards below summarize the why and the shape of each piece.
Features
Aggregated results + reusable search
An aggregated survey-results API and matching UI panels turned raw answers into something readable. home.vue was split into smaller components so the same survey table can be reused inside the header search box, and table state is persisted and localized.
CI/CD
Modular GitLab CI + Twemoji tree-shaking
The pipeline was split into include files for build, test, package, and deploy stages, with a benchmarking helper to track regressions. A postinstall step now collects only the Twemoji SVGs the app actually references — generated assets stay out of git, and Docker/CI builds get the inputs they need on a fresh clone.
Security
Sign-up flow + brute-force protection
Registration creates a pending account, holds it inactive until email confirmation, and dedupes repeat sign-ups behind a generic 409 so attackers can't probe addresses. IP rate limiting via nuxt-api-shield gates /api/auth/login, /api/auth/register, and /api/survey/accessCode, with a lightweight in-memory helper writing suspicious-activity rows for audit without slowing the hot path.
Email
Templated email + offline preview
Confirmation mail is composed from vue-email components behind a shared EmailLayout that owns <Html>, <Tailwind>, the logo header, and footer links. Theming is implicit — the layout imports app.config.ts so the brand primaryColor flows in without prop drilling. yarn preview-emails renders every template with a previewProps export to email/preview/*.html via Vite SSR, so design iteration doesn't depend on SMTP. DKIM/SPF/DMARC alignment landed alongside, reaching compauth=pass in Outlook.
Finalization
Milestones
From scaffold to today
Picked from the git history. No semantic versions yet, so each entry is dated and grouped under the phase it belongs to.