›_ ebskola.lv

Programmēšanas špikeris

Vienkopus sakopota uzziņu lapa: priekšgala (HTML, CSS, JavaScript), aizmugures (Python, PostgreSQL), izstrādes vide un drošības labās prakses.

Saturs

HTML - struktūra un semantika

Lapas skelets
<!DOCTYPE html>
<html lang="lv">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Lapas virsraksts</title>
  <link rel="stylesheet" href="style.css">
  <script src="app.js" defer></script>
</head>
<body>
  <header class="topbar">
    <a class="brand" href="index.html">ebSkola</a>
    <nav>
      <a href="index.html">Sākums</a>
      <a href="projekts.html">Projekts</a>
    </nav>
  </header>

  <main>
    <section class="hero">
      <p class="eyebrow">HTML · CSS · JavaScript</p>
      <h1>Mana pirmā lapa</h1>
      <p>Īss apraksts par projektu un to, ko lietotājs šeit var darīt.</p>
      <button id="poga">Pārbaudīt</button>
    </section>

    <section class="card">
      <h2>Projekta saturs</h2>
      <p id="rezultats">Šeit parādīsies JavaScript rezultāts.</p>
    </section>
  </main>

  <footer>© 2026 Mans projekts</footer>
</body>
</html>

Īss style.css paraugs

:root {
  --bg: #222831;
  --surface: #2A2F34;
  --surface-raised: #393E46;
  --text: #E7DEC9;
  --muted: #C8BCA4;
  --accent: #A89C88;
  --accent-strong: #FFB142;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: system-ui, sans-serif;
  background: var(--bg);
  color: var(--text);
  line-height: 1.6;
}

.topbar,
main,
footer {
  max-width: 960px;
  margin: 0 auto;
  padding: 24px;
}

.topbar {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  border-bottom: 1px solid #4a515c;
}

.brand,
nav a {
  color: var(--text);
  text-decoration: none;
}

nav {
  display: flex;
  gap: 12px;
}

.hero,
.card {
  background: var(--surface);
  border: 1px solid #4a515c;
  border-radius: 8px;
  padding: 24px;
  margin-top: 24px;
}

.eyebrow {
  color: var(--muted);
  font-size: 14px;
}

h1,
h2 {
  margin-top: 0;
}

button {
  background: var(--accent);
  border: 0;
  border-radius: 4px;
  padding: 10px 14px;
  cursor: pointer;
}
Vizuālais noformējums (CSS bāze)

Lai mainītu izskatu, izmanto CSS īpašības <style> blokā vai style.css failā.

DarbībaCSS īpašībaPiemērs
Fona krāsabackground-colorbody { background-color: #f0f0f0; }
Teksta krāsacolorp { color: #333333; }
Teksta centrēšanatext-alignh1 { text-align: center; }
Elementa centrēšanamargin: autodiv { width: 50%; margin: auto; }
Fonta veidsfont-familybody { font-family: sans-serif; }
Teksta izmērsfont-sizep { font-size: 16px; }

Modernā centrēšana (Flexbox)

/* Iecentrē visu saturu lapas vidū */
.centrets-konteiners {
    display: flex;
    justify-content: center; /* Horizontāli */
    align-items: center;     /* Vertikāli */
    height: 100vh;           /* Pilns ekrāna augstums */
}
Populārākie HTML tagi
TagsLietojums
<div>Universāls bloka konteiners.
<span>Universāls rindas (inline) konteiners.
<p>Teksta rindkopa.
<a href="...">Hipersaite.
<img src="..." alt="...">Attēls.
<ul> / <ol> / <li>Saraksti.
<h1> - <h6>Virsraksti.
Semantiska lapas sadaļa

Semantiskie tagi pasaka pārlūkam un meklētājiem, kāda loma ir saturam. Tie arī palīdz ekrāna lasītājiem saprast lapas struktūru.

<main>
  <article class="lesson-card">
    <header>
      <p class="eyebrow">Programmēšana I</p>
      <h2>5.1 Saraksti</h2>
    </header>

    <p>Apgūsti sarakstu izveidi, indeksus un metodes.</p>

    <footer>
      <a href="prog1_51.html">Atvērt nodarbību</a>
    </footer>
  </article>
</main>

Atceries: lapā parasti ir viens galvenais <h1>, bet katrai satura sadaļai drīkst būt savs <h2> vai <h3>.

Formas un ievades elementi
<form action="/saglabat" method="POST">
  <label for="vards">Vārds:</label>
  <input id="vards" name="vards" type="text" required>

  <label for="epasts">E-pasts:</label>
  <input id="epasts" name="epasts" type="email" required>

  <button type="submit">Sūtīt</button>
</form>

Biežāk lietotie ievades tipi

<input type="number" min="0" max="100" step="1">
<input type="date">
<input type="checkbox" id="piekrītu" name="piekrītu">
<textarea name="komentars" rows="4"></textarea>

<select name="kurss" required>
  <option value="">Izvēlies kursu</option>
  <option value="prog1">Programmēšana I</option>
  <option value="prog2">Programmēšana II</option>
</select>
Pieejamība (a11y) un SEO
  • Vienmēr lieto alt tekstu attēliem.
  • Formu elementus sasaisti ar <label> (izmantojot for un id).
  • Lieto semantiskos tagus (<main>, <article>), lai palīdzētu ekrāna lasītājiem.
<img src="diagramma.png"
     alt="Plūsmas diagramma ar trim soļiem: ievade, apstrāde, izvade"
     loading="lazy">

<nav aria-label="Galvenā navigācija">
  <a href="index.html">Tēmas</a>
  <a href="paligm.html" aria-current="page">Palīgmateriāli</a>
</nav>
Audio un video media
<!-- Audio -->
<audio controls preload="auto" loop>
  <source src="muzika.mp3" type="audio/mpeg">
  <source src="muzika.ogg" type="audio/ogg">
  Tavs pārlūks neatbalsta audio.
</audio>

<!-- Video -->
<video width="640" height="360" controls poster="preview.jpg">
  <source src="video.mp4" type="video/mp4">
  <track kind="subtitles" src="subs-lv.vtt" srclang="lv" label="Latviski">
</video>

<!-- Canvas (zīmēšana JS palīdzību) -->
<canvas id="game" width="800" height="600"></canvas>

<!-- SVG inline -->
<svg width="100" height="100">
  <circle cx="50" cy="50" r="40" fill="#FFB142"/>
</svg>

Formāti: audio - MP3 (universāls), OGG (atvērts kods); video - MP4 H.264 (universāls), WebM (mūsdienīgs).

CSS - stils un izkārtojums

Selektori
/* Tags */          h1 { color: red; }
/* Klase */          .karte { padding: 20px; }
/* ID */             #logo { width: 80px; }
/* Apvienots */      h2.galvenais { font-size: 2em; }
/* Bērnu */          ul > li { list-style: square; }
/* Pēctecis */       article p { line-height: 1.6; }
/* Pseidoklases */   a:hover { color: blue; }
                     input:focus { outline: 2px solid #FFB142; }
                     li:nth-child(odd) { background: #eee; }
/* Atribūti */       a[href^="https"] { color: green; }
Box Model un izvietojums
.kaste {
  /* No iekšas uz āru: content → padding → border → margin */
  width: 200px;
  padding: 16px;
  border: 2px solid #948979;
  margin: 20px;
  box-sizing: border-box; /* width iekļauj padding+border */
}

.absolute { position: absolute; top: 10px; left: 20px; }
.fixed { position: fixed; bottom: 0; right: 0; }
.sticky { position: sticky; top: 0; }
Flexbox
.konteineris {
  display: flex;
  flex-direction: row;        /* row | column */
  justify-content: center;    /* main ass: flex-start | center | space-between */
  align-items: center;        /* cross ass: flex-start | center | stretch */
  gap: 20px;
  flex-wrap: wrap;
}
.elements {
  flex: 1;             /* aug, lai aizpildītu */
  flex-basis: 200px;
}

Praktisks piemērs: poga + rinda ar kartēm

.actions {
  display: flex;
  gap: 12px;
  justify-content: flex-end;
  align-items: center;
}

.btn {
  border: 0;
  border-radius: 6px;
  padding: 10px 14px;
  background: #FFB142;
  color: #222831;
  font-weight: 700;
  cursor: pointer;
}

.card-row {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
}

.card {
  flex: 1 1 220px;
  padding: 16px;
  border: 1px solid #444;
  border-radius: 6px;
}
Grid izkārtojums
.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 20px;
}
.layout {
  display: grid;
  grid-template-areas:
    "header header header"
    "side   main   main"
    "footer footer footer";
  grid-template-columns: 200px 1fr 1fr;
}
.header { grid-area: header; }

Vienkāršs dashboard izkārtojums

.dashboard {
  display: grid;
  grid-template-columns: 260px minmax(0, 1fr);
  min-height: 100vh;
}

.sidebar { border-right: 1px solid #444; }
.content { padding: 24px; }

@media (max-width: 800px) {
  .dashboard { grid-template-columns: 1fr; }
  .sidebar { border-right: 0; border-bottom: 1px solid #444; }
}
Mainīgie un mediju vaicājumi
:root {
  --bg: #222831;
  --surface: #2A2F34;
  --text: #E7DEC9;
  --muted: #C8BCA4;
  --accent-strong: #FFB142;
}
body { background: var(--bg); color: var(--text); }

@media (max-width: 768px) {
  .grid { grid-template-columns: 1fr; }
  body { font-size: 16px; }
}
Animācijas un pārejas
.poga { background: #948979; transition: all 0.3s ease; }
.poga:hover {
  background: #FFB142;
  transform: translateY(-3px);
  box-shadow: 0 4px 8px rgba(0,0,0,0.3);
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}
.zime { animation: pulse 2s infinite; }

Kustību samazināšana lietotājiem, kam tā traucē

@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
}
Formu noformēšana
.form-grid {
  display: grid;
  gap: 12px;
  max-width: 520px;
}

label { font-weight: 700; }

input, select, textarea {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid #666;
  border-radius: 6px;
  background: #222831;
  color: #DFD0B8;
}

input:focus, select:focus, textarea:focus {
  outline: 2px solid #FFB142;
  border-color: transparent;
}
Transforms, filters un blend modes
/* Transforms - pārveidojumi */
.karte {
  transform: translate(20px, 10px) rotate(15deg) scale(1.2);
  transition: transform 0.3s ease;
}
.karte:hover { transform: scale(1.1) rotate(-3deg); }

/* 3D perspektīva */
.kub {
  transform: perspective(800px) rotateY(45deg) rotateX(20deg);
  transform-style: preserve-3d;
}

/* Filters - vizuālie efekti */
.attels {
  filter: blur(2px) brightness(1.2) contrast(1.1) grayscale(50%);
}
.attels:hover { filter: none; }

/* Blend modes */
.banner {
  background-blend-mode: multiply;
  mix-blend-mode: overlay;
}

/* Clip-path - formas */
.trijsturis {
  clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
}

JavaScript - interaktivitāte

Mainīgie un datu tipi
let mainīgais = 5;          // var mainīt
const konstante = "teksts";  // nav maināms

// Tipi: number, string, boolean, null, undefined, array, object
const masivs = [1, 2, 3];
const objekts = { vārds: "Anna", vecums: 12 };

typeof skaitlis;            // "number"
Array.isArray(masivs);      // true
Funkcijas
function saskaiti(a, b) { return a + b; }
const reizini = (a, b) => a * b;

function sveiks(vārds = "viesi") {
  return `Sveiks, ${vārds}!`;
}

const skaiti = [1, 2, 3];
const visi = [...skaiti, 4, 5];          // spread
function sum(...numbers) {                 // rest
  return numbers.reduce((a, b) => a + b);
}
Masīvu metodes
const skaiti = [1, 2, 3, 4, 5];

skaiti.map(x => x * 2);              // [2,4,6,8,10]
skaiti.filter(x => x > 2);           // [3,4,5]
skaiti.reduce((a, b) => a + b, 0);   // 15
skaiti.find(x => x > 3);             // 4
skaiti.some(x => x > 4);             // true
skaiti.every(x => x > 0);            // true
skaiti.includes(3);                   // true
skaiti.sort((a, b) => b - a);         // dilstoši
DOM manipulācija
const elem = document.getElementById("logo");
const visi = document.querySelectorAll(".karte");
const pirmais = document.querySelector(".karte");

elem.textContent = "Jauns teksts";
elem.classList.add("aktiivs");
elem.classList.toggle("paslēpts");
elem.style.color = "red";
elem.setAttribute("data-id", "42");

const jauns = document.createElement("div");
jauns.textContent = "Sveiks!";
document.body.appendChild(jauns);
jauns.remove();

Saraksta renderēšana no datiem

const stundas = [
  { nosaukums: "Saraksti", fails: "prog1_51.html" },
  { nosaukums: "Vārdnīcas", fails: "prog1_52.html" },
  { nosaukums: "For cikli", fails: "prog1_53.html" }
];

const saraksts = document.querySelector("#stundas");
saraksts.innerHTML = "";

for (const stunda of stundas) {
  const li = document.createElement("li");
  const saite = document.createElement("a");
  saite.href = stunda.fails;
  saite.textContent = stunda.nosaukums;
  li.appendChild(saite);
  saraksts.appendChild(li);
}
Notikumi
document.getElementById("poga").addEventListener("click", (e) => {
  console.log("Nospiests!", e.target);
});

document.addEventListener("keydown", (e) => {
  if (e.key === "ArrowLeft") speletajs.x -= 5;
  if (e.key === "Enter") sākt();
});

form.addEventListener("submit", (e) => {
  e.preventDefault();
  const dati = new FormData(form);
});

Formas validācija pirms sūtīšanas

const forma = document.querySelector("#pieteikums");
const kluda = document.querySelector("#kluda");

forma.addEventListener("submit", (e) => {
  e.preventDefault();
  const dati = new FormData(forma);
  const vards = dati.get("vards")?.trim();
  const punkti = Number(dati.get("punkti"));

  if (!vards || Number.isNaN(punkti) || punkti < 0) {
    kluda.textContent = "Ievadi vārdu un punktus virs 0.";
    return;
  }

  kluda.textContent = "";
  console.log({ vards, punkti });
});
Async, fetch un Promise
async function ielādēDatus() {
  try {
    const r = await fetch("https://api.example.com/dati");
    if (!r.ok) throw new Error("Tīkla kļūda");
    const dati = await r.json();
    console.log(dati);
  } catch (kļūda) { console.error(kļūda); }
}

fetch("/saglabat", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ vārds: "Anna", punkti: 95 })
});
localStorage
localStorage.setItem("highscore", "120");
localStorage.setItem("speletajs", JSON.stringify({ vārds: "Anna" }));

const score = localStorage.getItem("highscore");
const sp = JSON.parse(localStorage.getItem("speletajs") || "{}");

localStorage.removeItem("highscore");
localStorage.clear();
Klases un ES6 moduļi
// ES6 klase
class Varonis {
  #hp;  // privāts lauks (# prefix)

  constructor(vards, hp = 100) {
    this.vards = vards;
    this.#hp = hp;
  }

  get hp() { return this.#hp; }

  cizt(b) {
    this.#hp = Math.max(0, this.#hp - b);
    if (this.#hp === 0) console.log(`${this.vards} miris!`);
  }

  static fabrika(tips) {
    if (tips === "bruninieks") return new Varonis("Bruņinieks", 150);
    return new Varonis("Cilvēks", 100);
  }
}

// Mantošana
class Burvis extends Varonis {
  constructor(vards) {
    super(vards, 80);
    this.mana = 100;
  }
  burvojums(merkis) {
    if (this.mana >= 10) { this.mana -= 10; merkis.cizt(25); }
  }
}

// ES6 moduļi
// fails: varonis.js
export class Varonis { /* ... */ }
export const MAX_HP = 999;
export default class Game { /* ... */ }

// fails: main.js
import Game, { Varonis, MAX_HP } from './varonis.js';
Vienkāršs spēles cikls
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");

const speletajs = { x: 40, y: 40, atrums: 180 };
const taustini = new Set();
let ieprieksejais = performance.now();

document.addEventListener("keydown", e => taustini.add(e.key));
document.addEventListener("keyup", e => taustini.delete(e.key));

function update(dt) {
  if (taustini.has("ArrowRight")) speletajs.x += speletajs.atrums * dt;
  if (taustini.has("ArrowLeft")) speletajs.x -= speletajs.atrums * dt;
}

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.fillStyle = "#FFB142";
  ctx.fillRect(speletajs.x, speletajs.y, 32, 32);
}

function loop(laiks) {
  const dt = (laiks - ieprieksejais) / 1000;
  ieprieksejais = laiks;
  update(dt);
  draw();
  requestAnimationFrame(loop);
}

requestAnimationFrame(loop);

Python - sintakses pamati

Mainīgie un operatori
vards = "Anna"
vecums = 12
augstums = 1.65
ir_skoleens = True

str(42); int("10"); float("3.14")  # konvertācija

10 // 3   # 3 (veselo)
10 % 3    # 1 (atlikums)
2 ** 8    # 256

f"Sveiks, {vards}! Vecums: {vecums}"
Vadības struktūras
if punkti >= 90:    print("Lieliski")
elif punkti >= 70:  print("Labi")
else:               print("Mēģini vēlreiz")

for i in range(10): print(i)
for v in saraksts: print(v)
for i, v in enumerate(saraksts): print(i, v)

while dzivibas > 0:
    spelet()

# break, continue
for x in skaiti:
    if x < 0: continue
    if x > 100: break
Funkcijas un imports
def aprekini_vidu(skaiti):
    """Aprēķina vidējo vērtību."""
    if not skaiti: return 0
    return sum(skaiti) / len(skaiti)

reizina = lambda x, y: x * y

import random
from math import pi, sqrt
import json as j
Saraksti, vārdnīcas, kopas
saraksts = [1, 2, 3]
saraksts.append(4)
saraksts.insert(0, 0)
saraksts.remove(2)
saraksts.pop()
sorted(saraksts, reverse=True)

# List comprehension
kvadrati = [x**2 for x in range(10)]
parie = [x for x in saraksts if x % 2 == 0]

varonis = {"vards": "Anna", "hp": 100}
varonis["zelts"] = 50
varonis.get("inv", [])
for k, v in varonis.items(): ...

unikali = set([1, 1, 2, 3, 3])  # {1, 2, 3}

Datu grupēšana ar vārdnīcu

rezultati = [
    {"vards": "Anna", "kurss": "Python", "punkti": 87},
    {"vards": "Jānis", "kurss": "Python", "punkti": 72},
    {"vards": "Eva", "kurss": "SQL", "punkti": 91},
]

pa_kursiem = {}
for rinda in rezultati:
    kurss = rinda["kurss"]
    pa_kursiem.setdefault(kurss, []).append(rinda["punkti"])

for kurss, punkti in pa_kursiem.items():
    videjais = sum(punkti) / len(punkti)
    print(kurss, round(videjais, 1))
Failu apstrāde un izņēmumi
with open("dati.txt", "r", encoding="utf-8") as f:
    saturs = f.read()

with open("dati.txt", "w", encoding="utf-8") as f:
    f.write("rinda 1\nrinda 2")

import json
with open("d.json") as f: data = json.load(f)
with open("d.json", "w") as f: json.dump(data, f, indent=2)

import csv
with open("d.csv") as f:
    for r in csv.DictReader(f):
        print(r["vards"])

try:
    n = int(input("Ievadi: "))
except ValueError:
    print("Tas nav skaitlis!")
finally:
    print("Vienmēr izpildās")

Droša CSV rakstīšana

import csv

lauki = ["vards", "punkti"]
rindas = [
    {"vards": "Anna", "punkti": 120},
    {"vards": "Jānis", "punkti": 95},
]

with open("rezultati.csv", "w", encoding="utf-8", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=lauki)
    writer.writeheader()
    writer.writerows(rindas)
OOP klases
class Varonis:
    def __init__(self, vards, hp=100):
        self.vards = vards
        self.hp = hp

    def sanemt_bojajumu(self, bojajums):
        self.hp -= bojajums
        if self.hp <= 0:
            print(f"{self.vards} ir miris!")

    def __str__(self):
        return f"{self.vards} ({self.hp} HP)"

class Burvis(Varonis):
    def __init__(self, vards, mana=50):
        super().__init__(vards, hp=80)
        self.mana = mana

    def burvojums(self, merkis):
        if self.mana >= 10:
            self.mana -= 10
            merkis.sanemt_bojajumu(20)

Dataclass vienkāršiem datu objektiem

from dataclasses import dataclass

@dataclass
class Prieksmets:
    nosaukums: str
    cena: int
    retums: str = "parasts"

inventars = [
    Prieksmets("Zobens", 40),
    Prieksmets("Maģiska atslēga", 120, "rets"),
]

dargie = [p for p in inventars if p.cena >= 100]
Testēšana ar pytest
# fails: kalkulators.py
def dalit(a, b):
    if b == 0:
        raise ValueError("Ar nulli dalīt nedrīkst")
    return a / b

# fails: test_kalkulators.py
import pytest
from kalkulators import dalit

def test_dalit():
    assert dalit(10, 2) == 5

def test_dalit_ar_nulli():
    with pytest.raises(ValueError):
        dalit(10, 0)
python -m pytest
python -m pytest -q
Dekoratori un context managers
import functools
import time

# Vienkāršs dekorators
def izmeri_laiku(func):
    @functools.wraps(func)
    def ietinums(*args, **kwargs):
        sakums = time.time()
        rezultats = func(*args, **kwargs)
        print(f"{func.__name__} aizņēma {time.time()-sakums:.2f}s")
        return rezultats
    return ietinums

@izmeri_laiku
def lens_aprekins():
    time.sleep(1)
    return 42

# Iebūvētie dekoratori
class Konts:
    def __init__(self): self._bilance = 0

    @property                  # getter
    def bilance(self):
        return self._bilance

    @bilance.setter            # setter
    def bilance(self, v):
        if v < 0: raise ValueError("Negatīvs!")
        self._bilance = v

    @staticmethod              # nelieto self
    def aprekini_procentus(suma, p): return suma * p / 100

    @classmethod               # cls
    def tukss(cls): return cls()

# Context manager
class Faila_logger:
    def __enter__(self):
        self.f = open("log.txt", "a")
        return self.f
    def __exit__(self, *args):
        self.f.close()

with Faila_logger() as f:
    f.write("Notikums
")

PostgreSQL un SQL

Datubāzes un tabulu izveide
CREATE DATABASE spele;
\c spele

CREATE TABLE speletaji (
    id SERIAL PRIMARY KEY,
    vards VARCHAR(50) NOT NULL UNIQUE,
    epasts VARCHAR(120),
    punkti INTEGER DEFAULT 0,
    izveidots TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

DROP TABLE speletaji;

ALTER TABLE speletaji ADD COLUMN avatars TEXT;
ALTER TABLE speletaji DROP COLUMN epasts;
CRUD operācijas
-- INSERT
INSERT INTO speletaji (vards, punkti) VALUES ('Anna', 120);
INSERT INTO speletaji (vards, punkti) VALUES
    ('Jānis', 95), ('Eva', 145);

-- SELECT
SELECT * FROM speletaji;
SELECT vards, punkti FROM speletaji WHERE punkti > 100;
SELECT * FROM speletaji ORDER BY punkti DESC LIMIT 10;
SELECT COUNT(*) FROM speletaji;
SELECT AVG(punkti), MAX(punkti) FROM speletaji;

-- UPDATE
UPDATE speletaji SET punkti = punkti + 10 WHERE vards = 'Anna';

-- DELETE
DELETE FROM speletaji WHERE punkti < 50;
Datu tipi
TipsApraksts
SERIALAuto-increment vesels skaitlis
INTEGER / BIGINTVesels skaitlis
NUMERIC(10,2)Decimālskaitlis
VARCHAR(n)Tekstam līdz n simboliem
TEXTNeierobežota teksta lauka
BOOLEANtrue/false
DATE / TIMESTAMPDatums / datums + laiks
JSON / JSONBJSON dati
UUIDUnikāls identifikators
JOIN - saistītie dati
CREATE TABLE speles (
    id SERIAL PRIMARY KEY,
    speletajs_id INTEGER REFERENCES speletaji(id),
    punkti INTEGER,
    spelets TIMESTAMP DEFAULT NOW()
);

-- INNER JOIN
SELECT s.vards, sp.punkti
FROM speletaji s
INNER JOIN speles sp ON s.id = sp.speletajs_id;

-- LEFT JOIN
SELECT s.vards, COUNT(sp.id) AS speles_skaits
FROM speletaji s
LEFT JOIN speles sp ON s.id = sp.speletajs_id
GROUP BY s.vards;
Ierobežojumi, transakcijas un UPSERT
CREATE TABLE rezultati (
    id SERIAL PRIMARY KEY,
    speletajs_id INTEGER NOT NULL REFERENCES speletaji(id) ON DELETE CASCADE,
    punkti INTEGER NOT NULL CHECK (punkti >= 0),
    limenis INTEGER NOT NULL DEFAULT 1,
    UNIQUE (speletajs_id, limenis)
);

-- Transakcija: viss izdodas vai viss tiek atcelts
BEGIN;
UPDATE speletaji SET punkti = punkti + 10 WHERE id = 1;
INSERT INTO rezultati (speletajs_id, punkti, limenis) VALUES (1, 130, 2);
COMMIT;

-- Ja kļūda:
ROLLBACK;

-- UPSERT: ievieto vai atjaunina, ja tāds ieraksts jau eksistē
INSERT INTO rezultati (speletajs_id, punkti, limenis)
VALUES (1, 150, 2)
ON CONFLICT (speletajs_id, limenis)
DO UPDATE SET punkti = EXCLUDED.punkti;
Indeksi un veiktspēja
CREATE INDEX idx_speletaji_vards ON speletaji(vards);
CREATE INDEX idx_punkti_dilst ON speletaji(punkti DESC);
CREATE UNIQUE INDEX idx_uniq_vards ON speletaji(vards);

EXPLAIN ANALYZE SELECT * FROM speletaji WHERE vards = 'Anna';

DROP INDEX idx_speletaji_vards;
Python ↔ PostgreSQL
import psycopg2
from psycopg2.extras import RealDictCursor

conn = psycopg2.connect(
    host="localhost", database="spele",
    user="lietotajs", password="parole"
)

with conn, conn.cursor(cursor_factory=RealDictCursor) as cur:
    cur.execute("SELECT * FROM speletaji WHERE punkti > %s", (50,))
    for r in cur.fetchall():
        print(r["vards"], r["punkti"])

    cur.execute(
        "INSERT INTO speletaji (vards, punkti) VALUES (%s, %s) RETURNING id",
        ("Anna", 120)
    )
    jauns_id = cur.fetchone()["id"]

# ⚠ NEKAD nelieto string formatēšanu SQL - SQL injekcijas risks!

Savienojuma dati no vides mainīgajiem

import os
import psycopg2

conn = psycopg2.connect(os.environ["DATABASE_URL"])

with conn:
    with conn.cursor() as cur:
        cur.execute("SELECT NOW()")
        print(cur.fetchone()[0])
Transakcijas un datu integritāte
-- Transakcija - visi vai neviens
BEGIN;
    UPDATE konti SET bilance = bilance - 100 WHERE id = 1;
    UPDATE konti SET bilance = bilance + 100 WHERE id = 2;
    -- Ja kāds UPDATE neizdodas:
    -- ROLLBACK;
COMMIT;

-- SAVEPOINT - daļēja atcelšana
BEGIN;
    INSERT INTO logs VALUES (...);
    SAVEPOINT pirms_riska;
    UPDATE ... -- ja crashas
    ROLLBACK TO pirms_riska;  -- tikai šo daļu atceļ
COMMIT;

-- Constraints - datu integritāte
ALTER TABLE speletaji
  ADD CONSTRAINT pozitivi_punkti CHECK (punkti >= 0);

ALTER TABLE speles
  ADD CONSTRAINT fk_speletajs
  FOREIGN KEY (speletajs_id)
  REFERENCES speletaji(id)
  ON DELETE CASCADE
  ON UPDATE NO ACTION;

-- Triggers - automatiskas darbības
CREATE OR REPLACE FUNCTION pierakstit_izmainu()
RETURNS TRIGGER AS $$
BEGIN
    INSERT INTO audit_log(tabula, darbiba, laiks)
    VALUES (TG_TABLE_NAME, TG_OP, NOW());
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER speletaja_izmaina
  AFTER UPDATE OR DELETE ON speletaji
  FOR EACH ROW EXECUTE FUNCTION pierakstit_izmainu();

Git un GitHub

Bāzes komandas
git config --global user.name "Tavs Vārds"
git config --global user.email "tavs@pasts.lv"

git init
git clone https://github.com/lietotajs/repo.git

git status
git diff
git add fails.py    # vai 'git add .'
git commit -m "Skaidrs apraksts"
git push
git pull

git log --oneline --graph --all
git show abc123
Branch un sapludināšana
git branch
git branch jauna-funkcija
git checkout -b vel-jauns
git switch main

git merge jauna-funkcija
git branch -d jauna-funkcija

# Konflikta gadījumā: atrod <<<<<<< HEAD ... =======...>>>>>>>
# Izlemj versiju, git add, git commit

Tipiska darba plūsma ar Pull Request

git switch main
git pull
git switch -c fix/seo-links

# veic izmaiņas
git status
git add paligm.html
git commit -m "Expand programming cheat sheet examples"
git push -u origin fix/seo-links

# GitHub: atver Pull Request, pārbaudi diff, sapludini main zarā
Atjaunošana
git restore fails.py             # atceļ lokālas izmaiņas
git restore --staged fails.py    # noņem no add

git reset --soft HEAD~1          # atceļ commit, izmaiņas paliek
git reset --hard HEAD~1          # ⚠ pilnībā atceļ
git revert abc123                # drošs commit, kas atceļ iepriekšējo
.gitignore paraugs
.env
*.key
secrets.json

__pycache__/
*.pyc
venv/

node_modules/
dist/

.DS_Store
.vscode/
.idea/

*.sqlite
Stash, cherry-pick un rebase
# Stash - pagaidām paslēpj nesaglabātos darbus
git stash                          # paslēpj
git stash list                     # parāda visus
git stash pop                      # atjauno + dzēš no list
git stash apply stash@{1}          # atjauno bez dzēšanas
git stash drop                     # tikai dzēš

# Cherry-pick - atsevišķu commit kopē uz citu branch
git checkout main
git cherry-pick abc123             # ievieto šo commit šeit
git cherry-pick abc123^..def456    # diapazons

# Interactive rebase - pārkārto/apvieno commits
git rebase -i HEAD~5
# Editorā: pick, reword (mainīt ziņu), squash (apvienot),
#          fixup, edit, drop

# Reflog - atrod "pazudušus" commits
git reflog                         # visas darbības (pat dzēstas)
git reset --hard HEAD@{2}          # atjauno 2 darbības atpakaļ

# Bisect - bināra meklēšana, kurš commit ievieš bug
git bisect start
git bisect bad                     # tagad ir slikti
git bisect good v1.0               # v1.0 bija labi
# Git dod commits to test → git bisect good/bad
git bisect reset                   # beigt
Tagi un versijas
git tag v1.0.0
git tag -a v1.1.0 -m "Pirmā publiskā versija"
git push origin v1.1.0
git tag --list

# Pārslēgties uz konkrētu versiju tikai apskatei
git switch --detach v1.1.0

VS Code - īsceļi

Vispārējas operācijas
ĪsceļšDarbība
Ctrl+PAtvērt failu pēc nosaukuma
Ctrl+Shift+PKomandu palete
Ctrl+SSaglabāt
Ctrl+`Atvērt termināli
Ctrl+BSānjoslas slēptuve
Ctrl+/Komentē rindu
Alt+↑/↓Pārvietot rindu
Ctrl+DAtlasīt nākamo tādu pašu
F2Pārdēvēt simbolu
F12Iet uz definīciju
Ctrl+Shift+FMeklēt visā projektā
Multi-cursor un snippets
ĪsceļšDarbība
Alt+ClickPievieno kursoru tur, kur noklikšķini
Ctrl+Alt+↑/↓Pievieno kursoru augstāk/zemāk
Ctrl+DAtlasi nākamo tādu pašu vārdu
Ctrl+Shift+LAtlasi VISUS tādus pašus vārdus
Ctrl+Shift+Alt+↓Dublē rindu
Shift+Alt+↑/↓Kopē rindu augšup/lejup
// Pielāgots snippet (File → Preferences → Configure User Snippets → python.json)
{
  "Print debug": {
    "prefix": "pdb",
    "body": [
      "print(f"$1 = {$1}")"
    ],
    "description": "Print mainīgo ar nosaukumu"
  },
  "For range": {
    "prefix": "fr",
    "body": [
      "for ${1:i} in range(${2:10}):",
      "    $0"
    ]
  }
}

Pēc pdb + Tab → izvēršas par print(f"x = {x}").

Regulārās izteiksmes

Bāzes simboli
SimbolsNozīme
.Jebkurš simbols
\dCipars
\wVārda simbols
\sAtstarpe
^ / $Rindas sākums / beigas
*0+ reizes
+1+ reizes
?0 vai 1 reizi
{3,5}No 3 līdz 5 reizēm
[abc]a, b vai c
(grupa)Grupēšana
import re
re.match(r"^[\w.-]+@[\w.-]+\.\w{2,}$", "anna@skola.lv")
re.findall(r"\+?\d{8,12}", "Zvani: +37120123456")
re.sub(r"\d+", "###", "Skola Nr. 42")

Grupas un nosauktas grupas

teksts = "dat9_36.html - 3.6 Noslēguma projekts"
pattern = r"(?P<kurss>dat9)_(?P<tema>\d)(?P<stunda>\d)\.html"

m = re.search(pattern, teksts)
if m:
    print(m.group("kurss"))   # dat9
    print(m.group("tema"))    # 3
    print(m.group("stunda"))  # 6

# Vairāku atstarpju sakopšana
tirs = re.sub(r"\s+", " ", "Pārāk    daudz     atstarpju").strip()
Lookahead, lookbehind un grupas
SintakseNozīme
(?=...)Lookahead - sekos ...
(?!...)Negative lookahead - nesekos ...
(?<=...)Lookbehind - pirms ir ...
(?<!...)Negative lookbehind
(?P<vards>...)Nosaukta grupa
(?:...)Non-capturing group (tikai grupēt, ne saglabāt)
, Atsauce uz iepriekšējo grupu
import re

# Stipra parole: 8+ simboli, vismaz 1 cipars + 1 lielais burts
parole = r"^(?=.*\d)(?=.*[A-Z]).{8,}$"
re.match(parole, "Anna1234")   # match
re.match(parole, "annaanna")   # None

# Atrod cenas, kuras seko EUR/$ - bez tām
re.findall(r"(?<=EUR )\d+\.\d{2}", "Cena EUR 12.50 vai USD 15.00")
# → ['12.50']

# Nosauktas grupas
m = re.match(r"(?P<diena>\d{2})\.(?P<menesis>\d{2})\.(?P<gads>\d{4})",
             "31.12.2026")
print(m.group("gads"))  # '2026'

HTTP un API

HTTP metodes un statusa kodi
MetodeLietojums
GETIegūt resursu
POSTIzveidot jaunu
PUTAizstāt visu
PATCHDaļēji atjaunināt
DELETEDzēst
KodsNozīme
200OK
201Created
301/302Pāradresācija
400Bad Request
401Unauthorized
403Forbidden
404Not Found
500Servera kļūda
import requests
r = requests.get("https://api.example.com/users", params={"limit": 10})
if r.status_code == 200: dati = r.json()
requests.post("/lietotaji", json={"vards": "Anna"})

JavaScript fetch ar kļūdu apstrādi

async function ieladetProfilu(id) {
  const atbilde = await fetch(`/api/profils/${id}`);

  if (!atbilde.ok) {
    throw new Error(`API kļūda: ${atbilde.status}`);
  }

  return await atbilde.json();
}

ieladetProfilu(42)
  .then(profils => console.log(profils.vards))
  .catch(kļūda => console.error(kļūda.message));

Minimāls Flask API

from flask import Flask, jsonify, request

app = Flask(__name__)
speletaji = [{"id": 1, "vards": "Anna", "punkti": 120}]

@app.get("/api/speletaji")
def visi_speletaji():
    return jsonify(speletaji)

@app.post("/api/speletaji")
def pievienot_speletaju():
    dati = request.get_json()
    jaunais = {
        "id": len(speletaji) + 1,
        "vards": dati["vards"],
        "punkti": int(dati.get("punkti", 0)),
    }
    speletaji.append(jaunais)
    return jsonify(jaunais), 201
Autentifikācija un JWT
# Pamata autentifikācijas tipi:
# 1. Basic Auth (vienkāršs, NEIZMANTOT bez HTTPS)
curl -u lietotajs:parole https://api.example.com/dati

# 2. Bearer Token (visbiežāk)
curl -H "Authorization: Bearer eyJhbGc..." https://api.example.com/lieto

# 3. API Key (cookie vai header)
curl -H "X-API-Key: ak_live_abc123" https://api.example.com

# 4. OAuth2 plūsma:
# Lietotājs → autorizē → kods → maina pret access_token
# JWT (JSON Web Token) sastāv no 3 daļām, atdalītas ar punktu:
# header.payload.signature
# Bāze64-kodēts, var lasīt klients, bet servera puse pārbauda signature

import jwt   # pip install PyJWT
SECRET = "augsts_drosibas_atslega"

# Izveidot token
token = jwt.encode(
    {"user_id": 42, "exp": 1735689600},
    SECRET, algorithm="HS256"
)

# Pārbaudīt
try:
    data = jwt.decode(token, SECRET, algorithms=["HS256"])
    user_id = data["user_id"]
except jwt.ExpiredSignatureError:
    print("Token derīgums beidzies")
except jwt.InvalidTokenError:
    print("Nederīgs token")

Drošības principi: īss derīguma laiks (15 min), refresh tokens ilgākai sesijai, HTTPS vienmēr.

Drošība

OWASP TOP 10
  1. Injekcija - vienmēr parametrizēti pieprasījumi.
  2. Sliktā autentifikācija - paroles tikai kā hash (bcrypt, argon2).
  3. Sensitīvu datu izpaušana - HTTPS visur.
  4. XML/XXE - pieņem JSON, kur iespējams.
  5. Bojāta piekļuves kontrole - pārbaudi tiesības KATRĀ servera pieprasījumā.
  6. Drošības konfigurācijas kļūdas - atjaunini atkarības.
  7. XSS - vienmēr escape lietotāja ievadi.
  8. Nedrošā deserialiācija - nepieņem pickle no neuzticamiem avotiem.
  9. Komponentes ar ievainojamībām - sekoji npm audit, Dependabot.
  10. Žurnāli - ielogo notikumus.
# SLIKTI - SQL injekcija
cur.execute(f"SELECT * FROM users WHERE id = {user_input}")

# LABI - parametrizēts
cur.execute("SELECT * FROM users WHERE id = %s", (user_input,))

import bcrypt
salts = bcrypt.gensalt()
hash_val = bcrypt.hashpw(parole.encode(), salts)
bcrypt.checkpw(ievadita.encode(), hash_val)

Noslēpumi un konfigurācija

import os

SECRET_KEY = os.environ.get("SECRET_KEY")
DATABASE_URL = os.environ.get("DATABASE_URL")

if not SECRET_KEY:
    raise RuntimeError("Nav iestatīts SECRET_KEY")

# .env failu drīkst turēt lokāli, bet nedrīkst publicēt GitHub.
# .gitignore:
# .env
# *.key

XSS piemērs

// SLIKTI: lietotājs var ievadīt <script>...</script>
output.innerHTML = komentars;

// LABI: teksts tiek parādīts kā teksts, nevis HTML
output.textContent = komentars;
Paroles, hashing un autentifikācija
import bcrypt
from secrets import token_urlsafe

# REGISTRĀCIJA - saglabā paroles hash, NEKAD plain text
def registret(parole_plain: str) -> bytes:
    salts = bcrypt.gensalt(rounds=12)  # 12 = balanss starp drošību un ātrumu
    return bcrypt.hashpw(parole_plain.encode(), salts)

stored_hash = registret("Lielparole123!")
# Datubāzē glabājas: $2b$12$XwGUDDP3M2JcvqGY...

# PIETEIKŠANĀS - salīdzini ar saglabāto hash
def pieteikties(parole_plain: str, stored_hash: bytes) -> bool:
    return bcrypt.checkpw(parole_plain.encode(), stored_hash)

# Drošu paroļu kritēriji
def stipra_parole(p: str) -> bool:
    if len(p) < 12: return False
    if not any(c.isupper() for c in p): return False
    if not any(c.isdigit() for c in p): return False
    if not any(c in "!@#$%^&*" for c in p): return False
    return True

# Drošs sesijas token
session_id = token_urlsafe(32)  # ~256 bit nejaušums

# Two-Factor Authentication (2FA) ar TOTP
import pyotp
totp = pyotp.TOTP("base32secret3232")
totp.now()         # pašreizējais 6-ciparu kods
totp.verify("123456")  # validē lietotāja ievadi

Kritiskie noteikumi: nekad nelieto MD5/SHA1 paroles; vienmēr salt; lieto rate limiting pret brute-force; loģē neveiksmīgus pieteikumus.

Izvietošana

Bezmaksas hostings
PakalpojumsKam piemērots
GitHub PagesStatiskas HTML/CSS/JS lapas
Netlify / VercelSPA, statiskas lapas, vienkāršas API
Railway / RenderPython/Node apps + PostgreSQL
Streamlit CloudStreamlit aplikācijas
Supabase / NeonBezmaksas PostgreSQL
# GitHub Pages
git push
# GitHub.com → Settings → Pages → Source: main → /(root)
# https://lietotajs.github.io/repo

# .env (NEPUSH GitHub-ā!)
DATABASE_URL=postgresql://user:pass@host/db
SECRET_KEY=randomstring

Vienkāršs publicēšanas kontrolsaraksts

# Pirms publicēšanas
git status
git diff --check
python -m pytest

# Statiskai lapai pārbaudi lokāli
python3 -m http.server 8000

# Pēc publicēšanas pārbaudi:
# 1) vai nav 404 saišu
# 2) vai darbojas mobilajā skatā
# 3) vai sitemap.xml satur jaunās lapas
Docker pamati
# Dockerfile - image receptne
# FROM bāzes_image
# RUN komandas image būvēšanai
# COPY ielādē failus
# CMD palaišanas komanda

# Piemērs Python Flask app
cat > Dockerfile << 'EOF'
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
EOF

# Build un palaišana
docker build -t mans-app:1.0 .
docker run -d -p 5000:5000 --name mans-app mans-app:1.0

# Pārvaldība
docker ps                     # darbojošies containers
docker logs mans-app          # logu skats
docker stop mans-app          # apstādina
docker rm mans-app            # noņem
docker images                 # uzskaita images

# docker-compose.yml - vairāku containers konfigurācija
cat > docker-compose.yml << 'EOF'
services:
  web:
    build: .
    ports: ["5000:5000"]
    depends_on: [db]
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: parole
    volumes:
      - dbdata:/var/lib/postgresql/data
volumes:
  dbdata:
EOF

docker compose up -d   # palaiž visu
docker compose down    # apstādina

Atkļūdošana

Stratēģijas un rīki
  1. Izlasi kļūdas ziņojumu līdz galam - Python traceback apakšā ir kļūdas tips.
  2. Print debugging - pievieno print(f"x={x}").
  3. Pārlūka konsole (F12) - JS kļūdas, tīkls, DOM.
  4. Atomu metode - komentē 50% koda, lokalizē problēmu.
  5. Rubber duck - paskaidro problēmu skaļi.
  6. Git bisect - atrod commit, kas ievieš kļūdu.
import pdb; pdb.set_trace()
# Komandas: n=next, s=step, c=continue, p mainīgais

import logging
logging.basicConfig(level=logging.DEBUG)
logging.info("Spēle sākas")
logging.warning("Datne nav atrasta")
logging.error("DB nepieslēdzas")
console.log("Vienkārša ziņa");
console.table(speletaji);
console.error("Kļūda!");
console.time("aprekins"); /* kods */ console.timeEnd("aprekins");
debugger;

Git bisect kļūdas atrašanai

git bisect start
git bisect bad                 # pašreizējā versija ir bojāta
git bisect good v1.0.0          # zināma laba versija

# Git pārslēgs commit; katrā solī palaid testu:
python -m pytest
git bisect good                 # ja tests iziet
git bisect bad                  # ja tests krīt

git bisect reset                # atgriezties sākumā
Strukturēta logging un metrikas
import logging
import json
from datetime import datetime

# Pamata konfigurācija
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s [%(levelname)s] %(name)s: %(message)s',
    handlers=[
        logging.FileHandler('app.log'),
        logging.StreamHandler()  # arī uz konsoli
    ]
)
logger = logging.getLogger(__name__)

logger.debug("Sīkdetaļas")        # parasti slēpts produkcijā
logger.info("Spēle sākas")        # noklusējuma līmenis
logger.warning("Datne neeksistē")
logger.error("DB nepieslēdzas", exc_info=True)
logger.critical("Sistēma sabrūk")

# Strukturēts logging (JSON) - viegli analizēt
class JsonFormatter(logging.Formatter):
    def format(self, record):
        return json.dumps({
            "laiks": datetime.now().isoformat(),
            "limenis": record.levelname,
            "modulis": record.name,
            "zinjojums": record.getMessage(),
            "fails": record.filename,
            "rinda": record.lineno
        })

# Konteksta info
logger.info("Spēlētājs pievienojās", extra={
    "user_id": 42, "ip": "10.0.0.1", "wave": 3
})

# Metrikas - vienkāršs skaitītājs
from collections import Counter
metrikas = Counter()
metrikas["pieprasijumi"] += 1
metrikas["errori_500"] += 1

# Periodiski izvada uz /metrics endpoint
def metrikas_json():
    return json.dumps(dict(metrikas))

5 logging līmeņi: DEBUG (sīkumi) → INFO (notikumi) → WARNING (potenciālas problēmas) → ERROR (kļūdas) → CRITICAL (sistēmas bojājumi).

Kļūdu tipi (diagnostikas kategorijas)

Pirms labošanas nosaki, kāda tipa kļūda tā ir - tas norāda, kur meklēt. Stundu "Biežākās kļūdas" sadaļas parasti pieder kādai no šīm kategorijām:

Kļūdas tipsKad rodasTipisks piemērsKur meklēt
Sintakses kļūda
(syntax error)
Programma vispār nepalaižas / nekompilējas. Trūkst :, ;, iekavas; nepareiza atkāpe. Rindā, ko norāda kļūda (vai vienu rindu augstāk).
Izpildlaika kļūda
(runtime error)
Programma sākas, bet avarē izpildes laikā. ZeroDivisionError, NullReferenceException, IndexError. Traceback apakšējā rinda; vērtība, kas bija negaidīta.
Loģikas kļūda
(logic error)
Programma strādā, bet rezultāts ir nepareizs. < vietā <=; + vietā -; cikls iet par vienu reizi par maz. Salīdzini gaidīto vs faktisko izvadi; print starprezultātus.
Stāvokļa kļūda
(state error)
Mainīgais/objekts ir negaidītā stāvoklī. Score netiek atiestatīts; sarakstu pirms cikla neiztukšo; karogs paliek true. Kur mainīgais tiek mainīts; iniciaizācija pirms cikla.
Datu-formas kļūda
(data-shape error)
Dati nav tādā formā, kā kods sagaida. "5" (str) vietā 5 (int); JSON atslēga citā nosaukumā; tukšs saraksts. Tipa pārveide (int()); print(type(x)); pārbaudi datu avotu.
Vides kļūda
(environment error)
Kods ir pareizs, bet vide nav sagatavota. Bibliotēka nav instalēta; nepareizs faila ceļš; trūkst .env; SCons/compiler trūkst. Instalācija, ceļi, versijas, atļaujas - NEVIS pats kods.
Dizaina kļūda
(design error)
Kods strādā, bet risinājums ir slikti uzbūvēts. Viena funkcija dara 5 lietas; dati dublēti; nav iespējams paplašināt. Arhitektūra: kā sadalītas atbildības; vai datu modelis der.

Diagnostikas secība: 1) vai palaižas? (sintakse/vide) → 2) vai avarē? (izpildlaiks) → 3) vai pareizs rezultāts? (loģika/stāvoklis/dati) → 4) vai labi uzbūvēts? (dizains).

Projekta plānošana un dizains

Dizaina domāšana kā piecu soļu process

Design Thinking (Dizaina domāšana) ir cilvēkcentrēta problēmu risināšanas pieeja, ko Stanford d.school formalizēja par piecu iteratīvu soļu procesu. Tā piemērojama jebkurā projektā - no spēlēm līdz mobilajām lietotnēm.

SolisMērķisSpēles izstrādes piemērs
1. Empathize (Iejusties) Saproti lietotāja vajadzības, motivāciju, sāpju punktus. Intervē 5 skolēnus par to, kādas matemātikas spēles viņiem patīk un kāpēc.
2. Define (Definēt) Formulē konkrētu problēmas paziņojumu. "7. klases skolēni vēlas trenēt reizināšanu, bet esošās lietotnes ir garlaicīgas un bez progresa saglabāšanas."
3. Ideate (Ģenerēt idejas) Brainstorming bez kritikas - daudz ideju, dažādas pieejas. Saraksts ar 20 spēles mehānikām: laika trial, kosmosa kuģi, kāršu duelis, …
4. Prototype (Prototips) Vienkāršākais variants, ar ko var testēt galveno ideju. Paper prototype: zīmē uz papīra spēles ekrānus, izspēlē "ar pirkstu".
5. Test (Testēt) Lūdz reāliem lietotājiem mēģināt, vēro, klausies. Iterē. Dod prototipu 3 skolēniem, vēro, kur viņi apjūk → atgriežas pie Define vai Ideate.

Galvenais princips: process nav lineārs - bieži jāatgriežas pie iepriekšējiem soļiem. Pirmajā prototipā 80% ideju izgāzīsies. Tas ir labi - labāk noskaidrot agri nekā pēc 6 mēnešu izstrādes.

# Projekta plāns ar Design Thinking
## 1. Empathize (1 nedēļa)
- Intervēt 5 mērķauditorijas pārstāvjus
- Apskatīt 3 konkurentu lietotnes
- Identificēt 3 lielākos sāpju punktus

## 2. Define
- Problem statement: "..."
- Mērķauditorija: ...
- Veiksmes kritēriji: ...

## 3. Ideate (brainstorming sesija 30 min)
- Min 15 ideju, bez kritikas
- Sagrupēt pēc tēmām
- Izvēlēties 3 labākās testēšanai

## 4. Prototype (2 nedēļas)
- Paper prototype → Figma mockup → MVP kods

## 5. Test
- 5 lietotāji × 30 min sesijas
- Iziet uz #1 ar jauniem datiem
Spēles dizaina dokuments (GDD)

Game Design Document (GDD) ir spēles "ceļvedis", ko izstrādātāji un komandas locekļi seko. Garums: maziem projektiem 2–5 lapas, lielām spēlēm - 100+ lapas.

# Spēles dizaina dokuments - "Krāsu lēciens"

## 1. Pārskats (1 paragrāfs)
**Žanrs:** Hyper-casual puzzle
**Mērķauditorija:** 12+ gadu, mobilais
**Platformas:** Web (HTML5), iOS, Android
**Vidējā sesija:** 3–5 minūtes
**Unique selling point:** Pirmā puzzle spēle, kurā jākoordinē trīs kustīgas figūras.

## 2. Spēles cilpa (Core Loop)
1. Spēlētājs redz krāsu mērķi.
2. Pārvieto 3 figūras, savieno krāsas.
3. Saņem punktus → līmenis aug → grūtāks mērķis.
(atkārtojas 30 sec - 5 min)

## 3. Mehānikas
- **Galvenā:** Drag-drop ar trīs vienlaicīgiem pirkstiem.
- **Sekundārā:** Combo, ja izpilda 3 mērķus pēc kārtas.
- **Power-ups:** Laika apturēšana (3 sec), Krāsu maiņa, Hint.

## 4. Vizuālais stils
- Krāsu palete: 6 piesātinātas krāsas + tumšs fons.
- Animācijas: smooth (12 FPS papīra-stila tween).
- Fonts: Sans-serif, bold (Inter).

## 5. Audio
- Mūzika: 1 fona melodija (loop, 2 min), tempa maiņa pie combo.
- SFX: drag, drop, success, fail, level-up.

## 6. Monetizācija (ja attiecas)
- Bezmaksas ar reklāmām pēc katra 5. līmeņa.
- Premium: €2.99 noņem reklāmas.

## 7. Roadmap
- v0.1 (Sept): Core mehānika prototype
- v0.5 (Okt): 10 līmeņi, audio
- v1.0 (Nov): Publicēta web versija
- v1.1 (Dec): Mobilais build
User Stories un Acceptance Criteria

User Story ir īss prasību apraksts no lietotāja viedokļa. Formāts:

Kā [loma], es vēlos [darbība], lai [vērtība].

## Story #12: Saglabāt progresu

**Kā** spēlētājs,
**es vēlos** automātiski saglabāt savu progresu,
**lai** varētu turpināt spēli citu reizi.

### Acceptance criteria
- [ ] Pēc katra pabeigta līmeņa progress tiek saglabāts.
- [ ] Atverot spēli, parādās "Turpināt" poga.
- [ ] Ja nav saglabāta spēle, "Turpināt" ir paslēpta.
- [ ] Saglabāšana izdodas pat, ja interneta nav (lokāla).
- [ ] Pēc Cleanup data (browser settings) - spēle sākas no nulles.

### Prioritāte: Must Have
### Lielums: 5 punkti
### Atkarības: #8 (Level system)

MoSCoW prioritātes:

TipsNozīme
Must HaveBez tā produkts neder. ~60% laika.
Should HaveSvarīgs, bet ne kritisks. ~20%.
Could HaveJauki, ja paspēj. ~20%.
Won't HaveŠajā versijā nē. (Skaidri pierakstīts!)
Wireframes un mockup līmeņi
LīmenisDetalitāteRīksKad lietot
SketchPildspalva uz papīra, kvadrāti+līnijasPapīrs, balta tāfele5 min - agrīna ideja
Low-fi wireframePelēktoņi, pamata layoutExcalidraw, draw.ioDiskusijas komandā
Hi-fi mockupPilna krāsa, fonts, ikonasFigma, PenpotKlientu prezentācija
Interactive prototypeKlikšķi vada uz citiem ekrāniemFigma prototype modeLietotāju testēšana
# Wireframe priekš spēles galvenā menu (ASCII)

+----------------------------------------+
|                                        |
|         [LOGO ar spēles nosaukumu]     |
|                                        |
|         +------------------+           |
|         |  ▶  SĀKT SPĒLI  |           |
|         +------------------+           |
|                                        |
|         +------------------+           |
|         |   ⚙  Iestatījumi |           |
|         +------------------+           |
|                                        |
|         +------------------+           |
|         |   ★  Rezultāti   |           |
|         +------------------+           |
|                                        |
|                          v1.0  |  MIT  |
+----------------------------------------+

Padoms: sāc ar zemākajiem līmeņiem. Pavadot 2 stundas uz Figma mock-up, kuru pēc tam dizaina diskusijā izmet, ir lielāks zaudējums nekā 10 min skiči.

Spēļu projektu piemēri

Konkrēti, viena lapas projekta plāni, kas der kā paraugi savu projektu izveidei:

Piemērs 1 - "Skaitļu minētājs" (Pong līmenis: vienkāršs)

**Apraksts:** Dators izvēlas skaitli 1–100; spēlētājs min, dators dod mājienus.
**Tehnoloģijas:** Python (CLI), random modulis
**Laiks:** 1–2 stundas
**Mehānikas:** Input, salīdzināšana, while cikls, mēģinājumu skaitīšana
**MVP:** Vienkāršs cikls ar mājieniem "lielāks"/"mazāks"
**Iespējami uzlabojumi:** Difficulty (1-100, 1-1000), HighScore, GUI ar Streamlit

Piemērs 2 - "Atmiņu kāršu spēle" (līmenis: vidējs)

**Apraksts:** 4×4 režģis ar 8 simbolu pāriem. Atrodi visus pārus.
**Tehnoloģijas:** Python + Tkinter VAI JavaScript + HTML
**Laiks:** 4–6 stundas
**Datu struktūras:** list (klājs), dict (spēles statuss)
**Mehānikas:** Random shuffle, klikšķu handler, atrašanas pārbaude
**MVP:** Statisks 4×4 ar burtiem, klikšķi atklāj, sakrišana paliek atvērta
**Uzlabojumi:** Skaņa, attēli kāršu vietā, taimeris, multi-līmeņi 6×6

Piemērs 3 - "Krustiņi un nullītes pārlūkā" (līmenis: vidējs)

**Apraksts:** Klasiska 3×3 spēle ar AI pretinieku (minimax).
**Tehnoloģijas:** HTML+CSS+JavaScript (vanilla, bez framework)
**Laiks:** 6–10 stundas
**Komponenti:** Klāja stāvoklis, gājienu validators, uzvaras pārbaude, AI
**MVP:** 2-spēlētāju režīms, uzvarētāja noteikšana
**AI:** Minimax algoritms ar alpha-beta pruning
**Uzlabojumi:** Highscore localStorage, animācijas, mobilais touch

Piemērs 4 - "Roguelike pazemes spēle" (līmenis: sarežģīts)

**Apraksts:** Procedurāli ģenerēta pazeme ar permadeath.
**Tehnoloģijas:** Godot 4 + C++ (GDExtension)
**Laiks:** 40–80 stundas
**Mehānikas:** Procedural generation, turn-based combat, inventory, perma-death
**Klases (OOP):** Player, Enemy → Goblins/Brute/Skeleton, Item, Dungeon
**MVP:** Viens līmenis, kustība, viens ienaidnieka tips, viena spēja
**Iterācijas:** +items → +spējas → +bosses → +meta-progress

Piemērs 5 - "Multiplayer šautene" (līmenis: ļoti sarežģīts)

**Apraksts:** 2-4 spēlētāju top-down šautene tiešsaistē.
**Tehnoloģijas:** Godot 4 + C++ + WebSocket servers (Node.js)
**Laiks:** 100+ stundas (komandas projekts)
**Komandas lomas:** Programmētājs ×2, dizainers, audio
**Risks:** Tīkla latency, sinhronizācijas problēmas, hackeri
**MVP:** 2 spēlētāji lokāli (split-screen)
**Iterācijas:** → LAN spēle → Tiešsaistes lobby → Matchmaking

Padoms: Vienmēr sāc ar mazāko MVP (Minimum Viable Product) - vienkāršāko versiju, ko vari spēlēt. Tikai pēc tam paplašini.

Roadmap, milestones un Gantt

Roadmap ir augstākā līmeņa projektēšanas plāns, kas parāda, kas un kad notiks. Sastāv no milestones (starpmērķiem).

# Spēles projekta Roadmap - 12 nedēļas

## Fāze 1: Plānošana (Nedēļas 1–2)
- [x] Design thinking sesijas (5 soļi)
- [x] GDD v0.1 uzrakstīts
- [x] User stories saraksts (15 stories)
- [ ] Tehnoloģiju izvēle (Godot/Unity/Web?)

## Fāze 2: Prototype (Nedēļas 3–5) 🎯 MILESTONE: Spēlējams prototips
- [ ] Core mehānika strādā
- [ ] 1 līmenis ar visiem elementiem
- [ ] Iekšējais playtest

## Fāze 3: Content (Nedēļas 6–9) 🎯 MILESTONE: Alpha versija
- [ ] 10 līmeņi
- [ ] Audio (mūzika + 5 SFX)
- [ ] Polišs (animācijas, particles)
- [ ] 5 ārējie testētāji

## Fāze 4: Polish + Launch (Nedēļas 10–12) 🎯 MILESTONE: v1.0 publicēts
- [ ] Bug fixes no testētājiem
- [ ] Web export
- [ ] Marketing (screenshot, video, README)
- [ ] Publicēšana GitHub Pages

Gantt chart vizualizē uzdevumu ilgumu un atkarības. Bezmaksas rīki: GitHub Projects, Trello, GanttProject.

# ASCII Gantt - vienkāršs piemērs

Nedēļa:           1  2  3  4  5  6  7  8  9  10 11 12
Plānošana:        ██ ██
Prototype:              ██ ██ ██
Saturs:                       ██ ██ ██ ██
Polish:                                ██ ██
Launch:                                         ██ ██

Milestones:          M1       M2          M3       LAUNCH

Daudzi izstrādātāji pārvērtē: reālistisks plāns paredz 50% buferi neparedzētiem šķēršļiem (bugs, slimības, ārējie traucēkļi).

Risku analīze un mitigācijas plāns

Pirms sākt projektu, identificē iespējamos riskus un sagatavo plānu, kā tos mazināt.

# Risku analīzes matrica

| Risks                          | Varbūtība | Ietekme | Prioritāte | Mitigācija |
|--------------------------------|-----------|---------|------------|------------|
| Komandas dalībnieks aiziet     | Vidēja    | Augsta  | KRITISKS   | Cross-training, dokumentācija |
| Tehnoloģija nestrādā kā cerēts | Augsta    | Vidēja  | AUGSTS     | Spike (prototype) 1. nedēļā |
| Saturs nav gatavs laikā        | Augsta    | Augsta  | KRITISKS   | MVP fokuss, izgriezt ne-must-have |
| Bugs pēdējā minūtē             | Augsta    | Vidēja  | AUGSTS     | Buferis 2 nedēļas pirms launch |
| Hardware/server downtime       | Zema      | Augsta  | VIDĒJS     | Backup hostings, monitoring |
| Lietotāji negaida spēli        | Vidēja    | Augsta  | AUGSTS     | Marketing sākt 2 mēnešus iepriekš |

Formula: Prioritāte = Varbūtība × Ietekme

  • Varbūtība: Zema (1), Vidēja (2), Augsta (3)
  • Ietekme: Zema (1), Vidēja (2), Augsta (3)
  • Punkti 6+ = KRITISKS - pielieto resursus tūlīt
  • Punkti 3–5 = AUGSTS - sagatavo mitigācijas plānu
  • Punkti 1–2 = VIDĒJS - monitorē

Terminu vārdnīca (EN → LV)

Programmēšanas pasaule lielākoties runā angliski. Šeit ir biežāk lietotie angļu termini, to latviskais skaidrojums un konteksts, kurā tos sastapsi ebSkola kursos. Termini ir grupēti pa jomām.

Versiju kontrole (Git / GitHub)
Termins (EN)Skaidrojums (LV)Konteksts
repository (repo)Projekta krātuve - visi faili + izmaiņu vēsture"Izveido jaunu GitHub repo"
commitIzmaiņu "fotogrāfija" ar aprakstuNofiksē pabeigtu darba posmu
pushAugšupielādēt lokālos commit uz mākoniNodod darbu vērtēšanai
pullLejupielādēt jaunākās izmaiņas no mākoņaPirms darba sākuma komandā
cloneLejupielādēt repo kopiju savā datorāTikai 1× projektam
branchZars - paralēla izstrādes līnijaJauna funkcija bez galvenā koda bojāšanas
mergeSapludināt - apvienot divus zarusPievienot funkciju main zaram
stageSagatavot failus commit'am (git add)Izvēlies, ko iekļaut nākamajā commit
remoteAttālā repo adrese (parasti GitHub)origin = noklusējuma remote
conflictKonflikts - divas izmaiņas vienā rindāJārisina manuāli pēc merge
READMEProjekta apraksta fails (Markdown)Pirmais, ko lasa cits izstrādātājs
Tīmeklis (HTML / CSS / JavaScript)
Termins (EN)Skaidrojums (LV)Konteksts
tagBirka - HTML elements, piem. <p>Lapas struktūras pamatvienība
elementElements - birka ar saturuHTML dokumenta sastāvdaļa
attributeAtribūts - birkas papildinājums, piem. href<a href="...">
selectorSelektors - CSS norāde, ko stilizēt.karte, #logo
DOMDokumenta objektu modelis - lapa kā koksJS maina lapu caur DOM
eventNotikums - klikšķis, taustiņš, ielādeaddEventListener("click", ...)
event listenerNotikuma klausītājs - reaģē uz notikumuPoga reaģē uz klikšķi
renderRenderēt - attēlot saturu ekrānāPārlūks renderē HTML
viewportSkatlogs - redzamais loga apgabalsResponsīvais dizains
responsiveResponsīvs - pielāgojas ekrāna izmēramMobilais vs dators
callbackAtzvana funkcija - izsaukta vēlākTiek izsaukta pēc notikuma
localStorageLokālā krātuve pārlūkāSaglabā highscore bez servera
Programmēšana (Python / C++)
Termins (EN)Skaidrojums (LV)Konteksts
variableMainīgais - nosaukta vērtības glabātuvescore = 0
functionFunkcija - atkārtoti lietojams koda bloksdef aprekini():
parameter / argumentParametrs (definīcijā) / arguments (izsaukumā)def f(x)f(5)
returnAtgriež - funkcijas rezultātsreturn summa
loopCikls - atkārto darbībasfor, while
scopeTvērums - kur mainīgais ir pieejamsLokālais vs globālais
module / importModulis - atsevišķs koda fails / tā ielādeimport random
libraryBibliotēka - gatavs cita autora kodsmatplotlib, requests
list / arraySaraksts / masīvs - sakārtotu vērtību kopa[1, 2, 3]
dictionary / mapVārdnīca - atslēga→vērtība pāri{"hp": 100}
classKlase - objektu veidneclass Varonis:
object / instanceObjekts / eksemplārs - no klases izveidotsv = Varonis()
methodMetode - funkcija klases iekšienēv.cizt(10)
inheritanceMantošana - bērna klase pārmanto vecākuclass Burvis(Varonis)
exceptionIzņēmums - kļūda izpildes laikātry / except
compileKompilēt - pārvērst kodu mašīnvalodāC++ ar SCons
Datubāzes un API (PostgreSQL / REST)
Termins (EN)Skaidrojums (LV)Konteksts
databaseDatubāze - strukturēta datu krātuvePostgreSQL serveris
tableTabula - rindas un kolonnasspeletaji tabula
queryVaicājums - SQL pieprasījumsSELECT * FROM ...
schemaShēma - datubāzes struktūras aprakstsTabulu un kolonnu definīcijas
primary keyPrimārā atslēga - unikāls rindas IDid SERIAL PRIMARY KEY
foreign keyĀrējā atslēga - norāde uz citu tabuluSaista spēli ar spēlētāju
JOINApvienot datus no vairākām tabulāmINNER JOIN, LEFT JOIN
CRUDCreate, Read, Update, Delete operācijasDatu pamatdarbības
transactionTransakcija - visi vai neviensBEGIN ... COMMIT
APILietotnes saskarne - programmu sazināšanāsFrontend↔backend
RESTAPI stils ar HTTP metodēm + JSONGET/POST/PUT/DELETE
endpointGalapunkts - konkrēts API URL/api/speletaji
JSONCilvēkam lasāms datu formāts{"vards": "Anna"}
request / responsePieprasījums / atbildeKlients prasa, serveris atbild
Spēļu izstrāde (Godot / C++)
Termins (EN)Skaidrojums (LV)Konteksts
EngineDzinējs - spēļu izstrādes videGodot 4
Scene TreeSkatu koks - objektu hierarhijaGodot kreisais panelis
NodeMezgls - Godot pamatobjektsSprite2D, CharacterBody2D
InspectorInspektors - objekta īpašību panelisGodot labais panelis
signalSignāls - objektu paziņojumsemit_signal("died")
GDExtensionMehānisms C++ koda lietošanai GodotKompilēta bibliotēka
collisionSadursme - objektu saskareCollisionShape2D
state machineStāvokļu mašīna - AI uzvedības modelisIDLE → CHASE → ATTACK
pathfindingCeļa meklēšana - ap šķēršļiemNavigationAgent2D, A*
object poolingObjektu atkārtota izmantošanaLādiņu veiktspējai
profilingProfilēšana - veiktspējas mērīšanaAtrast lēno kodu
deltaLaiks kopš pēdējā kadraVienmērīga kustība
export / buildEksportēt - sagatavot palaižamu versijuWeb, Windows builds
Vispārīgi izstrādes termini
Termins (EN)Skaidrojums (LV)Konteksts
IDEIntegrēta izstrādes vide - koda redaktorsVS Code
debug / debuggingAtkļūdošana - kļūdu meklēšana un labošanaBreakpoint, print
deploy / deploymentIzvietošana - publicēt internetāGitHub Pages, Render
input / outputIevade / izvadeinput() / print()
prototypePrototips - vienkāršākā strādājošā versijaMVP - minimālais produkts
refactorPārstrukturēt kodu, nemainot uzvedībuPadarīt skaidrāku
dependencyAtkarība - cita nepieciešama bibliotēkarequirements.txt
environment variableVides mainīgais - slepens iestatījums.env fails (paroles)
UI / UXLietotāja saskarne / pieredzePogas, izkārtojums, lietojamība
frontend / backendPriekšgals (redzamais) / aizmugure (serveris)HTML+JS vs Python+DB
open sourceAtvērtais pirmkods - brīvi pieejamsMIT licence
syntaxSintakse - valodas gramatikas noteikumiIekavas, atkāpes