TenderSense OS Docs

Documentation — γιατί OS + πώς συνδέεσαι

Δύο μέρη. Πρώτα το αφήγημα — για επιχειρηματίες που θέλουν να καταλάβουν γιατί πρέπει να το δώσουν στους developers τους. Μετά το πλήρες τεχνικό documentation — για τους developers.

Μέρος 1 — Γιατί το λέμε λειτουργικό σύστημα

ΣΕ ΜΙΑ ΠΡΟΤΑΣΗ

Το TenderSense OS είναι το λειτουργικό σύστημα των ελληνικών B2G: ένας πυρήνας με όλα τα δεδομένα των δημόσιων συμβάσεων (χρηματοδότηση, προκήρυξη, σύμβαση, πληρωμή) σε immutable ledger, μία κοινή γλώσσα (Action Protocol) και ένα API — έτσι ώστε κάθε εταιρεία να συνδέει τα συστήματά της αντί να ξαναχτίζει υποδομή, και κάθε δημόσιος φορέας να έχει μία καθαρή εικόνα των έργων του.

Το πρόβλημα που βλέπουμε κάθε εβδομάδα

Μια τεχνολογική εταιρεία που δουλεύει με το Δημόσιο ξοδεύει, σήμερα, εκατοντάδες ώρες developers για να χτίσει — ξανά και ξανά — τα ίδια πέντε πράγματα: πώς μπαίνουν οι διαγωνισμοί στο σύστημά της, πώς ειδοποιείται η ομάδα, πώς παρακολουθείται μία σύμβαση, πώς βγαίνει η αναφορά για το ΔΣ, πώς αποδεικνύεται στο τέλος τι έγινε και πότε.

Αυτά τα πέντε πράγματα είναι υποδομή. Δεν είναι το προϊόν κανενός. Και όμως κάθε εταιρεία τα ξαναπληρώνει — στο δικό της silo, με τον δικό της τρόπο, που αύριο δεν μιλάει με τίποτα.

Όσο τα δεδομένα των δημόσιων συμβάσεων αλλάζουν κάθε μέρα (νέες προκηρύξεις, τροποποιήσεις, πληρωμές), τόσο ακριβότερο γίνεται το «ξαναχτίσιμο». Το πρόβλημα δεν είναι η έλλειψη δεδομένων — είναι ότι δεν υπάρχει ένα σύστημα στο οποίο συνδέεσαι. Υπάρχουν εργαλεία που σε βάζουν μέσα στο δικό τους κουτί.

Η λύση — ένα «λειτουργικό», όχι ένα «εργαλείο»

Το TenderSense OS είναι το στρώμα που λείπει: ο πυρήνας δεδομένων (όλα τα έργα, οι φάσεις, οι πληρωμές, σε μία γλώσσα), το Action Protocol (η γλώσσα με την οποία κάθε πρόγραμμα ζητάει πράγματα από τον πυρήνα) και το API (η πόρτα μέσα από την οποία συνδέεται οποιοδήποτε δικό σας σύστημα).

Όπως τα Windows ή το Linux δεν είναι «μία εφαρμογή» — είναι αυτό που κάνει όλες τις εφαρμογές να δουλεύουν μαζί — έτσι και εδώ: το OS δεν αντικαθιστά το ERP ή το CRM σας. Τα συνδέει.

Όταν η εταιρεία σας συνδεθεί, παύει να «εισάγει διαγωνισμούς» — το σύστημα τους ξέρει ήδη. Παύει να «παρακολουθεί συμβάσεις» — το σύστημα τις παρακολουθεί και σας ειδοποιεί. Οι developers σας παύουν να φτιάχνουν υποδομή — φτιάχνουν αυτό που μόνο εσείς ξέρετε να φτιάξετε: το δικό σας προϊόν.

Τα τρία επιχειρήματα για το ΔΣ σας

1. Δεν ξαναπληρώνετε υποδομή

Συνδεθείτε και λαμβάνετε. Το κόστος σύνδεσης ενός συστήματος είναι ώρες — όχι μήνες. Ό,τι χτίζουν οι developers σας πάνω στο OS είναι δικό σας προϊόν, όχι σκαλωσιά.

2. Τα δεδομένα σας μένουν δικά σας

Immutable ledger — κάθε γεγονός με προέλευση. Αποδεικνύετε τι έγινε, πότε, από ποιον. Το audit για το Δημόσιο δεν είναι report που φτιάχνετε — είναι replay που τρέχετε.

3. Μέλλον, όχι κουτί

Ό,τι χτίζετε γίνεται module που μιλάει το Action Protocol — δουλεύει με όλα τα υπόλοιπα, σήμερα και με ό,τι έρθει αύριο. Δεν αγοράζετε ένα εργαλείο που θα ξεπεράσετε. Συνδέεστε με ένα σύστημα.

Η πρόταση — δώστε αυτό στους developers σας

Αν είστε επιχειρηματίας, αυτό είναι το email που στέλνετε στην ομάδα σας:

«Παιδιά, σταματάμε να ξαναφτιάχνουμε την υποδομή των δημόσιων συμβάσεων.
Το TenderSense OS έχει ήδη τον πυρήνα: όλα τα έργα, οι φάσεις, οι πληρωμές,
σε ένα immutable ledger. Έχει Action Protocol — μία γλώσσα για ό,τι χτίζουμε.
Έχει API με keys και webhooks.

Διαβάστε το documentation παρακάτω, συνδεθείτε, και ό,τι ώρες θα πηγαίναν
σε scraping, εισαγωγές και αναφορές — πηγαίνουν στο προϊόν μας.»

— και μετά, το Μέρος 2.

Μέρος 2 — Τεχνική τεκμηρίωση για developers

Η αρχιτεκτονική με μία ματιά

τα δικά σας συστήματα (ERP, DMS, CRM, πανεπιστήμια, φορείς)
        │
        │  X-TenderSense-Key / webhooks (HMAC)
        ▼
┌──────────────────────── TenderSense OS ────────────────────────┐
│  Public API v1          — /api/v1/...        (REST, versioned) │
│  Action Protocol v1.0   — typed actions      (η γλώσσα = ABI)  │
│  Webhook dispatcher     — event.*            (push, signed)    │
│  Immutable event ledger — append-only        (provenance)      │
│  Replay engine          — χρονολόγιο ανά έργο (audit)          │
│  Tenants                — απομόνωση δεδομένων ανά οργανισμό    │
└────────────────────────────────────────────────────────────────┘
        ▲
        │  εμείς: οι εφαρμογές Revenue OS + Authority OS
        │  (Bid Room, Contract Room, Cockpit, Project Twin, Command Center)

Ο πυρήνας είναι append-only: τίποτα δεν διαγράφεται, κάθε γεγονός έχει χρονοσφραγίδα, προέλευση και fingerprint. Οι όψεις (UI) ξαναχτίζονται από τα γεγονότα — γι' αυτό μπορούμε να αναπαράγουμε το ιστορικό κάθε έργου ακριβώς όπως έγινε (replay).

Quickstart — πρώτη σύνδεση σε 3 βήματα

1. Δημιουργήστε API key

Μετά την είσοδο (session), δημιουργείτε κλειδί με τα scopes που χρειάζεστε. Το secret εμφανίζεται μία μόνο φορά — αποθηκεύουμε μόνο τον hash.

curl -X POST https://tendersense.gr/api/v1/keys \
  -H "Authorization: Bearer $TS_SESSION" \
  -H "Content-Type: application/json" \
  -d '{"name": "my-erp", "scopes": ["read:events", "write:feedback"]}'

→ { "id": "...", "name": "my-erp", "secret": "ts_…", "scopes": [...], ... }
2. Διαβάστε τον πυρήνα
curl https://tendersense.gr/api/v1/health
→ { "api": "tendersense-v1", "version": "1.0.0", "status": "ok" }

curl -H "X-TenderSense-Key: ts_…" \
  "https://tendersense.gr/api/v1/external/events?since_hours=24"
→ { "api_version": "1.0.0", "since": "…", "stats": {...}, "events": [...] }
3. Γράψτε πίσω — feedback
curl -X POST https://tendersense.gr/api/v1/external/feedback \
  -H "X-TenderSense-Key: ts_…" \
  -H "Content-Type: application/json" \
  -d '{"entity": "PROJECT-123", "reason": "Η δαπάνη έχει εγκριθεί από το ΔΣ",
       "evidence": ["DECISION-44"]}'
→ 202 { "accepted": true, "action_id": "…" }

Το feedback γίνεται typed action και φτάνει στον ιδιοκτήτη των δεδομένων για έγκριση — με πλήρες audit. Ο κύκλος read → act → write back κλείνει χωρίς μεσολάβηση.

Πιστοποίηση (Authentication)

Authorization: Bearer <token> Session χρήστη

Χρησιμοποιείται από τα δικά σας endpoints — βλέπει μόνο τα δικά σας δεδομένα (tenant guard).

/api/v1/events · /api/v1/projects/{key} · /api/v1/keys · /api/v1/webhooks · POST /api/v1/modules

X-TenderSense-Key: ts_… Server-to-server

Για εξωτερικά συστήματα — scoped keys, ανάκληση ανά πάσα στιγμή (soft — το audit παραμένει).

/api/v1/external/events · /api/v1/external/feedback

Λάθος ή ανακλημένο key: 401 με κεφαλίδα WWW-Authenticate: X-TenderSense-Key.

Scopes

read:events
Ανάγνωση των γεγονότων του πυρήνα (external/events).
read:projects
Ανάγνωση χρονολογίου έργων.
write:feedback
Υποβολή feedback (typed action) στον ιδιοκτήτη.

API Reference — Public API v1 (1.0.0)

GET /api/v1/health

Δημόσιο. Έκδοση + κατάσταση του API — για monitors και handshake.

GET /api/v1/events?since_hours=24&event_type=&limit=100

Session. «Τι άλλαξε στον πυρήνα» — append-only events. since_hours 1–720, limit 1–500. Επιστρέφει stats (μετρήσεις ανά τύπο) + events.

GET /api/v1/projects/{project_key}

Session. Το χρονολόγιο ενός έργου από το replay — ο πυρήνας, όχι η όψη. 404 αν δεν υπάρχει.

GET /api/v1/external/events?since_hours=24&limit=100

API key (read:events). Η ίδια ροή γεγονότων για εξωτερικά συστήματα.

POST /api/v1/external/feedback

API key (write:feedback). Body: {"entity": "...", "reason": "...", "evidence": ["..."]} → 202 + action_id. Γίνεται typed action EXTERNAL_FEEDBACK.

GET / POST /api/v1/keys · DELETE /api/v1/keys/{key_id}

Session. Διαχείριση API keys (max 10). Το secret μία φορά. Ανάκληση = soft (audit διατηρείται).

GET /api/v1/modules · POST /api/v1/modules

Το GET είναι δημόσιο (κατάλογος). Το POST θέλει session — καταχωρεί module που μιλάει το Action Protocol.

GET / POST /api/v1/webhooks · DELETE /api/v1/webhooks/{webhook_id}

Session. Καταχώρηση endpoint (max 10) — δείτε παρακάτω «Webhooks».

Webhooks — push συμβάντων με υπογραφή (replay-safe)

Καταχωρείτε URL + λίστα συμβάντων + secret. Κάθε delivery φέρει τέσσερις κεφαλίδες — η υπογραφή καλύπτει timestamp + delivery-id + body, ώστε ένα παλιό delivery να μην μπορεί να επαναπαιχθεί:

X-TenderSense-Signature HMAC-SHA256(secret, "{timestamp}.{delivery_id}.{body}") X-TenderSense-Timestamp unix seconds (δημιουργία του delivery) X-TenderSense-Delivery-Id μοναδικό id (hex) — dedup στον παραλήπτη X-TenderSense-Event ο τύπος του συμβάντος
Υποστηριζόμενα συμβάντα
event.created
tender.published
contract.expiring
approval.requested
payment.recorded
authority.feedback
stage_transition
typed_action_proposal
Επαλήθευση + replay protection (Python)
import hmac, hashlib, time

def verify(secret, headers, raw_body):
    ts = headers.get("X-TenderSense-Timestamp", "")
    did = headers.get("X-TenderSense-Delivery-Id", "")
    sig = headers.get("X-TenderSense-Signature", "")
    if not ts.isdigit() or abs(int(time.time()) - int(ts)) > 300:
        return False  # replay: πολύ παλιό delivery
    material = f"{ts}.{did}.".encode() + raw_body
    expected = hmac.new(secret.encode(), material,
                        hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, sig)
    # + κρατήστε τα delivery-id που έχετε δει (dedup)

Τα δημόσια webhook URLs πρέπει να είναι https (τα συμβάντα περιέχουν επιχειρησιακά δεδομένα). http μόνο για localhost. Αποτυχημένα deliveries ξαναδοκιμάζονται (3 attempts, backoff) — όλα στο audit.

Action Protocol v1.0 — το ABI

Κανένα πρόγραμμα δεν αλλάζει κρίσιμα δεδομένα — υποβάλλει δομημένη πρόταση. Ο άνθρωπος εγκρίνει.

Το σχήμα
{
  "action": "REQUEST_PRICING_APPROVAL",
  "entity": "OPP-2048",
  "reason": "...",
  "evidence": ["PRICE-12", "COST-44"],
  "confidence": 0.91,
  "requires_human_approval": true
}

Κύκλος ζωής: proposed → approved → executed — ή rejected / expired. Όλα στο ledger.

Το λεξικό (γνωστές ενέργειες)
REQUEST_PRICING_APPROVAL
REQUEST_COMPLIANCE_REVIEW
REQUEST_LEGAL_REVIEW
REQUEST_BID_APPROVAL
SUBMIT_OFFER
LOG_DECISION
NOTIFY_OWNER
AUTHORITY_CONFIRM_TENDER
EXTERNAL_FEEDBACK

Ευαίσθητες (SUBMIT_OFFER, εγκρίσεις κ.λπ.) ποτέ δεν εκτελούνται αυτόματα — απαιτούν ανθρώπινη έγκριση.

Module manifest — για ό,τι χτίζετε πάνω στο OS

Τι σημαίνει «καταχώρηση»: το marketplace είναι μητρώο (directory). Εμείς αποθηκεύουμε ΜΟΝΟ το manifest — ποτέ δεν εκτελούμε τον κώδικά σας μέσα στο TenderSense. Το module τρέχει στο δικό σας σύστημα και συνδέεται με τον πυρήνα μέσω API key (read/write) και webhook_url (push). «Εγκατάσταση» = ο τελικός χρήστης δίνει το δικό του key στο module σας — δεν ανεβαίνει κώδικας σε εμάς.

Το action_protocol_version δηλώνει ποια έκδοση του ABI μιλάει (τρέχουσα: 1.0). Το slug είναι δικό σας — κανείς άλλος δεν μπορεί να το πάρει.

{
  "slug": "my-invoicing-bridge",
  "name": "Invoicing Bridge",
  "description": "Στέλνει πληρωμές ΚΗΜΔΗΣ στο ERP μας",
  "author": "My Company",
  "version": "0.1.0",
  "action_protocol_version": "1.0",
  "actions": [
    {"action": "NOTIFY_OWNER"},
    {"action": "LOG_DECISION"}
  ],
  "webhook_url": "https://mycompany.example/hooks/ts"
}

Κανόνες: slug αλφαριθμητικό (a-z0-9-_), name υποχρεωτικό, τουλάχιστον μία action, max 50 actions, description ≤ 500, version ≤ 30 χαρακτήρες, webhook_url ≤ 300.

Ο πυρήνας — immutable event ledger + replay

Append-only (εφαρμογή). Κανένα API δεν τροποποιεί ούτε διαγράφει γεγονός — μόνο append. Κάθε γεγονός έχει τύπο, οντότητα, χρονοσφραγίδα, προέλευση και fingerprint (τα διπλότυπα δεν περνάνε).
Tamper-evident (hash chain). Κάθε γεγονός αποθηκεύει prev_hash + hash (SHA-256 πάνω στο προηγούμενο + το δικό του περιεχόμενο). Αλλαγή ενός γεγονότος σπάει ολόκληρη την αλυσίδα — ελέγξιμο με verify_ledger_integrity().
Replay. Το χρονολόγιο κάθε έργου αναπαράγεται από τα γεγονότα — όχι από αποθηκευμένη όψη. Έτσι ένα audit είναι απλώς «τρέξε το replay» — και το αποτέλεσμα είναι πάντα ίδιο με το τότε.
Τι ΔΕΝ είναι. Δεν είναι blockchain — δεν υπάρχει κατανεμημένη συναίνεση· η εμπιστοσύνη στηρίζεται στη δική μας υποδομή (MongoDB) και στον έλεγχο πρόσβασης. Το tamper-evidence εντοπίζει αλλαγές — δεν τις αποτρέπει από διαχειριστή της βάσης.

OpenAPI specification & SDK

Το πλήρες μηχαναγνώσιμο σχήμα του API είναι δημοσιευμένο — για codegen (openapi-generator, Postman, client libraries):

Python SDK — πλήρες παράδειγμα
from tendersense_sdk import TenderSenseClient

ts = TenderSenseClient(api_key="ts_...")

ts.health()                                   # { "api": "tendersense-v1", "version": "1.0.0", "status": "ok" }
ts.external_events(since_hours=24)            # η ροή γεγονότων του πυρήνα
ts.external_feedback("PROJECT-123",
                     "Η δαπάνη εγκρίθηκε", ["DECISION-44"])   # → typed action

# Webhook επαλήθευση με replay protection:
TenderSenseClient.verify_webhook_request(
    secret, request_headers, raw_body, max_age_seconds=300)

# Με session χρήστη (για keys / webhooks / modules):
ts2 = TenderSenseClient(session_token="<bearer>")
ts2.create_key("my-erp", ["read:events", "write:feedback"])
ts2.register_webhook("https://my.example/hook", ["payment.recorded"])
ts2.register_module({...})                    # manifest — βλέπε παραπάνω

Το SDK είναι μόνο stdlib — αντιγράφεται, ενσωματώνεται και διανέμεται ελεύθερα. Πλήρης τεκμηρίωση στο docstring.

Ασφάλεια — αρχιτεκτονική, όχι υπόσχεση

  • Immutable ledger — append-only + SHA-256 hash chain: κάθε γεγονός δεσμεύει το προηγούμενο (tamper-evident, ελέγξιμο).
  • Action Protocol — καμία ευαίσθητη ενέργεια χωρίς ανθρώπινη έγκριση· confidence 1.0 μόνο για ντετερμινιστικές συνδέσεις κωδικών.
  • Tenant απομόνωση — κάθε οργανισμός βλέπει μόνο τα δεδομένα του· το API δεν μπορεί να διαρρεύσει δεδομένα άλλου.
  • API keys — μόνο hash αποθηκεύεται· ανάκληση = soft (audit διατηρείται).
  • Webhooks — HMAC-SHA256 πάνω σε timestamp+delivery-id+body· replay-safe.
  • Υποδομή — εντός Ευρωπαϊκής Ένωσης, GDPR, αντίγραφα ασφαλείας.

Όρια & πολιτικές

  • since_hours: 1–720 · limit: 1–500 σε όλα τα list endpoints.
  • API keys: max 10 ανά λογαριασμό · webhooks: max 10 ανά λογαριασμό.
  • Ανάκληση key / webhook = soft delete — το ιστορικό (audit) παραμένει.
  • Tenant απομόνωση: με session βλέπετε μόνο τα δικά σας δεδομένα — το API δεν μπορεί να διαρρεύσει δεδομένα άλλου οργανισμού.
  • Versioning: το API είναι versioned (/api/v1) — νέες εκδόσεις δεν σπάνε υπάρχουσες συνδέσεις.

Ερωτήσεις; Επικοινωνήστε μαζί μας.