FULL STACK

Development Workshop

From Static Pages to Dynamic Applications

🚀 Building the Future of Web Development

The Evolution of Web Architecture 🌐

Let's travel through time and see how web development evolved...

Press ↓ to begin the journey

1990s

🏗️ HTML: The Foundation

Static pages with just structure and content


<html>
  <body>
    <h1>Welcome to the Web!</h1>
    <p>This is a static page.</p>
  </body>
</html>
                  
Late 1990s

🎨 HTML + CSS: Adding Style

Separation of content and presentation


body {
  font-family: Arial, sans-serif;
  background-color: #f0f0f0;
}

h1 {
  color: #333;
  text-align: center;
}
                  
Early 2000s

⚡ HTML + CSS + JavaScript: Interactivity

Dynamic behavior and user interactions


function showMessage() {
  alert('Hello, Interactive Web!');
}

document.getElementById('button')
  .addEventListener('click', showMessage);
                  
2009-2012

🅰️ Angular Era: The Framework Revolution

Structured applications with MVC architecture


angular.module('myApp', [])
  .controller('MyController', function($scope) {
    $scope.message = 'Hello Angular World!';
  });
                  
2013-Present

⚛️ React: Component-Based Architecture

Reusable components and virtual DOM


function Welcome({ name }) {
  return <h1>Hello, {name}!</h1>;
}

function App() {
  return <Welcome name="React World" />;
}
                  
2016-Present

🚀 Next.js: Full Stack Made Simple

Server-side rendering, API routes, and more!


// pages/api/hello.js
export default function handler(req, res) {
  res.status(200).json({ message: 'Hello from Next.js!' });
}

// pages/index.js
export default function Home({ data }) {
  return <h1>{data.message}</h1>;
}
                  

What is "Full Stack"? 🤔

Building both ends of the application spectrum

👆 Frontend (What users see)

👇 Backend (What powers it all)

🎨

Frontend (Client-Side)

User Interface & Experience

Visual design • User interactions • Data presentation

HTML, CSS, JavaScript, React
⚙️

Backend (Server-Side)

Logic, Data & Infrastructure

Business logic • Database operations • API endpoints

Node.js, Express, Databases, APIs

The Full Stack Developer

Frontend Skills

UI/UX Design
Component Architecture
State Management

+

Backend Skills

API Development
Database Design
Server Management

Defining Our Technology Stack 🛠️

A stack is your chosen set of technologies that work together

Think of it like choosing your tools for a specific job

Stack Components (Backend)

🗄️

Database

The foundation where all your data lives and breathes

MongoDB PostgreSQL MySQL
🖥️

Backend/Server

The brain that processes logic and handles requests

Node.js Express Python

Stack Components (Frontend)

🎨

Frontend

The beautiful face users interact with every day

React Vue Angular
🌐

Runtime

The environment where everything comes alive

Browser Node.js Cloud

Popular Stack Options 🗺️

Different combinations for different needs

💡LAMP Stack

Linux, Apache, MySQL, PHP

Traditional web development

⚛️ MERN Stack

MongoDB, Express, React, Node.js

Modern JavaScript ecosystem

🐍 Django Stack

Django, PostgreSQL, Python

Rapid development with Python

💎 Ruby on Rails

Rails, PostgreSQL, Ruby

Convention over configuration

Choosing the Right Stack

🎯

Project Requirements

What are you building?

E-commerce Blog Dashboard
👥

Team Expertise

What does your team know?

JavaScript Python PHP

Performance Needs

How fast does it need to be?

Real-time Standard Heavy Load
📈

Scalability

How will it grow?

Small Medium Enterprise
🕒

Development Speed

How quickly do you need to ship?

Prototype MVP Production
💰

Budget & Resources

What can you afford?

Free Low Cost Enterprise

Code in Action 💻

Let's see what each layer looks like in practice

Frontend: React Component


import React, { useState, useEffect } from 'react';
import './UserProfile.css';

// UserProfile component with full CRUD functionality
function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  // Fetch user data on component mount
  useEffect(() => {
    const fetchUser = async () => {
      try {
        const response = await fetch(`/api/users/${userId}`);
        if (!response.ok) throw new Error('User not found');
        const userData = await response.json();
        setUser(userData);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchUser();
  }, [userId]);

  // Handle user data updates
  const updateUser = async (updatedData) => {
    try {
      const response = await fetch(`/api/users/${userId}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(updatedData)
      });
      const updatedUser = await response.json();
      setUser(updatedUser);
    } catch (err) {
      setError('Failed to update user');
    }
  };

  if (loading) return <div className="spinner">Loading...</div>;
  if (error) return <div className="error">Error: {error}</div>;

  return (
    <div className="user-profile">
      <div className="profile-header">
        <img src={user.avatar} alt={user.name} className="avatar" />
        <h2>{user.name}</h2>
        <p className="email">{user.email}</p>
      </div>
      
      <div className="profile-details">
        <p><strong>Joined:</strong> {new Date(user.joinDate).toLocaleDateString()}</p>
        <p><strong>Posts:</strong> {user.postCount}</p>
        <p><strong>Status:</strong> {user.isActive ? 'Active' : 'Inactive'}</p>
      </div>
      
      <button onClick={() => updateUser({ ...user, lastSeen: new Date() })}>
        Mark as Seen
      </button>
    </div>
  );
}

export default UserProfile;
            

Backend: Express API Server


const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
const User = require('./models/User');

// Initialize Express app with middleware
const app = express();
app.use(helmet()); // Security headers
app.use(cors()); // Enable CORS
app.use(express.json({ limit: '10mb' })); // Parse JSON bodies
app.use(express.static('public')); // Serve static files

// Rate limiting middleware
const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100 // limit each IP to 100 requests per windowMs
});
app.use('/api/', limiter);

// GET user by ID with full profile data
app.get('/api/users/:id', async (req, res) => {
  try {
    const userId = req.params.id;
    const user = await User.findById(userId)
      .populate('posts')
      .select('-password'); // Exclude sensitive data
    
    if (!user) {
      return res.status(404).json({ 
        error: 'User not found',
        code: 'USER_NOT_FOUND' 
      });
    }
    
    // Add computed fields
    const userWithStats = {
      ...user.toObject(),
      postCount: user.posts.length,
      isActive: user.lastSeen > new Date(Date.now() - 24 * 60 * 60 * 1000)
    };
    
    res.json(userWithStats);
  } catch (error) {
    console.error('Database error:', error);
    res.status(500).json({ 
      error: 'Internal server error',
      code: 'DATABASE_ERROR' 
    });
  }
});

// PUT update user profile
app.put('/api/users/:id', async (req, res) => {
  try {
    const userId = req.params.id;
    const updates = req.body;
    
    // Validate and sanitize updates
    const allowedUpdates = ['name', 'email', 'bio', 'lastSeen'];
    const filteredUpdates = Object.keys(updates)
      .filter(key => allowedUpdates.includes(key))
      .reduce((obj, key) => ({ ...obj, [key]: updates[key] }), {});
    
    const updatedUser = await User.findByIdAndUpdate(
      userId, 
      filteredUpdates, 
      { new: true, runValidators: true }
    ).select('-password');
    
    if (!updatedUser) {
      return res.status(404).json({ error: 'User not found' });
    }
    
    res.json(updatedUser);
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

// Start server
const PORT = process.env.PORT || 3001;
app.listen(PORT, () => {
  console.log(`🚀 Server running on port ${PORT}`);
});
            

Database: Complete Schema & Operations


-- Create users table with constraints and indexes
CREATE TABLE users (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  name TEXT NOT NULL CHECK(length(name) > 0),
  email TEXT UNIQUE NOT NULL CHECK(email LIKE '%@%.%'),
  bio TEXT DEFAULT '',
  avatar_url TEXT,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  last_seen DATETIME DEFAULT CURRENT_TIMESTAMP,
  is_active BOOLEAN DEFAULT 1
);

-- Create posts table with foreign key relationship
CREATE TABLE posts (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  user_id INTEGER NOT NULL,
  title TEXT NOT NULL,
  content TEXT NOT NULL,
  published BOOLEAN DEFAULT 0,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

-- Create indexes for better query performance
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_active ON users(is_active, last_seen);
CREATE INDEX idx_posts_user ON posts(user_id);
CREATE INDEX idx_posts_published ON posts(published, created_at);

-- Insert sample data with transaction
BEGIN TRANSACTION;
INSERT INTO users (name, email, bio) VALUES 
  ('John Doe', 'john@example.com', 'Full-stack developer'),
  ('Jane Smith', 'jane@example.com', 'UI/UX Designer'),
  ('Bob Johnson', 'bob@example.com', 'DevOps Engineer');

INSERT INTO posts (user_id, title, content, published) VALUES 
  (1, 'Getting Started with React', 'React is a powerful...', 1),
  (1, 'Advanced Node.js Patterns', 'In this post...', 1),
  (2, 'Design Systems 101', 'Creating consistent...', 1);
COMMIT;

-- Complex query: Get user with post statistics
SELECT 
  u.id,
  u.name,
  u.email,
  u.created_at,
  COUNT(p.id) as post_count,
  MAX(p.created_at) as latest_post,
  CASE 
    WHEN u.last_seen > datetime('now', '-1 day') THEN 'active'
    ELSE 'inactive'
  END as status
FROM users u
LEFT JOIN posts p ON u.id = p.user_id AND p.published = 1
WHERE u.is_active = 1
GROUP BY u.id, u.name, u.email, u.created_at, u.last_seen
ORDER BY post_count DESC, u.created_at DESC;

-- Update user last seen timestamp
UPDATE users 
SET last_seen = CURRENT_TIMESTAMP,
    updated_at = CURRENT_TIMESTAMP
WHERE id = ?;
            

Our Workshop Stack 🚀

Next.js + Turborepo + Express + SQLite

Frontend Technologies 🎨

Next.js

Full-Stack React Framework

SSR & SSG API Routes File Routing
Production-ready React framework with built-in optimization and routing
🎨

Tailwind CSS

Utility-First CSS Framework

Rapid Styling Responsive Customizable
Modern CSS framework for building beautiful UIs with utility classes
📦

Turborepo

Monorepo Build System

Fast Builds Caching Task Pipeline
High-performance monorepo tool for managing multiple packages efficiently

Backend Technologies 🖥️

。🇯‌🇸‌

Node.js

JavaScript Runtime

V8 Engine NPM Ecosystem Async I/O
High-performance JavaScript runtime powering our backend services
⚡︎

Express.js

Database API Server

REST APIs Middleware Database Layer
Dedicated Express server handling all database interactions and API endpoints
🗄️

SQLite

Embedded Database

File-based Zero Config ACID
Lightweight, serverless database perfect for development and prototyping

Why This Stack?

Perfect for Modern Development

Speed, Simplicity, Scalability

🚀

Production Ready

Next.js provides full‑stack capabilities out of the box

Lightning Fast

Turborepo accelerates builds with smart caching

🎨

Rapid Styling

Tailwind CSS enables instant UI development

Why This Stack?

Perfect for Modern Development

Speed, Simplicity, Scalability

🗄️

Zero Config Database

SQLite works immediately — no setup required

🔧

Monorepo Ready

Scales from prototype to enterprise architecture

📦

Industry Standard

Battle‑tested tools used worldwide

Why This Stack?

Clean Architecture Separation
🎯

Next.js Frontend

UI, API routes, and server‑side rendering

🖥️

Express.js Backend

Dedicated database API server

🏗️

Turborepo Management

Efficient multi‑package coordination

Why This Stack?

Developer Experience
🧩

Single Language

  • JavaScript/TypeScript end‑to‑end
  • Shared types across client & server
  • Lower context switching
🧪

Testing Friendly

  • API routes easy to unit test
  • Component testing with JSDOM
  • Mock DB via SQLite file
🧰

Tooling

ESLint Prettier TypeScript Turborepo

Why This Stack?

Performance & Deployment
📦

Optimized Delivery

  • Static + SSR hybrid rendering
  • Image & font optimization
  • Code splitting by route
☁️

Deploy Anywhere

  • Vercel / Netlify friendly
  • Node server or serverless
  • Edge‑ready routes
📈

Scale

  • Monorepo pipelines
  • Caching & incremental builds
  • Shared UI libraries

Why This Stack?

Considerations
⚠️

Trade‑offs

  • Learning curve for full‑stack Next
  • Build tooling complexity
  • Serverless cold starts (varies)
🧭

When To Use

  • Rapid MVPs to production
  • Teams sharing UI & APIs
  • DX and speed are priorities

What We'll Build Together

In 45 Minutes

Task Management App

Create Tasks

Add, edit, and complete tasks

🗂️

Categories

Organize by lists or tags

💾

SQLite Persistence

Local DB via Express API

🎨

Beautiful UI

React Tailwind Liquid Glass

Ready to build something amazing? 🚀

Ready to Code? 💻

Let's build our full stack application!

🎯 Next: Live Coding Session

⏱️ Duration: 45 minutes

🚀 From zero to deployed app!

QR Code to GitHub Template
Get Started Now

Grab the Template

📱 Scan the QR code

💻 Or visit the repo directly

github.com/MelodicAlbuild/
hackuta-website-template