2 System Overview
Othmane Ataallah edited this page 2026-07-29 08:39:03 +02:00

System Overview — the bigger picture

How our three projects, our tools and our Git workflow fit together. Ten minutes here saves weeks of confusion. Diagrams are Mermaid — Gitea renders them natively.


1. The whole system at a glance

Three products, one contract, one origin server. Every dev has the SAME local setup; Gitea is the only shared machine.

flowchart TB
    subgraph TEAM["👥 Team"]
        PM["PM<br/>backlog · reviews · decisions<br/>owns openapi.yaml"]
        DEVS["3 devs<br/>one per repo"]
    end

    subgraph GITEA["🗄️ Gitea — ORIGIN (the only shared server)"]
        direction LR
        RAPI["trizagenda-api<br/>code · issues · board"]
        RWEB["trizagenda-web<br/>code · issues · board"]
        RMOB["trizagenda-mobile<br/>code · issues · board"]
        RTEAM["trizagenda-team<br/>this wiki · shared docs"]
    end

    subgraph MACHINE["💻 Each dev machine (identical, self-sufficient)"]
        direction LR
        CLONES["local clones<br/>feature branches"]
        RUNTIME["local runtime<br/>API + clients + docker services<br/>(diagram 2)"]
    end

    DEVS -->|"branch → push → Pull Request"| GITEA
    PM -->|"review ≤ 24h · squash merge · milestone tags"| GITEA
    GITEA -->|"clone · pull --rebase daily"| CLONES
    CLONES --> RUNTIME

    classDef origin fill:#e8eef7,stroke:#1a4b8c,stroke-width:2px;
    class GITEA origin;

Read it like this: code and decisions flow through Gitea and nowhere else. Nothing is deployed anywhere yet — "the system" runs complete on every dev machine, every day.


2. Runtime — how the three apps exchange data (on YOUR machine)

flowchart LR
    subgraph CLIENTS["Clients"]
        WEB["🌐 trizagenda-web<br/>React 19 · Vite · :5173<br/>session = httpOnly refresh cookie"]
        MOB["📱 trizagenda-mobile<br/>Flutter · emulator<br/>session = X-Refresh-Token header"]
    end

    subgraph CONTRACT["📜 THE contract"]
        SPEC["openapi.yaml v1.2.1<br/>single source of truth<br/>(copy in each repo)"]
        PRISM["Prism mock · :4010<br/>fake API serving the spec"]
    end

    subgraph APISRV["⚙️ trizagenda-api — Spring Boot · :8080/api/v1"]
        REST["REST JSON<br/>JWT Bearer 15 min<br/>+ rotating refresh tokens"]
        STOMP["WebSocket / STOMP<br/>(M4 — topic contract = spec candidate)"]
    end

    subgraph COMPOSE["🐳 docker compose up -d   (in trizagenda-api/)"]
        PG[("PostgreSQL 16 · :5432<br/>THE database — schema owned by Flyway")]
        REDIS[("Redis 7 · :6379<br/>rate-limit & cache backend (M6)")]
        MINIO[("MinIO · :9000 / UI :9001<br/>S3 files — avatars & attachments")]
        MAILPIT["Mailpit · SMTP :1025<br/>inbox UI → http://localhost:8025<br/>catches EVERY dev email (OTP reset)"]
    end

    WEB -->|"HTTP JSON · cookie flow"| REST
    MOB -->|"HTTP JSON · 10.0.2.2:8080<br/>X-Client-Type: mobile"| REST
    WEB -.->|"mock-first features"| PRISM
    MOB -.->|"mock-first features"| PRISM
    SPEC --> PRISM
    SPEC -.->|"npm run generate:api → TS types"| WEB
    REST --> PG
    REST --> REDIS
    REST --> MINIO
    REST -->|"OTP reset email"| MAILPIT
    STOMP -.->|"real-time notifications (M4)"| WEB
    STOMP -.->|"real-time notifications (M4)"| MOB

    classDef spec fill:#fdf3d8,stroke:#b8860b,stroke-width:2px;
    class SPEC spec;
    classDef future stroke-dasharray: 5 5;
    class STOMP future;

The rules that make this work:

  • Clients NEVER talk to the database or to each other — everything crosses the API, which enforces roles/scope from the JWT. The only shared state between web and mobile IS the API's database.
  • openapi.yaml is the treaty. The API implements it, web generates its TypeScript types from it, Prism mocks it, and nobody invents an endpoint outside it. Spec change = version bump by the PM, announced, copies re-synced (npm run generate:api on web).
  • Mock-first: new client features are built against Prism (:4010) so nobody waits on the API dev; auth is the exception — always the real API. At each milestone's integration checkpoint, that feature flips from mock to real.
    • Mobile nuance: the app currently ships a demo-data layer (fake repositories inside the app) instead of Prism for non-auth domains — same principle, same swap points (see mobile ARCHITECTURE.md §6).
  • Emails never leave your machine in dev: the API sends real SMTP to Mailpit (http://localhost:8025). Production swaps in a real SMTP server via MAIL_* env vars — same code, different application-*.yml profile.
  • The database schema belongs to Flyway migrations (V*__*.sql in the API repo) — never edit an applied migration; local reset = docker compose down -v.

3. Git — origin vs your machine

Trunk-based, squash-only, tags per milestone (full rules).

gitGraph
   commit id: "main"
   commit id: "M1 starts"
   branch feat/API-12-rate-limit
   checkout feat/API-12-rate-limit
   commit id: "feat: limiter"
   commit id: "test: limiter"
   checkout main
   merge feat/API-12-rate-limit id: "PR 12 — squash" type: HIGHLIGHT
   branch feat/API-14-blacklist
   checkout feat/API-14-blacklist
   commit id: "feat: blacklist"
   checkout main
   merge feat/API-14-blacklist id: "PR 14 — squash"
   commit id: "checkpoint fixes" tag: "v0.1.0"
  • main is protected — it only moves by squash-merged PRs, so one commit = one issue, and git log reads like the changelog.
  • Local machine: your clone, your feature branches (feat/API-12-slug), your WIP commits — messy is fine there, the squash cleans it up.
  • Origin (Gitea): protected main + your pushed branches + the PR conversation.
  • Every morning: git pull --rebase origin main on your branch — small daily rebases instead of one giant conflict at PR time.
  • Milestone end: the PM tags main (v0.1.0 … v1.0.0) right after the integration checkpoint passes.

4. The daily loop — issue to merged

flowchart LR
    A["📋 Pick the top<br/>'Ready' issue<br/>on the milestone board"] --> B["🌱 branch<br/>feat/XXX-nn-slug"]
    B --> C["🔨 code + tests<br/>mvn verify · npm test<br/>flutter analyze && flutter test"]
    C --> D["⬆️ push → PR on Gitea<br/>template + screenshots"]
    D --> E{"👀 PM review<br/>≤ 24h"}
    E -->|"changes requested"| C
    E -->|"approved"| F["🔀 squash merge<br/>→ main"]
    F --> G["🔁 everyone:<br/>git pull --rebase"]
    G --> A

    classDef gate fill:#fdecea,stroke:#c0392b;
    class E gate;

While a PR waits for review: start the next Ready issue — never idle on a blocked PR.


5. Dev vs production (so nobody confuses the two)

Dev (your machine) Production (later)
API config application-dev.yml (safe defaults) application-prod.yml — everything from env vars, fail-fast
Database docker Postgres, disposable (down -v) managed PostgreSQL, backed up
Emails Mailpit (nothing leaves the machine) real SMTP (MAIL_* env)
Files docker MinIO S3-compatible storage
Secrets dev-only values in dev yml env vars only — never in git
API docs Swagger UI on off

Same code, same images, different profile — that's the whole trick.