Γέφυρες συνομιλίας
Μια γέφυρα συνομιλίας κάνει ένα εξωτερικό προϊόν συνομιλίας — σήμερα το Slack — έναν πρώτης τάξης τρόπο εισόδου σε έναν χώρο εργασίας του Control Center. Κάντε @-αναφορά στο bot και ένας πράκτορας ξυπνά· απαντήστε στο νήμα του Slack και η συνομιλία συνεχίζεται· πληκτρολογήστε μια εντολή slash και ένα εισιτήριο καταχωρείται. Κάτω από αυτά, οι ίδιοι χώροι, οι ίδιες μεταγραφές, τα ίδια εισιτήρια και η ίδια απόδοση που χρησιμοποιεί η εφαρμογή υπολογιστή. Η συνομιλία είναι μια επιφάνεια πάνω στον χώρο εργασίας, όχι ένα αντίγραφό του.
Το Slack είναι ο μόνος πάροχος που διατίθεται. Δεν υπάρχει υλοποίηση για Discord, Telegram, Teams ή Matrix πουθενά στο προϊόν. Η λειτουργία είναι γραμμένη σκόπιμα τυφλή ως προς τον πάροχο — η προσθήκη ενός δεύτερου προϊόντος είναι μία τιμή enum, ένας προσαρμογέας και ένα plugin — αλλά σήμερα «συνομιλία» σημαίνει Slack.
Δύο επιφάνειες την καλύπτουν και ανήκουν σε διαφορετικούς ανθρώπους. Η σύνδεση ενός χώρου εργασίας με το Slack και η προσαρμογή του bot είναι ενέργειες διαχειριστή στις Ρυθμίσεις → Χώρος εργασίας → Γενικά. Η σύνδεση του δικού σας λογαριασμού συνομιλίας με την ταυτότητά σας στο Control Center είναι ενέργεια μέλους στις Ρυθμίσεις → Χώρος εργασίας → Προφίλ και ταυτότητα.
Τρεις αποφάσεις διαμορφώνουν ολόκληρη τη λειτουργία: προς ποια κατεύθυνση τρέχει η σύνδεση, τι εξουσιοδοτεί ένα μήνυμα που φτάνει από έξω και πού επιτρέπεται να ζει η γνώση για συγκεκριμένα προϊόντα.
Εξερχόμενη εκ σχεδιασμού
Ενότητα με τίτλο «Εξερχόμενη εκ σχεδιασμού»Η γέφυρα δεν ακούει ποτέ για λογαριασμό του παρόχου. Στο Slack φτάνει μέσω Socket Mode: ο διακομιστής ζητά από το Slack ένα URL socket και καλεί προς τα έξω, και μετά λαμβάνει αναφορές, άμεσα μηνύματα και εντολές slash μέσα από αυτή τη σύνδεση.
Η συνέπεια είναι το νόημα. Ένας φορητός υπολογιστής πίσω από NAT, ένας οικιακός διακομιστής χωρίς domain, ένα μηχάνημα που αλλάζει δίκτυα — όλα τους μπορούν να εκτελέσουν τη γέφυρα χωρίς θύρα εισόδου, χωρίς tunnel, χωρίς πιστοποιητικό TLS και χωρίς δημόσιο URL προς εναλλαγή όταν αλλάζει. Δεν υπάρχει τελικό σημείο webhook προς ασφάλιση, γιατί δεν υπάρχει τελικό σημείο webhook. Όταν το Control Center συνθέτει τον ορισμό της εφαρμογής, επιβάλλει το Socket Mode και αφαιρεί κάθε request URL, γιατί μια εφαρμογή ρυθμισμένη και για τα δύο θα ήταν μια εφαρμογή που δουλεύει μισά.
Το κόστος είναι μια σύνδεση που πρέπει να κρατηθεί ζωντανή, κάτι που είναι δουλειά του διακομιστή: η επανασύνδεση γίνεται με εκθετική καθυστέρηση επανάληψης με τυχαία διακύμανση, με ανώτατο όριο τα 30 δευτερόλεπτα, μια εναλλαγή socket που ξεκινά ο πάροχος επανασυνδέεται χωρίς να κλιμακώσει αυτή την καθυστέρηση και ένα απορριφθέν διαπιστευτήριο είναι τελειωτικό — η αέναη επανάληψη ενός ανακληθέντος token θα κέρδιζε μόνο ένα όριο ρυθμού, οπότε η γέφυρα σταματά και περιμένει νέα token, αναφέροντας αυτούσιο το σφάλμα του ίδιου του παρόχου στις ρυθμίσεις.
Ένας χώρος εργασίας χωρίς εφαρμογή συνομιλίας δεν κοστίζει απολύτως τίποτα: κανένα socket, κανένα χρονόμετρο, καμία κίνηση. Και το όλο πράγμα ξεκινά μετά το μήνυμα ετοιμότητας του διακομιστή, γιατί μια εφαρμογή συνομιλίας που αργεί να απαντήσει δεν πρέπει ποτέ να καθυστερήσει την εκκίνηση.
Εξουσιοδοτεί η ιδιότητα μέλους, όχι η κατοχή token
Ενότητα με τίτλο «Εξουσιοδοτεί η ιδιότητα μέλους, όχι η κατοχή token»Ο άνθρωπος που εγκατέστησε την εφαρμογή δεν είναι ο άνθρωπος που στέλνει το μήνυμα. Έτσι, κάθε εισερχόμενο συμβάν επιλύεται σε ένα υποκείμενο πριν συμβεί οτιδήποτε και κλείνει κατά την αποτυχία με μια εξήγηση:
- Ένας λογαριασμός συνομιλίας χωρίς σύνδεση ενημερώνεται πώς να συνδεθεί, μέσα στο νήμα του Slack όπου έγραψε.
- Ένας συνδεδεμένος λογαριασμός του οποίου ο χρήστης δεν είναι μέλος αυτού του χώρου εργασίας καλείται να ζητήσει πρόσκληση από έναν διαχειριστή.
- Ένα μέλος με ρόλο μόνο για ανάγνωση (
viewer,guest) ενημερώνεται ότι ο ρόλος του δεν μπορεί να ξεκινήσει εργασία.
Καμία από αυτές τις περιπτώσεις δεν προχωρά. Ένα μήνυμα συνομιλίας δεν αποδίδεται ποτέ σε κάποιον που δεν το έστειλε — αυτό είναι που κρατά ειλικρινή το ίχνος ελέγχου, τα όρια ρυθμού ανά υποκείμενο και όποιον αναφέρει ένα εισιτήριο. Δείτε τη Συνεργασία — ταυτότητα, ιδιότητα μέλους και παρουσία για το μοντέλο ιδιότητας μέλους στο οποίο στηρίζεται.
Η σύνδεση είναι επίλυση ταυτότητας, όχι παραχώρηση πρόσβασης. Η ιδιότητα μέλους ελέγχεται ξανά σε κάθε συμβάν, οπότε μια σύνδεση που ανήκει σε κάποιον που έχει στο μεταξύ αφαιρεθεί καταλήγει σε άρνηση και όχι στα παλιά του προνόμια. Δύο διαδρομές καθιερώνουν μια σύνδεση: ένας βραχύβιος κωδικός μίας χρήσης που το μέλος πληκτρολογεί στη συνομιλία, ή μια αυτόματη αντιστοίχιση στο επαληθευμένο email του παρόχου — και η διαδρομή του email απαιτεί ακόμη ο αντιστοιχισμένος χρήστης να είναι ήδη μέλος, οπότε ένας άγνωστος του οποίου η διεύθυνση τυχαίνει να υπάρχει στον διακομιστή δεν συνδέεται με τίποτα.
Οι κωδικοί κρατούνται σκόπιμα στη μνήμη, με διάρκεια ζωής 15 λεπτά. Η αποθήκευση ενός θα δημιουργούσε μια διαρκή γραμμή σε σχήμα διαπιστευτηρίου για κάτι που προορίζεται να εξατμιστεί, και μια επανεκκίνηση του διακομιστή που ακυρώνει κάθε εκκρεμή κωδικό είναι η σωστή συμπεριφορά, όχι παλινδρόμηση — το μέλος πατά ξανά «σύνδεση».
Μια άρνηση απαντιέται μέσα στο νήμα του Slack όπου άνοιξε το μήνυμα, ως πραγματική απάντηση. Μια απάντηση σε νήμα επισημαίνει το μήνυμα στο οποίο απαντά, φτάνει στον έναν άνθρωπο που τη χρειάζεται και κρατά ακόμη το «δεν έχεις συνδεθεί» έξω από το ίδιο το κανάλι. Η ανάρτηση μηνύματος είναι επίσης η μία δυνατότητα που έχει κάθε πάροχος, οπότε η εξήγηση δεν εξαρτάται ποτέ από μια λειτουργία που η εφαρμογή μπορεί να μην φέρει.
Προέλευση και το πρόβλημα της ηχούς
Ενότητα με τίτλο «Προέλευση και το πρόβλημα της ηχούς»Μια γέφυρα που καθρεφτίζει και προς τις δύο κατευθύνσεις θα μπει σε βρόχο,
εκτός αν κάτι ξεχωρίζει τις δύο κατευθύνσεις. Κάθε μήνυμα που φέρνει μέσα η
γέφυρα σφραγίζεται με metadata['chat'] — πάροχο, ομάδα, συνομιλία, νήμα,
μήνυμα και αποστολέα. Ο εξερχόμενος καθρέφτης παραλείπει κάθε μήνυμα που φέρει
αυτή τη σφραγίδα.
Αυτός ο μοναδικός κανόνας είναι που κάνει ασφαλές το αμφίδρομο καθρέφτισμα: ένα ανθρώπινο μήνυμα που πληκτρολογείται στο Control Center προωθείται έξω στο συνδεδεμένο νήμα (με πρόθεμα το όνομα του συντάκτη), ενώ ένα μήνυμα που ήρθε από τη συνομιλία σταματά εκεί όπου μπήκε.
Αυτό που περνά προς τα έξω είναι σκόπιμα στενό. Η απάντηση του πράκτορα
προωθείται ως συνηθισμένο κείμενο συνομιλίας. Μια σύντομη σκέψη μπορεί να
εμφανιστεί στη γραμμή Thinking… της κάρτας. Η έξοδος των εργαλείων είναι ένας
τοίχος από diffs και παραμένει στο Control Center, όπου δείχνει επίσης μια
περικομμένη απάντηση.
Μια κάρτα αναφέρει την εργασία· το κείμενο παραμένει το μήνυμα
Ενότητα με τίτλο «Μια κάρτα αναφέρει την εργασία· το κείμενο παραμένει το μήνυμα»Όπου ο πάροχος τα αποδίδει, μια στροφή φέρει μία κάρτα εργασίας, που επεξεργάζεται επί τόπου για όσο διαρκεί η στροφή και κάθεται πάνω από την απάντηση που εξηγεί.
Η κάρτα είναι ένα ομαδοποιημένο σχέδιο, όχι μια λιωμένη παράγραφος. Το Slack
συνενώνει τα details και το output στην ίδια εργασία, οπότε τα details μιας
γραμμής στέλνονται μία φορά (η σκέψη στο Thinking…) και το output δεν
μεταδίδεται ποτέ σε ροή. Η προετοιμασία είναι μία γραμμή της οποίας ο τίτλος
αντικαθίσταται (Working on it…, Cloning …). Η συλλογιστική προσθέτει μια
γραμμή Thinking…. Κάθε εργαλείο έχει τη δική του γραμμή (Read lib/main.dart).
Η απάντηση είναι συνηθισμένο κείμενο κάτω από την κάρτα — η προβολή σχεδίου του
Slack τη διαβάζει από ένα μεταγενέστερο markdown append και όχι από ένα τμήμα
ανακατεμένο στις εργασίες. Τίποτα άλλο: καμία έξοδος εργαλείου και μόνο ένα
όρισμα εργαλείου από μια σύντομη λίστα επιτρεπομένων, γιατί τα ορίσματα ενός
άγνωστου εργαλείου μπορεί να είναι ολόκληρο το σώμα ενός αρχείου και μια γραμμή
χωρά μόνο μία γραμμή.
Η κάρτα καλύπτει επίσης την αναμονή πριν τη στροφή. Μια πρώτη αναφορά
δημιουργεί τη συνομιλία και η δημιουργία της κλωνοποιεί κάθε αποθετήριο στο οποίο
θα δουλέψει ο πράκτορας — που σε ένα πραγματικό αποθετήριο είναι λεπτά κατά τα
οποία δεν έχει ζητηθεί ακόμη τίποτα από τον πράκτορα και το νήμα μοιάζει σαν το
bot να αγνόησε το αίτημα. Έτσι, η κάρτα ανοίγει τη στιγμή που η αναφορά γίνεται
δεκτή (Working on it…) και μετά αυτή η γραμμή προετοιμασίας ενημερώνεται με τα
ίδια λόγια που δείχνει η εφαρμογή υπολογιστή — Cloning acme/widgets…,
Setting up Reviewer…, Starting the agent… — έπειτα μια γραμμή Thinking…
μόλις ο πράκτορας αρχίσει να συλλογίζεται, και μετά μια γραμμή ανά εργαλείο. Μία
κάρτα, ένα μήνυμα, από το «σε άκουσα» μέχρι την απάντηση ως συνηθισμένο κείμενο
από κάτω. Η προετοιμασία αναφέρεται μόνο όπου κάποιος στη συνομιλία την περιμένει:
μια συνομιλία που ετοιμάζεται στην εφαρμογή, ή μια εγκαταλελειμμένη που
συνεχίζεται στην εκκίνηση του διακομιστή, εφοδιάζεται χωρίς καμία κάρτα.
Φέρει το μόνο πράγμα που δεν μπορεί να δώσει η συνομιλία στον αναγνώστη: έναν
σύνδεσμο View in Control Center προς τη συνομιλία πίσω από την απάντηση. Τα
προϊόντα συνομιλίας δέχονται http(s) σε έναν σύνδεσμο και τίποτα άλλο, οπότε
το κουμπί δείχνει σε μια μικρή σελίδα που σερβίρει αυτός ο διακομιστής, η οποία
ανακατευθύνει τον περιηγητή στον σύνδεσμο control-center:// της εφαρμογής
υπολογιστή. Αυτή η σελίδα δεν διαβάζει τίποτα και δεν επιλύει τίποτα — τα ids
στο URL της αντηχούν σε έναν βαθύ σύνδεσμο και πουθενά αλλού — και ένας
διακομιστής χωρίς προσβάσιμο δημόσιο URL απλώς παράγει μια κάρτα χωρίς κουμπί
και όχι μια χαλασμένη.
Οι κάρτες είναι μια δυνατότητα όπως κάθε άλλη. Ένας πάροχος χωρίς αυτές
συμπεριφέρεται ακριβώς όπως πριν, μόνο με κείμενο, και ένας πάροχος που αρνείται
μια κάρτα τη στιγμή της κλήσης κρατά τη ροή του: η απάντηση υπερισχύει πάντα της
κάρτας που την περιγράφει. Όταν η ροή είναι εντελώς κλειστή, η ολοκληρωμένη
κάρτα ταξιδεύει με το ένα και μοναδικό αναρτημένο μήνυμα. Ένα καταχωρισμένο
εισιτήριο τυγχάνει της ίδιας μεταχείρισης — η επιβεβαίωση του /cc ticket είναι
μια ολοκληρωμένη κάρτα της οποίας ο λόγος ύπαρξης είναι ο σύνδεσμος προς το
εισιτήριο που μόλις δημιουργήθηκε.
Οι δυνατότητες διαπραγματεύονται και μετά θυμούνται
Ενότητα με τίτλο «Οι δυνατότητες διαπραγματεύονται και μετά θυμούνται»Τα προϊόντα συνομιλίας διαφέρουν ως προς το τι μπορούν να αποδώσουν, οπότε η γέφυρα είναι γραμμένη απέναντι στην πλουσιότερη επιφάνεια — μια απάντηση που μεγαλώνει ζωντανά μέσα σε ένα νήμα, μια παροδική κατάσταση «σκέφτεται…», ένα νήμα με τίτλο, μια εφήμερη απάντηση σε μια εντολή slash — και υποβαθμίζεται μία δυνατότητα τη φορά. Ένας πάροχος χωρίς τίποτα από αυτά δουλεύει ακόμη· οι απαντήσεις απλώς φτάνουν ως ένα μήνυμα.
Το να διαφημίζεις μια δυνατότητα δεν σημαίνει ότι την υπόσχεσαι. Οι απαντήσεις σε ροή του Slack χρειάζονται μια λειτουργία επί πληρωμή και το Slack αρνείται μόνο τη στιγμή της κλήσης. Μια άρνηση που χαρακτηρίζεται μόνιμη θυμάται για όλη τη ζωή της σύνδεσης: η γέφυρα σταματά να ρωτά και αναρτά ολόκληρες απαντήσεις από εκεί και πέρα, και οι ρυθμίσεις το λένε στα ίσια, γιατί στο «οι απαντήσεις μου σταμάτησαν να έρχονται σε ροή» πρέπει να μπορεί κανείς να απαντήσει χωρίς να διαβάσει ένα αρχείο καταγραφής. Οι κάρτες εργασίας απορρίπτονται με τον ίδιο τρόπο αν το Slack αρνηθεί μια.
Κάθε όριο ανήκει στον πάροχο και όχι στη γέφυρα: το ανώτατο όριο μηνύματος, το ανώτατο όριο τμήματος ροής και το αν μια ροή χρειάζεται άγκυρα νήματος δηλώνονται όλα από τον προσαρμογέα, και μια μακριά απάντηση χωρίζεται σε όριο παραγράφου, γραμμής ή λέξης και όχι στη μέση λέξης.
Μία γέφυρα, ένας προσαρμογέας ανά προϊόν
Ενότητα με τίτλο «Μία γέφυρα, ένας προσαρμογέας ανά προϊόν»Ό,τι έχει σχήμα προϊόντος ζει πίσω από μια θύρα. Ο γενικός πυρήνας ξέρει για
markdown, συνομιλίες, νήματα συνομιλίας και μέλη· δεν ξέρει τίποτα για φακέλους
του Slack, mrkdwn ή gateway intents. Τρία κομμάτια το κάνουν αυτό να δουλέψει:
- Ο προσαρμογέας ομαλοποιεί ένα προϊόν: το μέσο μεταφοράς του, τις κλήσεις
του στο API, τον κωδικοποιητή κειμένου του και τις ιδιομορφίες των φακέλων του.
Εκείνες του Slack είναι διδακτικές — μια αναφορά σε κανάλι φτάνει δύο
φορές (ως
app_mentionκαι ωςmessage) και οι περισσότεροι υποτύποι μηνυμάτων είναι διακοσμητικοί και όχι νέα αιτήματα. Και τα δύο διευθετούνται στον προσαρμογέα, οπότε ο πυρήνας δεν μαθαίνει ποτέ ότι το Slack παραδίδει διπλά. - Ο περιγραφέας είναι το δημόσιο σχήμα του παρόχου: ποια διαπιστευτήρια χρειάζεται, ποιες είναι οι μορφές τους, ποια URL βοηθούν έναν χρήστη να τα βρει, τι μπορεί να κάνει και αν η εφαρμογή του μπορεί να δημιουργηθεί ή να επεξεργαστεί από εδώ. Η κάρτα ρυθμίσεων, ο διάλογος σύνδεσης και η επικύρωση ορισμάτων παράγονται όλα από αυτόν — ο πελάτης στέλνει πίσω έναν πάροχο και έναν χάρτη με κλειδιά τα αναγνωριστικά των πεδίων.
- Το plugin είναι η σύνθεση στην πλευρά του διακομιστή: πώς τα διαπιστευτήρια γίνονται επαληθευμένη σύνδεση, πώς χτίζεται ένας προσαρμογέας και πώς διαχειρίζεται η εφαρμογή στην πλευρά του παρόχου.
Άρα η προσθήκη ενός προϊόντος είναι μία τιμή enum, ένας προσαρμογέας και ένα plugin. Καμία νέα πράξη RPC, καμία αλλαγή σχήματος, καμία αλλαγή πελάτη — και ο πελάτης μένει ειλικρινής, γιατί ένα πεδίο που δεν έχει ακούσει ποτέ αποδίδεται ακόμη με την ετικέτα που έδωσε ο διακομιστής.
Δύο λεπτομέρειες κρατούν την αφαίρεση από το να διαρρεύσει προς τα πάνω. Τα βήματα διαχείρισης της εφαρμογής για τα οποία ένας πάροχος δεν έχει API (δημιουργία token, εγκατάσταση της εφαρμογής, επανεγκατάσταση μετά από αλλαγή δικαιωμάτων) επιστρέφονται ως ονομασμένα βήματα με δικούς τους συνδέσμους, ώστε η οθόνη ολοκλήρωσης της ρύθμισης να τα δείχνει χωρίς να ξέρει ποιος πάροχος είναι. Και κάθε οδηγία που γράφει η γέφυρα ονομάζει τον πάροχο και την εντολή που χρησιμοποιεί όντως η εφαρμογή, ώστε μια μετονομασμένη εντολή ή ένας δεύτερος πάροχος να διαβάζεται σωστά χωρίς νέα συμβολοσειρά.
Πού ζουν τα διαπιστευτήρια
Ενότητα με τίτλο «Πού ζουν τα διαπιστευτήρια»Τα token συνομιλίας ενός χώρου εργασίας βρίσκονται στον δικό του κατάλογο,
δίπλα στη βάση δεδομένων του — ως απλό JSON στο
<dataDir>/<workspaceId>/chat_credentials/<provider>.json, όχι στη βάση
δεδομένων και σκόπιμα όχι στο keychain του λειτουργικού συστήματος. Δύο
συνέπειες χάνονται εύκολα αργότερα: η διαγραφή ενός χώρου εργασίας αποσυνδέει
τον κατάλογο και τα token του φεύγουν μαζί του, και η εξαγωγή ή η δημιουργία
αντιγράφου ασφαλείας ενός χώρου εργασίας αντιγράφει το workspace.db, οπότε
ένας χώρος εργασίας που παραδίδεται σε κάποιον άλλο δεν κουβαλά ζωντανά token bot
μέσα του. Το αρχείο κληρονομεί το όριο εμπιστοσύνης του συστήματος αρχείων του
κεντρικού υπολογιστή του διακομιστή — ό,τι έχει πρόσβαση ανάγνωσης στον κατάλογο
δεδομένων μπορεί να διαβάσει ένα token bot, που είναι το ίδιο όριο πίσω από το
οποίο βρίσκονται οι βάσεις δεδομένων.
Ένα αρχείο ανά πάροχο, γραμμένο ατομικά και με δικαιώματα μόνο του ιδιοκτήτη: μια ανακληθείσα εφαρμογή διαγράφεται αποσυνδέοντας ένα αρχείο, και ένα κατεστραμμένο αρχείο κοστίζει έναν πάροχο και όχι όλους. Τα διαπιστευτήρια ταξιδεύουν προς τα μέσα με τη λειτουργία σύνδεσης και δεν βγαίνουν ποτέ ξανά έξω — οι αναγνώσεις κατάστασης απαντούν μόνο με μεταδεδομένα σύνδεσης.
Τι δεν προσφέρεται σκόπιμα
Ενότητα με τίτλο «Τι δεν προσφέρεται σκόπιμα»- Δομικές ρυθμίσεις της εφαρμογής. Το μέσο μεταφοράς, τα scopes και οι συνδρομές σε συμβάντα επιβάλλονται, δεν εκτίθενται. Μια εφαρμογή που μπορεί να ρυθμιστεί σε σιωπή από μια οθόνη ρυθμίσεων είναι αίτημα υποστήριξης, όχι λειτουργία.
- Συνομιλία και εντολές slash. Η επιφάνεια του Slack είναι μηνύματα, απαντήσεις σε νήματα και εντολές slash.
- Μια δεύτερη πηγή αλήθειας. Η συνομιλία δεν είναι μέρος όπου αποθηκεύεται εργασία. Το νήμα του Slack είναι ένας χώρος, η απάντηση είναι μια μεταγραφή, το εισιτήριο είναι ένα εισιτήριο — όλα τους στον χώρο εργασίας, προσβάσιμα από κάθε πελάτη.
Δείτε επίσης
Ενότητα με τίτλο «Δείτε επίσης»- Συνεργασία — ταυτότητα, ιδιότητα μέλους και παρουσία: τα υποκείμενα και οι ρόλοι μέσα από τους οποίους επιλύει η γέφυρα
- Χώροι εργασίας και απομόνωση: γιατί οι σύνδεσμοι και τα διαπιστευτήρια είναι ανά χώρο εργασίας
- Το μοντέλο πρακτόρων: τι ξυπνά όταν φτάνει μια αναφορά
- Εισιτήρια και ανάθεση: τι καταχωρεί το
/cc ticket - Αρχιτεκτονική: πού κάθεται η γέφυρα ανάμεσα στον διακομιστή και τους πελάτες
- Συνδέστε το Slack στον χώρο εργασίας σας
- Ρύθμιση ενσωμάτωσης Slack
- Σύνδεση λογαριασμού Slack
- Προσαρμογή του chat bot
- Συνομιλίες PR: οι ίδιες τρεις αποφάσεις, φτιαγμένες για έναν κεντρικό υπολογιστή κώδικα