Architecture & Databases
This lesson covers web architecture: client-side (front-end) vs server-side (back-end) development, databases, and how they work together in modern web applications.
This lesson covers multiple topics with varying importance for your HSC exam. Use this guide to allocate your study time effectively:
ποΈ SQL Databases (40% of study time)
Topics to understand deeply:
These form the foundation for understanding how all pieces fit together.
Topics to be familiar with:
Contextual knowledge:
These provide important context but are less likely to be deeply tested.
ββ TIER 4: Good to Know
W3C is the international standards organization for the web (founded 1994 by Tim Berners-Lee), developing protocols and guidelines for accessibility, interoperability, and evolution of the web.
Develops guidelines for web accessibility covering visual, auditory, physical, speech, cognitive, and neurological disabilities.
Four Core Principles (POUR):
Example: A blind user relies on a screen reader to navigate websites. Without proper alt attributes on images, the screen reader would only say "image" without context. With alt text like <img alt="Shopping cart with 3 items">, the user understands the image's purpose.
Ensures web support for all languages, scripts, and cultures.
lang attribute (<html lang="en">, <html lang="ja">)<article>, <nav>, <header>) vs generic <div>ββββ TIER 2: Very Important
Modern web applications have three layers: client-side, server-side, and database.
Code runs in the user's browser. Controls UI, interactivity, and presentation.
What it does: Defines the content and structure of the webpage
What it does: Controls visual appearance and layout
What it does: Adds interactivity and dynamic behavior
<form id="loginForm">
<label for="email">Email:</label>
<input type="email" id="email" required>
<label for="password">Password:</label>
<input type="password" id="password" required>
<button type="submit">Log In</button>
</form>
form {
max-width: 400px;
padding: 2rem;
background: white;
border-radius: 8px;
}
input {
width: 100%;
padding: 0.8rem;
margin: 0.5rem 0;
border: 1px solid #ccc;
}
button {
background: #007bff;
color: white;
padding: 1rem 2rem;
border: none;
cursor: pointer;
}
document.getElementById('loginForm').addEventListener('submit', function(e) {
e.preventDefault(); // Stop default form submission
const email = document.getElementById('email').value;
const password = document.getElementById('password').value;
// Validate inputs
if (!email.includes('@')) {
alert('Please enter a valid email address');
return;
}
if (password.length < 8) {
alert('Password must be at least 8 characters');
return;
}
// Send login request to server
fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password })
})
.then(response => response.json())
.then(data => {
if (data.success) {
window.location.href = '/dashboard';
} else {
alert('Invalid credentials');
}
});
});
Code runs on the web server. Handles business logic, database operations, authentication, and dynamic content generation.
| Language | Popular Frameworks | Use Cases |
|---|---|---|
| Python | Django, Flask, FastAPI | Data-driven apps, machine learning integration, rapid prototyping |
| JavaScript (Node.js) | Express.js, NestJS, Next.js | Real-time apps (chat), APIs, full-stack JavaScript development |
| PHP | Laravel, Symfony, WordPress | Content management systems, traditional web apps |
| Java | Spring Boot, Jakarta EE | Enterprise applications, banking systems, high-traffic sites |
| Ruby | Ruby on Rails | Rapid web application development, startups |
from flask import Flask, request, jsonify
from werkzeug.security import check_password_hash
import sqlite3
app = Flask(__name__)
@app.route('/api/login', methods=['POST'])
def login():
# Get data from client request
data = request.get_json()
email = data.get('email')
password = data.get('password')
# Validate inputs (server-side validation is critical!)
if not email or '@' not in email:
return jsonify({'success': False, 'error': 'Invalid email'}), 400
if not password or len(password) < 8:
return jsonify({'success': False, 'error': 'Invalid password'}), 400
# Query database for user
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
cursor.execute('SELECT id, password_hash FROM users WHERE email = ?', (email,))
user = cursor.fetchone()
conn.close()
# Check if user exists and password matches
if user and check_password_hash(user[1], password):
# Create session (simplified)
session_token = create_session_token(user[0])
return jsonify({
'success': True,
'token': session_token
})
else:
return jsonify({'success': False, 'error': 'Invalid credentials'}), 401
What's happening here:
Click on each code snippet to see whether it runs on the client (browser) or server:
| Aspect | Client-Side (Front-End) | Server-Side (Back-End) |
|---|---|---|
| Runs on | User's browser | Web server |
| Languages | HTML, CSS, JavaScript | Python, Node.js, PHP, Java, Ruby |
| Purpose | User interface, presentation, interactivity | Business logic, database operations, authentication |
| Visible to user? | Yes (view source, dev tools) | No (hidden from users) |
| Security | Never trust client-side validation (can be bypassed) | Secure, validates all inputs |
| Performance | Depends on user's device | Depends on server capacity |
| Database Access | No direct access (security risk) | Yes, full database access |
βββ TIER 3: Important
Controls visual appearance, layout, responsiveness, and animations while separating content (HTML) from presentation.
Define styles once, apply across thousands of pages. Single CSS rule change updates entire website.
/* Define brand colors once */
:root {
--primary-color: #007bff;
--secondary-color: #6c757d;
--background: #f8f9fa;
}
/* Apply to all buttons */
button {
background: var(--primary-color);
color: white;
}
/* Apply to all headings */
h1, h2, h3 {
color: var(--primary-color);
}
Result: If the company rebrands and changes the primary color, you only need to update --primary-color once, and all 500 pages update automatically. Without CSS, you'd need to manually edit every HTML file!
Websites adapt to different screen sizes (desktop, tablet, mobile) and orientations.
/* Desktop layout (default) */
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr; /* 3 columns */
gap: 2rem;
}
/* Tablet layout (max-width: 768px) */
@media (max-width: 768px) {
.container {
grid-template-columns: 1fr 1fr; /* 2 columns */
}
}
/* Mobile layout (max-width: 480px) */
@media (max-width: 480px) {
.container {
grid-template-columns: 1fr; /* 1 column */
}
}
// Define variables
$primary-color: #007bff;
$font-stack: 'Helvetica Neue', sans-serif;
// Nesting (cleaner than standard CSS)
nav {
background: $primary-color;
font-family: $font-stack;
ul {
list-style: none;
padding: 0;
li {
display: inline-block;
margin-right: 1rem;
a {
color: white;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
}
}
Compiled to standard CSS: Sass compiles to browser-compatible CSS, but the source code is much more readable and maintainable.
--primary-color, --spacing-large)ββ TIER 4: Good to Know
Frameworks provide pre-built tools, components, and patterns that speed up development and improve code quality.
Complete structure for building single-page applications (SPAs) with routing, state management, and component reusability.
| Framework | Description | Key Features | Used By |
|---|---|---|---|
| React | JavaScript library for building user interfaces (developed by Facebook/Meta) |
β’ Component-based architecture β’ Virtual DOM for performance β’ JSX syntax (HTML in JS) β’ Huge ecosystem |
Facebook, Instagram, Netflix, Airbnb |
| Vue.js | Progressive framework for building user interfaces |
β’ Easy to learn β’ Reactive data binding β’ Single-file components β’ Flexible and modular |
Alibaba, Xiaomi, GitLab |
| Angular | Full-featured framework (developed by Google) |
β’ TypeScript-based β’ Two-way data binding β’ Dependency injection β’ Complete solution (routing, forms, HTTP) |
Google, Microsoft, IBM |
| Svelte | Compiler-based framework (no virtual DOM) |
β’ Compiles to vanilla JS β’ Smaller bundle sizes β’ Reactive by default β’ Simple syntax |
Spotify, Apple, The New York Times |
import React, { useState } from 'react';
function Counter() {
// State management with hooks
const [count, setCount] = useState(0);
return (
<div>
<h2>Count: {count}</h2>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
<button onClick={() => setCount(count - 1)}>
Decrement
</button>
<button onClick={() => setCount(0)}>
Reset
</button>
</div>
);
}
export default Counter;
Why use React?
Counter component can be used anywhereuseState automatically updates UI when count changesPre-designed components and utility classes for faster styling.
| Framework | Approach | Pros | Cons |
|---|---|---|---|
| Bootstrap | Component-based (pre-designed buttons, cards, modals) | Easy to use, responsive grid, extensive documentation | Sites look similar, larger file size, requires overrides for customization |
| Tailwind CSS | Utility-first (small classes: flex, text-center, bg-blue-500) |
Highly customizable, small bundle size (with purging), no naming conflicts | Steeper learning curve, HTML can become cluttered with classes |
| Bulma | Flexbox-based, modern and clean | Lightweight, easy syntax, responsive | Smaller community than Bootstrap |
<button class="btn btn-primary btn-lg">
Click Me
</button>
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Click Me
</button>
Bootstrap: Fewer classes, but harder to customize without overriding styles
Tailwind: More classes, but complete control without writing custom CSS
ββββ TIER 2: Very Important
How web requests travel from browser to server and back.
Scenario: User visits https://example.com/products
93.184.216.34GET /products HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
Accept: text/html
Cookie: session_id=abc123
/productsSELECT id, name, price, image_url
FROM products
WHERE in_stock = TRUE
ORDER BY price ASC;
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 4523
Set-Cookie: session_id=abc123
<!DOCTYPE html>
<html>
<head><title>Products</title></head>
<body>...
Total time: Typically 50-500 milliseconds, depending on network speed, server location, and complexity
Handles HTTP requests, serves static files, routes dynamic requests to application code.
| Web Server | Description | Strengths |
|---|---|---|
| Nginx | High-performance, asynchronous web server | Excellent for serving static files, reverse proxy, load balancing |
| Apache | Mature, feature-rich web server | Highly configurable, extensive module ecosystem |
| Node.js (Express) | JavaScript runtime serving as web server | Real-time applications, full JavaScript stack |
| Caddy | Modern web server with automatic HTTPS | Easy configuration, automatic SSL certificate management |
Many production setups use Nginx as a reverse proxy in front of an application server:
βββββ TIER 1: Critical - Must Master
Standard language for managing relational databases. Stores user accounts, products, orders, and persistent data.
-- Get all columns from students table
SELECT * FROM students;
-- Get specific columns
SELECT first_name, last_name, email FROM students;
-- Get unique values (no duplicates)
SELECT DISTINCT course_name FROM courses;
-- Students with GPA above 3.5
SELECT * FROM students WHERE gpa > 3.5;
-- Students in a specific course
SELECT * FROM students WHERE course = 'Software Engineering';
-- Multiple conditions (AND)
SELECT * FROM students WHERE gpa > 3.0 AND year = 12;
-- Multiple conditions (OR)
SELECT * FROM students WHERE course = 'Physics' OR course = 'Chemistry';
-- Pattern matching (LIKE)
SELECT * FROM students WHERE email LIKE '%@gmail.com';
-- Sort by GPA (highest first)
SELECT * FROM students ORDER BY gpa DESC;
-- Sort by last name alphabetically
SELECT * FROM students ORDER BY last_name ASC;
-- Get top 5 students by GPA
SELECT * FROM students ORDER BY gpa DESC LIMIT 5;
-- Sort by multiple columns
SELECT * FROM students ORDER BY year DESC, gpa DESC;
Groups rows with same values. Aggregate functions: COUNT, SUM, AVG, MAX, MIN.
-- Count students in each course
SELECT course, COUNT(*) as student_count
FROM students
GROUP BY course;
-- Average GPA per year level
SELECT year, AVG(gpa) as average_gpa
FROM students
GROUP BY year;
-- Total sales per product
SELECT product_id, SUM(quantity) as total_sold
FROM orders
GROUP BY product_id;
-- Filter grouped results with HAVING
SELECT course, COUNT(*) as student_count
FROM students
GROUP BY course
HAVING COUNT(*) > 10;
Example:
-- Get courses with more than 10 students who have GPA > 3.0
SELECT course, COUNT(*) as count
FROM students
WHERE gpa > 3.0 -- Filter BEFORE grouping
GROUP BY course
HAVING COUNT(*) > 10; -- Filter AFTER grouping
Combine rows from multiple tables based on related columns.
Two tables:
| id | name | course_id |
|---|---|---|
| 1 | Alice | 101 |
| 2 | Bob | 102 |
| 3 | Charlie | 101 |
| id | course_name | instructor |
|---|---|---|
| 101 | Software Engineering | Dr. Smith |
| 102 | Physics | Dr. Johnson |
| 103 | Chemistry | Dr. Lee |
-- Get student names with their course names
SELECT students.name, courses.course_name
FROM students
INNER JOIN courses ON students.course_id = courses.id;
-- Result:
-- Alice | Software Engineering
-- Bob | Physics
-- Charlie | Software Engineering
| JOIN Type | Returns | Use Case |
|---|---|---|
| INNER JOIN | Only rows with matches in both tables | Get students enrolled in courses (excludes students without courses) |
| LEFT JOIN | All rows from left table + matching rows from right table (NULL if no match) | Get all students, including those not enrolled in any course |
| RIGHT JOIN | All rows from right table + matching rows from left table (NULL if no match) | Get all courses, including those with no students |
| FULL OUTER JOIN | All rows from both tables (NULL where no match) | Get all students and all courses, regardless of enrollment |
-- Get ALL students, even if they're not enrolled in a course
SELECT students.name, courses.course_name
FROM students
LEFT JOIN courses ON students.course_id = courses.id;
-- Result:
-- Alice | Software Engineering
-- Bob | Physics
-- Charlie | Software Engineering
-- David | NULL (David exists in students but has no course_id)
Select options below to build a SQL query and see the results:
βββ TIER 3: Important
Two approaches: raw SQL queries or Object-Relational Mapping (ORM).
Library for database interaction using programming language objects instead of SQL queries. Automatically translates code to SQL.
# Python with raw SQL (sqlite3)
import sqlite3
conn = sqlite3.connect('school.db')
cursor = conn.cursor()
# Manual SQL query
cursor.execute('SELECT * FROM students WHERE gpa > ?', (3.5,))
students = cursor.fetchall()
# Manual data processing
for row in students:
print(f"ID: {row[0]}, Name: {row[1]}, GPA: {row[2]}")
conn.close()
# Python with ORM (SQLAlchemy)
from sqlalchemy import create_engine, Column, Integer, String, Float
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
# Define Student model (represents students table)
class Student(Base):
__tablename__ = 'students'
id = Column(Integer, primary_key=True)
name = Column(String)
gpa = Column(Float)
# Create database connection
engine = create_engine('sqlite:///school.db')
Session = sessionmaker(bind=engine)
session = Session()
# Query using Python objects (no SQL!)
students = session.query(Student).filter(Student.gpa > 3.5).all()
# Access data like Python objects
for student in students:
print(f"ID: {student.id}, Name: {student.name}, GPA: {student.gpa}")
| Aspect | Raw SQL | ORM (e.g., SQLAlchemy, Django ORM) |
|---|---|---|
| Syntax | Write SQL strings directly | Use Python/JavaScript objects and methods |
| Learning Curve | Must learn SQL syntax | Must learn ORM API (but use familiar programming language) |
| Database Portability | SQL syntax varies between databases (PostgreSQL vs MySQL vs SQLite) | ORM handles differences, easily switch databases |
| Performance | Can write highly optimized queries | ORM-generated queries may be less efficient for complex operations |
| Security | Risk of SQL injection if not using parameterized queries | Automatically prevents SQL injection |
| Code Readability | SQL strings mixed with application code | Clean, Pythonic/JavaScript-like code |
| Complex Queries | Full SQL power (joins, subqueries, CTEs) | Can be verbose or require raw SQL fallback |
| Schema Management | Manual table creation with SQL | Migrations automatically generate SQL from model changes |
cursor.execute(
'INSERT INTO students (name, email, gpa) VALUES (?, ?, ?)',
('John Doe', 'john@example.com', 3.8)
)
conn.commit()
new_student = Student(name='John Doe', email='john@example.com', gpa=3.8)
session.add(new_student)
session.commit()
ORM Advantage: More readable, type-safe, and prevents SQL injection automatically.
ββ TIER 4: Good to Know
Combine web and mobile apps for app-like experiences in the browser.
Affects readability, accessibility, and brand identity.
Example:
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
font-size: 16px;
line-height: 1.6;
color: #333;
}
Requires careful implementation for accessibility and performance.
| Navigation Type | Description | Best For |
|---|---|---|
| Top Navigation Bar | Horizontal menu at top of page | 5-7 main sections, desktop-focused sites |
| Hamburger Menu | Hidden menu revealed by β° icon | Mobile apps, sites with many sections |
| Tab Bar (Bottom Nav) | Fixed navigation at bottom of screen | Mobile apps, 3-5 primary actions |
| Sidebar Navigation | Vertical menu on left/right side | Admin dashboards, content-heavy sites |
| Breadcrumbs | Home > Products > Laptops > MacBook | E-commerce, deep content hierarchies |
Ensures everyone can use your application, regardless of disability, device, or internet speed.
<button> instead of <div onclick> (screen reader support)<img alt="Red shopping cart icon">)<label><div> instead of <button> for clickable elementsDevOps/RPA/BPA, AI vs ML, training models, neural networks, decision trees, ethical implications