2015 թվականին մոտ 18,1 միլիարդ տոննա ապրանք՝ մոտ 19,2 տրիլիոն դոլար արժողությամբ, տեղափոխվել է U.S. Ազգային տրանսպորտային ցանց. Այս թիվը կանխատեսվում է մինչև 27 միլիարդ տոննա մինչև 2045 թվականը: KeepTruckin-ում մենք ստեղծել ենք բեռների տեսանելիության հարթակ՝ բրոքերներին, առաքողներին և այլ հաճախորդներին իրական ժամանակում տեսանելի դարձնելու իրենց բեռները: Այս հոդվածում մենք քննարկում ենք մեր մտքի գործընթացը, երբ մենք լուծում ենք այս հարթակի տարբեր բաղադրիչների նախագծման տեխնիկական մարտահրավերները (դրանք ներառում են API-ի դիզայնը, ETL խողովակաշարը, մուտքի վերահսկման մոդելը, աշխատանքային հոսքի համակարգը և այլն):

Առաջին բաները

Բեռնափոխադրումների տեսանելիության հարթակը նախագծելիս մենք պետք է հաշվի առնեինք բրոքերների և փոխադրողների պահանջները, ինչպես նաև լրացուցիչ պահանջներ, որոնք մենք ինքներս ավելացրեցինք:

Առաջնային սպառողները և նրանց պահանջները

Բեռնափոխադրումների տեսանելիության հարթակը հիմնականում ուղղված է առաքման կողմը ներկայացնող յուրաքանչյուրին. սա ներառում է բրոքերներին, առաքողներին և հարթակից օգտվող ցանկացած այլ անձի: Բեռնափոխադրումների ոլորտում բեռնափոխադրողն այն կողմն է, ով ցանկանում է ապրանքներ տեղափոխել, իսկ բրոքերը միջին կողմն է առաքողի և փոխադրողների միջև: Այս հիմնական օգտվողների ակնկալիքները մեր տեսանելիության ծառայության համար ներառում են.

  • API-ներ, որոնք հեշտ է հասկանալ և սպառել
  • Բեռը փոխադրող մեքենային կապելու, բեռը մեքենա փոխադրելու սխալ կապերը հայտնաբերելու և նշելու ունակություն
  • API՝ բեռ տեղափոխող մեքենայի գտնվելու վայրը քաշելու համար
  • Հրում մեխանիզմ՝ իրենց կազմաձևված վերջնակետերում տեղաբաշխումներ ստանալու համար
  • Նվազագույն հեղինակային ծախսեր

Փոխադրողները և նրանց պահանջները

Փոխադրողները ընկերություններ են, որոնք ունեն տրանսպորտային միջոցների նավատորմ և ապահովում են փոխադրումներ: Մեր բեռնափոխադրումների տեսանելիության ծառայությունը հասանելի է փոխադրողների տվյալներին, և, հետևաբար, մենք պետք է հաշվի առնենք նրանց պահանջները, որոնք կենտրոնանում են տվյալների անվտանգության շուրջ. դրանք ներառում են.

  • Լրիվ տեսանելիություն և վերահսկողություն, թե ովքեր ունեն իրենց տվյալների մուտքի թույլտվություն
  • Լրիվ տեսանելիություն, թե ով է մուտք գործում իրենց տվյալներին և որքան հաճախ

KeepTruckin-ի պահանջները

Մեր լրացուցիչ մտահոգությունները մեր ծառայության նախագծման մեջ ներառում էին.

  • Գնահատման սահմանափակում՝ չարաշահումը և համակարգի ծանրաբեռնվածությունը կանխելու համար
  • Աջակցող թիմի համար անտեսելու թույլտվությունը
  • Պատմական հետագծման տվյալների պահպանում՝ վճարումների և բիզնեսի օգտագործման այլ դեպքերի սպասարկման համար

Հաջորդը` Գործոնները և մեր մոտեցումը

Բրոքերի աշխատանքային հոսք

Որպես տեսանելիության սպասարկման մեր հարթակի մաս՝ մենք ցուցադրեցինք ՌԵՍՏ API-ների մի շարք: KeepTruckin-ն ունի հավելվածների շուկա՝ մեր արտադրանքի հետ ինտեգրվելու համար: Բրոքերը նախ պետք է մշակի և հրապարակի հավելված մեր շուկայում և կարգավորի բոլոր թույլտվությունները՝ նախքան այս API-ներից օգտվելը:

Բրոքերը պետք է բաժանորդագրվի մեքենային` դրան հետևելու համար: Բաժանորդագրությունները կարելի է կառավարել՝ օգտագործելով POST և PUT / subscribe API-ները: Ե՛վ ձգման, և՛ մղման մեխանիզմներն աշխատում են միայն ակտիվ բաժանորդագրության ժամանակային պատուհանում:

Հավաքածուն նաև բաղկացած է API-ից, որն օգնում է բրոքերներին որոշել այն մեքենան, որն, ամենայն հավանականությամբ, կապված է բեռի հետ, երբ տրվում է հետաքրքրության վայր, օրինակ՝ բեռը վերցնելու կամ իջեցնելու վայրը: Սրանք ծառայում են որպես գործիքներ՝ հաստատելու էլեկտրոնային գրանցման սարքի (ELD) ճշգրտությունը կամ այլ հետագծման ID-ն, որը կարող է բրոքերն ստացել իրենց բեռների համեմատ՝ անցանց կամ այլ ալիքներով:

Բրոքերների և նավատորմի միջև թույլտվությունների կառավարում

Առաջին մարտահրավեր. Գործընկերների և թույլտվությունների համընկնումը

Առաջին մարտահրավերը, որին մենք հանդիպեցինք բրոքեր մուտք գործելիս, գործընկերների համընկնումն էր: Մենք պարզեցինք, որ մեր սեփական օպերատորի գործընկերներից շատերն արդեն համագործակցում էին բրոքերի հետ: Երբ մենք գնացինք թույլտվություններ ստեղծելու նավատորմի համար, որոնք և՛ KeepTruckin-ի, և՛ բրոքերի ընդհանուր գործընկերներն էին, մենք պարզեցինք, որ բրոքերն արդեն թույլտվություն ուներ հետևելու այս նավատորմի մեքենաներին, հավանաբար օգտագործելով տեսանելիության միջնորդ մատակարար: Սա նշանակում էր, որ մենք կարող էինք կիրառել նույն թույլտվությունների տրամադրումը մեր համակարգում՝ մուտքի ժամանակ: Խնդիրը KeepTruckin-ի և բրոքերի միջև փոխադարձ գործընկերներ գտնելն էր՝ առանց որևէ կողմի հաճախորդների ամբողջ բազայի կամ նույնիսկ հաճախորդների բազայի չափի բացահայտման:

Խնդիրը լուծելու համար մենք միջնորդին խնդրեցինք կիսել Տրանսպորտի դեպարտամենտի (DOT) համարների (սրանք բոլոր գրանցված առևտրային մեքենաներին տրված թվեր) իրենց բոլոր գործընկեր նավատորմերի հեշերի ցանկը: Ցանկը ընդհատված էր անհայտ քանակի պատահական թվերի հեշերով՝ բրոքերի հաճախորդների բազայի չափը բաց թողնելու ռիսկը վերացնելու համար:

Ընտրված հեշ ֆունկցիան ստեղծեց միակողմանի հեշ՝ վերացնելով հեշերի հաշվին DOT թվերի վերահաշվարկի հնարավորությունը: Այնուհետև մենք այս ցուցակը համեմատեցինք KeepTruckin-ի հաճախորդների նավատորմի DOT թվերի հետ ստեղծված նմանատիպ ցուցակի հետ: Բրոքերին թույլտվություն է տրվել հետևելու բեռներին համընկնող նավատորմերին պատկանող ցանկացած տրանսպորտային միջոցի վրա:

Երկրորդ մարտահրավեր. նավատորմերին տալ իրենց տվյալների հասանելիության ամբողջական վերահսկողություն

Մենք ցանկանում էինք թույլտվությունների կառավարման ամբողջական վերահսկողությունը տրամադրել հենց նավատորմերին: Դա հնարավոր դարձնելու համար մենք խնդրեցինք բրոքերներին ստեղծել իրենց տեսանելիության հավելվածները KeepTruckin App Marketplace-ում:

Նավատորմի կառավարիչը կարող է բրոքերին թույլտվություն տրամադրել հետևելու իրենց նավատորմի ցանկացած տրանսպորտային միջոցի բեռներին՝ տեղադրելով բրոքերի հավելվածը, որը հասանելի է KeepTruckin App Marketplace-ում (Նկար 3): Հավելվածը հեռացնելու դեպքում թույլտվությունը չեղարկվում է:

Նվազագույնի հասցնել OAuth 2.0 բրոքերների գերավճարը

Մեր բեռնափոխադրումների տեսանելիության API-ները թույլտվության համար օգտագործում են OAuth 2.0: Սովորաբար, գործընկերը, որը հավելված է մշակում KeepTruckin App Marketplace-ում, պետք է պահի և կառավարի տարբեր վիճակներ (հավաստագրման դրամաշնորհներ, մուտքի նշաններ, թարմացման նշաններ) յուրաքանչյուր նավատորմի դեմ, որը տեղադրում է իրենց հավելվածը: Բեռնափոխադրումների հետևման համատեքստում բրոքերները ցանկություն են հայտնել նվազագույնի հասցնել այն պետությունների թիվը, որոնք նրանց անհրաժեշտ են՝ բեռնափոխադրումների տեսանելիության API-ները օգտագործելու համար: Մենք պետք է կրճատեինք այն պետությունների թիվը, որոնք պետք է կառավարեին բրոքերին՝ միաժամանակ պահպանելով API-ները OAuth 2.0-ի հետևում անվտանգության և հետևողականության համար:

Դրան հասնելու համար մենք ստեղծում ենք պրոքսի նավատորմ յուրաքանչյուր բրոքերի համար, երբ միանում ենք:

Այժմ բրոքերներին անհրաժեշտ է միայն հիշել և կառավարել ինքնության հետ կապված պետությունները մեկ վստահված նավատորմի համար (Նկար 4): Թույլտվությունների կառավարումը (ինչպես նկարագրված է նախորդ բաժնում) հոգ է տանում բրոքերի հատուկ վստահված նավատորմի և բոլոր իրական նավատորմի միջև քարտեզագրման մասին: Բրոքերն այժմ կարող է զանգահարել API-ներ՝ օգտագործելով վստահված նավատորմի համար ստեղծված մուտքի նշանը և մուտք ունենալ դեպի դրան քարտեզագրված բոլոր իրական նավատորմերը:

Տրանսպորտային միջոցը բեռի հետ կապելը

Երբ բրոքերները հետևում են մեքենայի բեռին, երբեմն նրանց ստացած էլեկտրոնային անտառահատման սարքի ID-ն (ELD ID) կամ որևէ այլ հետագծման ID-ն, որը նրանք կարող են ստանալ բեռի դիմաց, սխալ են: Մեր տեսանելիության ծառայության մի մասն էր բրոքերների համար մեխանիզմ տրամադրել՝ ստուգելու, որ ELD ID-ն (կամ որևէ այլ հետագծման ID), որը նրանք ստանում են ծանրաբեռնվածության դեպքում, ճշգրիտ է: Այդ նպատակով մենք ստեղծել ենք association API-ի երկու տարբերակ: Օգտագործելով ասոցիացիայի API-ը, բրոքերը կարող է տրամադրել նավատորմի նույնացուցիչը և հետաքրքրության վայրը, օրինակ՝ բեռի տեղափոխման վայրը, և տեսանելիություն ձեռք բերել, թե որ նավատորմի մեքենաներից մեկը, ամենայն հավանականությամբ, վերցրել է այդ բեռը: Եթե ​​պոտենցիալ համընկնում չկա, նրանք կարող են նշել հետագծման ID-ն որպես վատ:

Մոտավորության վրա հիմնված ասոցիացիա (v1)

Մենք սկսել ենք API-ի ավելի պարզ տարբերակից, որտեղ մենք հաշվարկում ենք նավատորմի բոլոր մեքենաների հեռավորությունները մինչև տվյալ հետաքրքրության կետը և դրանք վերադարձնում ենք՝ ըստ տվյալ վայրի մոտակայության:

Բազմաթիվ մեքենաներով մեծ նավատորմերի համար էջադրման ընթացքում հետևողականությունը դառնում է անհանգստություն՝ հաշվի առնելով, որ մեր թվարկած մեքենաները կարող են անընդհատ շարժման մեջ լինել: Եթե ​​մենք վերահաշվարկենք հեռավորությունները, երբ բեռնվում է յուրաքանչյուր նոր էջ, մենք վտանգի ենք ենթարկում ամբողջությամբ բաց թողնել որոշ մեքենաներ կամ կրկնել որոշ մեքենաներ: Հետևողականությունը պահպանելու համար, երբ API-ն կանչվում է, մենք հաշվարկում և պահում ենք բոլոր մեքենաների հեռավորությունները տվյալ վայրից 300 վայրկյան: Բոլոր հաջորդական էջերը սպասարկվում են քեշից: Քեշի բանալին ստացվում է բրոքերի ինքնությունից, նավատորմի և տվյալ վայրից:

Մեքենայի ընթացիկ գտնվելու մասին տեղեկատվությունը կարդացվում է քեշից: API-ի պատասխանը կարող է ներառել նաև տրանսպորտային միջոցների պատմական վայրերը՝ կախված բրոքերի հատուկ կոնֆիգուրացիայից: Այս տեղեկատվությունը պահվում և կարդացվում է DynamoDB-ում:

Բազմաչափ չափանիշների վրա հիմնված ասոցիացիա (v2)

v1-ի խնդիրն այն է, որ այն չի օգտագործում տարբեր այլ ազդանշաններ, որոնք ավելի կարևոր էին թվում բեռը մեքենային կապելու համար: Դրանք ներառում են այն ուղղությունը, որով շարժվել է մեքենան՝ համեմատած հետաքրքրության վայրի հետ, կամ իրական ETA-ի և բրոքերի կողմից սահմանված ETA-ի միջև անհամապատասխանությունը:

v2-ում մենք դիտարկում ենք երեք տարբեր գործոններ և տարբեր կշիռներ ենք նշանակում՝ բեռ-մեքենա կապը որոշելու համար (Նկար 5): Մենք նաև վերադարձնում ենք բացահայտ հավանականության միավորը ցուցակի յուրաքանչյուր մեքենայի հետ՝ հնարավորություն տալով բրոքերներին ավելի տեղեկացված որոշումներ կայացնել:

  • Մեքենայի գտնվելու վայրը՝ ըստ ժամանման գնահատված ժամանակի (ETA). Բրոքերն այս API-ն զանգահարելիս փոխանցում է ETA և հետաքրքրություն ներկայացնող վայրը: Մենք վերցնում ենք մեքենայի ներկայիս գտնվելու վայրը և հաշվարկում ETA-ն տվյալ հետաքրքրության վայրում: Այս հաշվարկը կատարվում է մեր Հետևել և հետագծել ծառայության կողմից: Միավորը հաշվարկվում է՝ անցած ETA-ն համապատասխանեցնելով հաշվարկված ETA-ին:
  • Սպասարկման ժամեր (HOS) ցիկլը մնացել է. Մենք նայում ենք մեքենայի վարորդի մնացած HOS-ին, համեմատում այն ​​նպատակակետի ETA-ի հետ և հաշվարկում համապատասխան միավորը:
  • Մեքենայի ուղղությունը. Մենք նայում ենք անցյալի N թվին և համեմատում ենք մեքենայի առանցքակալը յուրաքանչյուր վայրում այդ դիրքի և վերջնական դիրքի միջև անկյան հետ: Հաշիվը կախված է միավորների ընդհանուր քանակից, որոնց համար անկյունները համընկնում են:

API-ի տոկոսադրույքի սահմանափակում

Մեր ասոցիացիայի API-ի թանկ բնույթը պահանջում էր մեխանիզմ՝ մուտքային հարցումները կարգավորելու համար: Մենք դրան հասանք՝ օգտագործելով Bottleneck՝ KeepTruckin-ի ներքին սակագների սահմանափակման ծառայությունը, որը մշակվել է Go-ում:

Տեղորոշման թարմացում Հրում Webhooks-ի միջոցով

Բրոքերը կարող է ընտրել բաժանորդագրված մեքենայի տեղադրության թարմացումները իրենց կազմաձևված վերջնակետում: Ընտրանքն իրականացվում է հավելվածի մակարդակի կոնֆիգուրացիայի միջոցով:

Այս push use case-ը սպասարկվել է KeepTruckin-ի Webhook Dispatcher Service-ի միջոցով (որը սպառում է նոր հաղորդագրությունները Kafka-ից և գրում դրանք արտաքին համակարգերում գործընկերների կողմից կազմաձևված REST վերջնակետերի միջոցով) և մեր Webhook Pusher Service: em>,մշակված հատուկ այս օգտագործման դեպքի համար (Նկար 6):

Երբ բոլոր կոնֆիգուրացիաները ճիշտ կարգավորված են, և բրոքերը նոր բաժանորդագրություն է ստեղծում մեքենային հետևելու համար, վեբ-կապիկի հոսքը գործարկվում է: Կախված բաժանորդագրության մեկնարկի ժամից՝ համապատասխան մանրամասներով հաղորդագրությունը կա՛մ անմիջապես հերթագրվում է Amazon SQS-ում, կա՛մ Backburner հերթում տեղադրվում է այնպիսի ուշացումով, որ երբ հասնում է բաժանորդագրության մեկնարկի ժամը, հաղորդագրությունը հերթագրվում է SQS-ում: .

Webhook Pusher Service-ը շարունակում է SQS հարցումները նոր հաղորդագրությունների համար: Հենց որ նա գտնում է նոր հաղորդագրություն, նա հարցնում է մեքենայի վերջին գտնվելու վայրի քեշը և հաղորդագրություն է ուղարկում Կաֆկային բաժանորդագրված մեքենայի մասին տարբեր մանրամասներով, ներառյալ նրա ներկայիս գտնվելու վայրը: Այն նաև այնուհետև նոր հաղորդագրություն է գրում SQS-ում՝ կազմաձևված ուշացումից հետո: Webhook դիսպետչեր ծառայությունը սպառում է Kafka-ով գրված հաղորդագրությունը և ուղարկում տեղեկատվությունը բրոքերին՝ իր կազմաձևված REST վերջնակետով: Webhook Pusher Service-ը ուշացումով ընդունում է այն հաղորդագրությունը, որն ավելացվել է SQS-ին, և հոսքը կրկնվում է ինքն իրեն՝ տեղանքի թարմացված մանրամասներով կանոնավոր ընդմիջումներով բրոքերի համակարգ մտցնելով: Շրջանակն ավարտվում է, երբ ավարտվում է բաժանորդագրության ժամկետը, կամ բրոքերի թույլտվությունը չեղյալ է հայտարարվում:

Գործունեության վահանակ նավատորմի ղեկավարների համար

Մենք նավատորմի կառավարիչներին տեսանելի դարձրինք, թե ով է մուտք գործել իրենց տվյալներ և որքան հաճախ՝ ներկառուցված հավելվածների շուկայում հասանելի գործունեության վահանակի միջոցով (Նկար 7):

Այստեղ խնդիրն այն էր, որ յուրաքանչյուր մեքենայի հետագծման իրադարձության մասին տեղեկատվությունը պահպանվի, որը կարող է շատ արագ աճել: Տվյալները կտրատելու և կտրատելու հեշտությունը հարաբերական տվյալների բազան դարձրեց գայթակղիչ լուծում: Բայց աղյուսակի չափը և չօգտագործված հին չափորոշիչները մաքրելու գործընթացներ ավելացնելու անհրաժեշտությունը մեզ ստիպեցին այլընտրանքներ դիտարկել:

Ռեդիս-ում տեղավորվեցինք երկու պատճառով. Առաջինը կարդալու և գրելու արագությունն էր: Գրելու արագությունը կարևոր էր, քանի որ մենք լրացուցիչ կոդ էինք միացնում՝ գոյություն ունեցող API-ներում չափումներ գրանցելու համար և չէինք ցանկանում զգալի ուշացում ավելացնել: Մենք նաև քննարկեցինք հաղորդագրությունների հերթ օգտագործելը և իրադարձությունները ասինխրոն կերպով մշակելը, բայց մենք հրաժարվեցինք այս գաղափարից՝ հօգուտ Redis-ին համաժամանակյա գրելու, վերջինս ավելի պարզ մոտեցում է՝ ավելի քիչ ավելացված սպասարկման ծախսերով: Redis-ի ընտրության մեր երկրորդ պատճառը TTL-ներ սահմանելու հնարավորությունն էր՝ դրան գրելիս: Սա նշանակում էր ավելի քիչ ծախսեր հին չափումների մաքրման համար:

Մեր վերջնական լուծումը բաղկացած էր երեք տեսակավորված հավաքածուներից Redis-ում: Բազմաթիվ հավաքածուներ եղել են տվյալների շտեմարանի ընտրության հետևանք, որն աջակցում է միայն բանալի-արժեքներ և տվյալների պարզ կառուցվածքներ, այլ ոչ թե դրանց վրա ինդեքսներով սյունակներ: Մենք հայտնաբերեցինք այն դաշտերը, որոնց վրա ցանկանում էինք թույլ տալ օգտվողներին զտել: Յուրաքանչյուրի համար մենք ավելացրել ենք նոր տեսակավորված հավաքածու, որտեղ scoreն այն արժեքն է, որի վրա պետք է զտել: Յուրաքանչյուր հետագծման իրադարձության համար մի քանի հավաքածուների գրություններն օպտիմալացնելու համար մենք օգտագործեցինք Redis գործարքները: Օգտագործելով այս մոտեցումը՝ 100 տրանսպորտային միջոցներին հետևելու հարցումը տեսավ 20 մս-ից պակաս ավելացված ուշացում՝ հաշվի առնելով նոր զետեղված կոդը՝ չափումների ֆիքսման համար: Կոմպլեկտի առանձին տարրերի մակարդակով TTL-ները կառավարելու համար մենք օգտագործեցինք այնպիսի մոտեցում, որը նման է Redis-ի պասիվ ժամկետանց մոտեցմանը. այսինքն՝ ամեն անգամ, երբ մի շարք մուտք են գործում, մենք դրանից հանում ենք N օրից հին բոլոր տարրերը՝ օգտագործելով Redis-ի ZREMRANGEBYSCORE հրամանը (դա հնարավոր է միայն այն պատճառով, որ բոլոր միավորները հավասար են կամ բխում են ժամանակի դրոշմներից):

Չափանիշներ բիզնեսի հետախուզության (BI) և վճարումների համար

Պահանջներից մեկն այն էր, որ բիզնեսին թույլ տրվի վերահսկել և վերլուծել բրոքերների օգտագործման օրինաչափությունները և դրանք վճարել ըստ օգտագործման:

Մենք չկարողացանք մատուցել այս վերլուծական օգտագործման դեպքերը մեր հարաբերական տվյալների բազայից, քանի որ մենք այնտեղ չենք պահում հետևելու անհատական ​​իրադարձությունները: Ավելին, մենք չէինք ցանկանում ծանրաբեռնել մեր առաջնային հարաբերական տվյալների բազան ներքին վերլուծական օգտագործման լրացուցիչ դեպքերով: Redis-ում պահվող հետագծման իրադարձությունները, որոնք սնուցում են վերը քննարկված գործողությունների վահանակը, պահվում են միայն ժամանակավորապես և ժամկետը լրանում է մեկ ամիս հետո: Այս իրադարձությունները քեշում ավելի երկար ժամանակ պահելը զգալիորեն կբարձրացնի քեշի օգտագործումը՝ ազդելով և՛ կատարողականի, և՛ վճարումների վրա, և Redis-ը կդարձնի ոչ պիտանի այս օգտագործման դեպքում:

Հետևաբար, մենք ստեղծեցինք տվյալների խողովակաշար, որտեղ API-ի յուրաքանչյուր հարված Կաֆկայում տեղադրում է համապատասխան չափումներ պարունակող հաղորդագրություն: Հաղորդագրությունն այնուհետև մշակվում է ասինխրոն կերպով PySpark հոսքային աշխատանքների միջոցով՝ ելքը պահելով AWS S3-ում։ Այնուհետև S3-ից ստացված տվյալները սպառվում են ETL աշխատատեղերի կողմից, որոնք տվյալները փոխակերպում են ցանկալի ձևաչափերի և տեղափոխում դրանք մեր տվյալների լիճ: Ի վերջո, մենք օգտագործում ենք Redash-ը՝ տվյալների աղբյուրին միանալու և համապատասխան հաշվետվություններն ու վահանակները սպասարկելու համար:

Եզրափակել. Մեր ճարտարապետության դիագրամը

Այս հարթակի բաղադրիչների նախագծման հետ կապված մեր քննարկումներն ամփոփված են ստորև ներկայացված դիագրամում: Նկար 8-ը պատկերում է Freight Visibility հարթակի ընդհանուր ճարտարապետական ​​դիագրամը:

Բեռնափոխադրումների տեսանելիության պլատֆորմը հաջողության է հասել իր առաքելության մեջ՝ բրոքերներին, առաքիչներին և այլ հաճախորդներին իրական ժամանակում տեսանելի դարձնելու իրենց բեռները՝ միաժամանակ բավարարելով բոլոր շահագրգիռ կողմերի պահանջները:

Վերջին, բայց երբեք նվազագույնը. ներդրումներ

Շնորհակալություն բոլորին, ովքեր օգնեցին մատուցել սա.

Մենք ուրախ ենք լինել Medium համայնքի մի մասը: Մենք նախատեսում ենք տեղադրել բազմաթիվ նոր պատմություններ, ուստի անպայման հետևեք մեր հրապարակմանը: Իմացեք ավելին մեր ինժեներական թիմի մասին այստեղ:Ցանկանու՞մ եք միանալ KeepTruckin-ին: Մենք աշխատում ենք: