How I Built a Full-Stack AI Meeting Minutes App in 7 Days – And How You Can Too (With Security Built-In) + Video

Listen to this Post

Featured Image

Introduction:

The intersection of generative AI and full-stack development has given rise to a new breed of intelligent applications that can transcribe, summarize, and extract actionable insights from audio in real-time. Hasham Ahmad recently demonstrated this by building “MeetingMind AI” – a complete local-first MVP with cloud-ready architecture that processes meeting audio through Whisper for transcription and GPT for structured minutes generation. This article breaks down the technical architecture, implementation steps, and critical security considerations every AI engineer must address when deploying similar systems in production.

Learning Objectives:

  • Understand the end-to-end architecture of an AI-powered meeting minutes application, from audio upload to structured JSON output.
  • Learn how to implement asynchronous job processing with Hangfire, FFmpeg, Whisper, and OpenAI GPT integration.
  • Master security hardening techniques for AI pipelines, including API key management, input validation, and secure file handling.

You Should Know:

1. The AI-Driven Development Lifecycle: Discovery, Confirmation, Implementation

Hasham’s approach wasn’t about asking ChatGPT to generate the entire application in one prompt. Instead, he followed a disciplined three-stage methodology that kept him in control while leveraging AI as a collaborator.

What this does: The Discovery Codex stage reviews requirements, architecture, backlog, and existing code – turning ambiguities into explicit questions rather than hidden assumptions. Confirmation ensures each phase has an agreed scope, implementation plan, architectural decisions, risks, and acceptance criteria. Implementation then builds sequentially – persistence, uploads, background processing, status tracking, FFmpeg, Whisper, GPT integration, retry/history, and frontend – with each phase verified before continuing.

How to use it:

bash
Stage 1: Discovery – Document your requirements
Create a requirements.md file with:
– Functional requirements (upload, transcribe, summarize)
– Non-functional requirements (latency, scalability, security)
– Architecture decisions (why Hangfire? why PostgreSQL?)

Stage 2: Confirmation – Define acceptance criteria
Example: “The API must return a job ID within 200ms of upload”

Stage 3: Implementation – Build in vertical slices
Start with the data layer, then API endpoints, then background workers
[/bash]

2. Asynchronous Job Processing Architecture

The MeetingMind AI workflow is entirely asynchronous: Upload → Create job → Hangfire queue → FFmpeg conversion → Whisper transcription → GPT minutes generation → Save results. This decoupling is essential for AI applications where processing can take minutes.

What this does: The API returns a job ID immediately, allowing the frontend to display progress while a separate worker handles the long-running audio and AI processing. Hangfire manages the queue, retries on failure, and provides visibility into job status.

How to implement it (ASP.NET Core):

bash
// 1. Configure Hangfire in Program.cs
services.AddHangfire(config => config
.UsePostgreSqlStorage(Configuration.GetConnectionString(“HangfireConnection”)));
app.UseHangfireDashboard(); // Secure this in production!

// 2. Define your background job
public class MeetingProcessor
{
public async Task ProcessMeeting(Guid jobId, string audioFilePath)
{
// Step 1: Convert audio with FFmpeg
var wavPath = await ConvertToWav(audioFilePath);

// Step 2: Transcribe with Whisper
var transcript = await TranscribeWithWhisper(wavPath);

// Step 3: Generate minutes with GPT
var minutes = await GenerateMinutesWithGPT(transcript);

// Step 4: Save results to PostgreSQL
await SaveMeetingMinutes(jobId, transcript, minutes);
}
}

// 3. Enqueue the job from your API controller
BackgroundJob.Enqueue(p => p.ProcessMeeting(jobId, filePath));
[/bash]

3. Secure API Key Management for OpenAI Integration

The application integrates with OpenAI GPT for structured JSON output. In production, exposing API keys in code or client-side is a critical vulnerability.

What this does: Proper key management ensures that your OpenAI credentials are never exposed in logs, client-side code, or version control.

How to secure it (Linux/macOS):

bash
Store your OpenAI API key as an environment variable
export OPENAI_API_KEY=”sk-…”
Or use a .env file (never commit this to Git!)
echo “OPENAI_API_KEY=sk-…” >> .env
echo “.env” >> .gitignore

For production on Linux servers, use systemd environment files
/etc/systemd/system/yourapp.service.d/env.conf
bash
Environment=”OPENAI_API_KEY=sk-…”
[/bash]

How to secure it (Windows):

bash
Set system-wide environment variable
Or use Azure Key Vault / AWS Secrets Manager for production
Azure CLI example:
az keyvault secret set –vault-1ame “MyKeyVault” –1ame “OpenAIKey” –value “sk-…”
[/bash]

Best practice: In ASP.NET Core, use `IConfiguration` with Azure Key Vault or AWS Secrets Manager:
bash
// Program.cs
builder.Configuration.AddAzureKeyVault(
new Uri(“https://mykeyvault.vault.azure.net/”),
new DefaultAzureCredential());
// Then access securely
var apiKey = configuration[“OpenAIKey”];
[/bash]

4. Secure File Upload and FFmpeg Processing

MeetingMind AI allows users to upload meeting audio files. File uploads are a common attack vector – malicious files can contain exploits or overwhelm storage.

What this does: Implements validation, sanitization, and secure processing of uploaded audio files before they reach FFmpeg and Whisper.

Step-by-step guide:

  1. Validate file type and size – Only allow .mp3, .wav, `.m4a` with a maximum size (e.g., 100MB).
  2. Store files outside the web root – Never store uploads in `wwwroot` or publicly accessible directories.
  3. Use a random GUID for filenames – Prevent path traversal attacks.
  4. Run FFmpeg in a sandboxed environment – Use containerization or restricted user permissions.

bash
// ASP.NET Core secure file upload
[HttpPost(“upload”)]
public async Task Upload(IFormFile file)
{
// 1. Validate file extension
var allowedExtensions = new[] { “.mp3”, “.wav”, “.m4a” };
var ext = Path.GetExtension(file.FileName).ToLowerInvariant();
if (!allowedExtensions.Contains(ext))
return BadRequest(“Invalid file type”);

// 2. Validate file size (100MB limit)
if (file.Length > 100 1024 1024)
return BadRequest(“File too large”);

// 3. Generate secure filename
var secureFileName = $”{Guid.NewGuid()}{ext}”;
var storagePath = Path.Combine(“/secure/upload/storage”, secureFileName);

// 4. Save with restricted permissions
using (var stream = new FileStream(storagePath, FileMode.Create))
{
await file.CopyToAsync(stream);
}
// Set restrictive permissions (Linux)
// chmod 600 /secure/upload/storage/

return Ok(new { jobId = Guid.NewGuid(), fileName = secureFileName });
}
[/bash]

FFmpeg security: Always validate that FFmpeg is processing expected audio formats. Consider running FFmpeg in a Docker container with limited resources:
bash
Run FFmpeg with resource limits
docker run –rm -v /uploads:/uploads -m 512m –cpus=0.5 jrottenberg/ffmpeg \
-i /uploads/input.mp3 -ar 16000 -ac 1 /uploads/output.wav
[/bash]

5. Structured JSON Output and Prompt Injection Prevention

The application uses OpenAI GPT with structured JSON output. Without proper safeguards, prompt injection attacks could manipulate the model’s behavior.

What this does: Implements system prompts, input sanitization, and output validation to ensure the GPT model produces safe, structured results.

Step-by-step guide:

  1. Use a system prompt that defines the role and output format strictly.
  2. Sanitize user inputs before including them in prompts.
  3. Validate JSON output against a schema before storing or displaying.

bash
Python example with OpenAI
import openai
import json
from jsonschema import validate

system_prompt = “””
You are a secure meeting minutes generator. Your output MUST be valid JSON with this schema:
{
“summary”: “string”,
“decisions”: [“string”],
“action_items”: [{“task”: “string”, “assignee”: “string”, “deadline”: “string”}],
“risks”: [“string”],
“next_steps”: [“string”]
}
Do not include any additional text, markdown, or explanations outside the JSON.
“””

def generate_minutes(transcript):
Sanitize transcript – remove potential injection attempts
sanitized = transcript.replace(““`”, “”).replace(“;”, “.”)

response = openai.ChatCompletion.create(
model=”gpt-4″,
messages=[
{“role”: “system”, “content”: system_prompt},
{“role”: “user”, “content”: f”Generate minutes from this transcript: {sanitized}”}
],
temperature=0.3
)

Parse and validate JSON
try:
result = json.loads(response.choicesbash.message.content)
Validate against schema (using jsonschema library)
validate(instance=result, schema=SCHEMA)
return result
except (json.JSONDecodeError, ValidationError) as e:
Log and return error – never display raw model output to users
raise ValueError(“Invalid output from AI model”)
[/bash]

6. Database Security and Connection Hardening

The application uses PostgreSQL and Entity Framework Core. Securing the database connection and queries is non-1egotiable in production.

What this does: Ensures database credentials are never exposed, queries are parameterized, and sensitive data is encrypted.

Step-by-step guide:

bash
// 1. Use connection strings from secure configuration
// appsettings.json (never store real credentials here!)
{
“ConnectionStrings”: {
“DefaultConnection”: “Host=localhost;Database=meetingmind;Username=;Password=”
}
}

// 2. In production, use environment variables or Azure Key Vault
// Program.cs
builder.Configuration.AddEnvironmentVariables();
var connectionString = builder.Configuration.GetConnectionString(“DefaultConnection”);

// 3. Always use parameterized queries (EF Core does this automatically)
// Example: Never concatenate strings into SQL
var meetings = await context.Meetings
.FromSqlRaw(“SELECT FROM Meetings WHERE UserId = {0}”, userId)
.ToListAsync();

// 4. Encrypt sensitive data at rest
// Use PostgreSQL’s pgcrypto extension
// CREATE EXTENSION IF NOT EXISTS pgcrypto;
// INSERT INTO Meetings (Transcript) VALUES (pgp_sym_encrypt(‘…’, ‘encryption_key’));

// 5. Enable SSL/TLS for database connections
// “Host=myhost;Database=mydb;Username=user;Password=pass;SSL Mode=Require;”
[/bash]

7. Frontend Security: React and API Communication

The frontend uses React and Material UI. Securing the React application and its communication with the backend is critical.

What this does: Prevents XSS, CSRF, and ensures all API calls are authenticated and encrypted.

Step-by-step guide:

  1. Always use HTTPS – Enforce SSL/TLS for all API endpoints.
  2. Implement JWT-based authentication – Never store tokens in localStorage (use HttpOnly cookies).
  3. Sanitize all user-generated content before rendering in React.
  4. Use environment variables for API URLs – Never hardcode production URLs.

bash
// React best practices
// 1. Use HttpOnly cookies for authentication (not localStorage)
// 2. Sanitize transcript display
import DOMPurify from ‘dompurify’;

function TranscriptDisplay({ transcript }) {
// Never use dangerouslySetInnerHTML without sanitization
const sanitized = DOMPurify.sanitize(transcript);
return

;
}

// 3. Secure API calls with credentials
const response = await fetch(‘/api/meetings’, {
credentials: ‘include’, // Send cookies automatically
headers: {
‘Content-Type’: ‘application/json’,
‘X-CSRF-TOKEN’: csrfToken // For CSRF protection
}
});
[/bash]

8. Monitoring, Logging, and Incident Response

Hangfire provides job status tracking and retry capabilities. In production, you need comprehensive logging and monitoring to detect anomalies.

What this does: Provides visibility into job failures, performance bottlenecks, and potential security incidents.

How to implement:

bash
// Structured logging with Serilog
Log.Information(“Job {JobId} started processing audio {AudioFile}”, jobId, audioFile);
Log.Warning(“Job {JobId} retry {RetryCount} due to transient error”, jobId, retryCount);
Log.Error(ex, “Job {JobId} failed permanently”, jobId);

// Monitor Hangfire dashboard – secure it with authentication
app.UseHangfireDashboard(“/hangfire”, new DashboardOptions
{
Authorization = new[] { new HangfireAuthorizationFilter() }
});

// Set up alerts for:
// – Job failure rate > 5%
// – Processing time > 5 minutes
// – Unusual API key usage patterns
[/bash]

What Undercode Say:

  • Key Takeaway 1: AI-assisted development is most effective when AI is treated as an engineering collaborator, not a code generator. Clear requirements, controlled scope, documented decisions, and continuous verification enable rapid development without losing control of the codebase.
  • Key Takeaway 2: The asynchronous architecture (Upload → Queue → Process → Save) is the gold standard for AI applications. By decoupling the API from long-running tasks, you maintain responsiveness, enable retries, and provide real-time progress tracking to users.
  • Analysis: Hasham’s one-week MVP demonstrates that with the right methodology and tools, even complex AI pipelines can be built quickly. However, the security considerations highlighted here are often overlooked in rapid development. API key exposure, prompt injection, insecure file uploads, and database vulnerabilities are the top risks in AI applications. Organizations must adopt a “security-by-design” approach, integrating input validation, encryption, and monitoring from day one. The future of AI engineering lies not just in building smarter models, but in building secure, resilient, and observable systems that can withstand real-world threats. As AI becomes more embedded in business workflows, the attack surface expands – and so does the responsibility of the AI engineer.

Prediction:

  • +1 The AI-Driven Development Lifecycle methodology will become a standard practice in software engineering, reducing development time by 40-60% while maintaining code quality and security.
  • +1 Asynchronous job processing with tools like Hangfire, Celery, or AWS Step Functions will become the default architecture for all AI applications, enabling better scalability and fault tolerance.
  • -1 The rapid adoption of AI APIs (OpenAI, Anthropic, etc.) will lead to a surge in API key leaks and credential stuffing attacks, prompting a new wave of API security standards and automated key rotation tools.
  • -1 Prompt injection attacks will evolve into a major OWASP Top 10 category, forcing organizations to implement robust input sanitization and output validation layers for all LLM integrations.
  • +1 The convergence of full-stack development and AI engineering will create a new role – the “AI Full-Stack Engineer” – who understands both frontend/backend development and LLM orchestration, security, and observability.

▶️ Related Video (66% Match):

🎯Let’s Practice For Free:

🎓 Live Courses & Certifications:

Join Undercode Academy for Verified Certifications

🚀 Request a Custom Project:

Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands

IT/Security Reporter URL:

Reported By: Hashamahmad Aiengineering – Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow UndercodeTesting & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin | 🦋BlueSky