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 σας παύουν να φτιάχνουν υποδομή — φτιάχνουν αυτό που μόνο εσείς ξέρετε να φτιάξετε: το δικό σας προϊόν.
Τα τρία επιχειρήματα για το ΔΣ σας
Συνδεθείτε και λαμβάνετε. Το κόστος σύνδεσης ενός συστήματος είναι ώρες — όχι μήνες. Ό,τι χτίζουν οι developers σας πάνω στο OS είναι δικό σας προϊόν, όχι σκαλωσιά.
Immutable ledger — κάθε γεγονός με προέλευση. Αποδεικνύετε τι έγινε, πότε, από ποιον. Το audit για το Δημόσιο δεν είναι report που φτιάχνετε — είναι replay που τρέχετε.
Ό,τι χτίζετε γίνεται 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 βήματα
Μετά την είσοδο (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": [...], ... }
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": [...] }
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)
Χρησιμοποιείται από τα δικά σας endpoints — βλέπει μόνο τα δικά σας δεδομένα (tenant guard).
/api/v1/events · /api/v1/projects/{key} · /api/v1/keys · /api/v1/webhooks · POST /api/v1/modules
Για εξωτερικά συστήματα — scoped keys, ανάκληση ανά πάσα στιγμή (soft — το audit παραμένει).
/api/v1/external/events · /api/v1/external/feedback
Λάθος ή ανακλημένο key: 401 με κεφαλίδα WWW-Authenticate: X-TenderSense-Key.
Scopes
API Reference — Public API v1 (1.0.0)
Δημόσιο. Έκδοση + κατάσταση του API — για monitors και handshake.
Session. «Τι άλλαξε στον πυρήνα» — append-only events. since_hours 1–720, limit 1–500. Επιστρέφει stats (μετρήσεις ανά τύπο) + events.
Session. Το χρονολόγιο ενός έργου από το replay — ο πυρήνας, όχι η όψη. 404 αν δεν υπάρχει.
API key (read:events). Η ίδια ροή γεγονότων για εξωτερικά συστήματα.
API key (write:feedback). Body: {"entity": "...", "reason": "...", "evidence": ["..."]} → 202 + action_id. Γίνεται typed action EXTERNAL_FEEDBACK.
Session. Διαχείριση API keys (max 10). Το secret μία φορά. Ανάκληση = soft (audit διατηρείται).
Το GET είναι δημόσιο (κατάλογος). Το POST θέλει session — καταχωρεί module που μιλάει το Action Protocol.
Session. Καταχώρηση endpoint (max 10) — δείτε παρακάτω «Webhooks».
Webhooks — push συμβάντων με υπογραφή (replay-safe)
Καταχωρείτε URL + λίστα συμβάντων + secret. Κάθε delivery φέρει τέσσερις κεφαλίδες — η υπογραφή καλύπτει timestamp + delivery-id + body, ώστε ένα παλιό delivery να μην μπορεί να επαναπαιχθεί:
event.created tender.published contract.expiring approval.requested payment.recorded authority.feedback stage_transition typed_action_proposal
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
OpenAPI specification & SDK
Το πλήρες μηχαναγνώσιμο σχήμα του API είναι δημοσιευμένο — για codegen (openapi-generator, Postman, client libraries):
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) — νέες εκδόσεις δεν σπάνε υπάρχουσες συνδέσεις.
Ερωτήσεις; Επικοινωνήστε μαζί μας.