Rama Rahmanda
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    ## BE - TH Book Source Epic: https://ruanggguru.atlassian.net/browse/RBGR-6610 Implementation: - Ops provide 2 google sheets to manage the mapping from book source to question. - BE - Create new endpoint to get book source give question serial - why do we need the mapping? - requested by TH team, due to requirement by their law to show citation source of a problem set that we show - where will it be shown? - will be shown as book source in question details - show source description only. - how big the data? - around 10k, based on TH team ### related fields 2 tables - question_serial - book_source - source_type - is an enum, 4 possible values - exam book - textbook - official exam - mock exam - book title - book description Implementation details: - Create worker to pull book source and question mapping to book source, the worker will pulling the data once a day - [book source](https://docs.google.com/spreadsheets/d/10vnrvvPsMZ2TofxD7PjMWcDCwiu3SkDJ0Hqc2ls8yL4/edit#gid=570812937) - [question mapping](https://docs.google.com/spreadsheets/d/1zQP142rX-EK0DphwTSuZygXvBqGZmgE34Q3EJdZhol4/edit#gid=280677941) ### how to fetch data (**choosen option: 2**) - option1: add fields to existing endpoint (`/question_detail`) - pros: - reuse endpoint, not too many - single endpoint call from FE - cons: - bloated endpoint - added complexity - added load (need to query new stuff) - implementation: - worker will periodically/on request fetch data from excel - option2 (SELECTED): Create new endpoint to get book source given question serial - GET /question_detail/book_source/{question_serial} - pros: - we won't disrupt existing endpoint - won't add latency/load - cons: - more endpoint to maintain - implementation: - in RDA - fetch data from DB - `SELECT * from book_questions bq left join books b on b.serial = bq.book_serial where question_serial = "$question_serial"` - tables: - 1 table for books - 1 table for m-n relation ### how Ops will manipulate the data - option 1 - data entry came from gsheet - 3 columns???? - book serial (ISBN?) - question_serial - action, enum: - CREATE - UPDATE - DELETE - saved on DB, triggered daily or by extension - service get whole table, data filtering and processing done in service - https://gitlab.com/ruangguru/source/-/blob/master/video-transfer/main.go - user will get error feedback via `Error message` column, error is shown per row ## bugs from last sprint - wrong sitemap path - issue on chatbot ## RBGR-6211 Roboguru RN Banner and Sorting ### [BE] RBGR-6318 Adjust thread list filter to add sortBy createdAt with answerable Thread - add new sorting param called `CreatedAtGami` with value `ASC` and `DESC` - new where param in mysql db ``` q.SortBy = "forum_thread.created_at" db = db.Where("(forum_thread.answer_count < 2") db = db.Where("forum_thread.discussion_by_expert_counter < 1") ``` - new where param in es db ``` db = db.Must(elastic.NewRangeQuery(rgForumThreadPrefix + "answer_count").Lt(2)) db = db.Must(elastic.NewRangeQuery(rgForumThreadPrefix + "discussion_by_expert_counter").Lt(1)) ``` ### [BE] RBGR-6322 Adjust modular component to show new banner (new sheet) - Add new sheet (by ops or product) - Add new modular component - new id in endpoint modular component. sample ``` curl 'https://roboguru.sirogu.com/api/v3/roboguru-discovery/modular-components' \ -H 'authority: roboguru.sirogu.com' \ -H 'accept: application/json' \ -H 'accept-language: en,id-ID;q=0.9,id;q=0.8,en-US;q=0.7' \ -H 'cache-control: no-cache' \ -H 'content-type: application/json' \ -H 'cookie: GCP_IAP_UID=104601912716404164306; _ga_2FWJ6H3WGT=GS1.1.1628577877.24.0.1628577877.60; _ga_Q1ZSM4QR0X=GS1.1.1631633114.2.1.1631633114.0; _hjid=12c1afdc-e7be-4993-80a5-1d8ab676da97; _hjSessionUser_2680642=eyJpZCI6IjRjMGRjYzM2LTViMjYtNTRmNS05MzA2LWU2YmIwYTY4MTkwMCIsImNyZWF0ZWQiOjE2MzcyMjgyNzM0MDcsImV4aXN0aW5nIjp0cnVlfQ==; _hjSessionUser_2674152=eyJpZCI6IjdlMzhlMGExLTM1YjMtNWQ3NS1iZDk2LTk0MDYyM2FjMDdlMSIsImNyZWF0ZWQiOjE2Mzc1Njk5MzA1NDMsImV4aXN0aW5nIjp0cnVlfQ==; role=student; isLoggedIn=false; userID=user5XDETP7KV11A; _roboguruSession=95544c52-4cea-4ee1-a386-306e26a56ff3; _rgSession=9002d4d5-5f68-43ae-9cea-31f4d8e2b033; token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJydCI6ImV5SmhiR2NpT2lKSVV6STFOaUlzSW5SNWNDSTZJa3BYVkNKOS5leUpoYm05dUlqcDBjblZsTENKbGVIQWlPakUyTlRRME9Ea3dNRE1zSW5Wdll5STZJblZ6WlhJMVdFUkZWRkEzUzFZeE1VRWlMQ0p5SWpvaWMzUjFaR1Z1ZENJc0luUnZhMlZ1U1VRaU9pSXhOalV5T1RNNU1ERXpPREUzTWpVNE1qSTRJbjAuUDZHenBpWWljS0ZyWGVwbjZvQkIxRVhuVjZQamc0NmdzRWZpRFg5eVF2YyIsImFub24iOnRydWUsImV4cCI6MTY1Mzk3MDYwMywidW9jIjoidXNlcjVYREVUUDdLVjExQSIsInIiOiJzdHVkZW50IiwidG9rZW5JRCI6IjE2NTI5MzkwMTM4MTcyNTgyMjgifQ.7pJUXRuVx3BYiJzv8qsXRh6H2PxaP5xCReage3_6d0s; refreshToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhbm9uIjp0cnVlLCJleHAiOjE2NTQ0ODkwMDMsInVvYyI6InVzZXI1WERFVFA3S1YxMUEiLCJyIjoic3R1ZGVudCIsInRva2VuSUQiOiIxNjUyOTM5MDEzODE3MjU4MjI4In0.P6GzpiYicKFrXepn6oBB1EXnV6Pjg46gsEfiDX9yQvc; expireToken=1653970423000; _gid=GA1.2.3768689.1653884203; _gat_UA-196723136-1=1; _gat_UA-49650255-35=1; _gat_UA-49650255-1=1; _ga=GA1.2.625588034.1627638456; _ga_MZNBZXV2VM=GS1.1.1653884203.414.1.1653884235.0; _ga_KGEN8KBRBW=GS1.1.1653884203.437.1.1653884235.0; _ga_EN706YSJ4M=GS1.1.1653884203.377.1.1653884235.28' \ -H 'country: id' \ -H 'disable-node-proxy: false' \ -H 'origin: https://roboguru.sirogu.com' \ -H 'pragma: no-cache' \ -H 'referer: https://roboguru.sirogu.com/forum/sebutkan-penerapan-polinomial-pada-kehidupan-sehari-hari-dan-berikan-contoh-soalnya_FRM-2RDK876E' \ -H 'sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="102", "Google Chrome";v="102"' \ -H 'sec-ch-ua-mobile: ?0' \ -H 'sec-ch-ua-platform: "macOS"' \ -H 'sec-fetch-dest: empty' \ -H 'sec-fetch-mode: cors' \ -H 'sec-fetch-site: same-origin' \ -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36' \ -H 'with-auth: true' \ --data-raw '{"id":"roboguru-new-banner","data":{"gradeSerial":"3GAWQ3PJRB","isDummy":false}}' \ --compressed ``` - create new modular file in CloudFunction. sample ``` const { buildLayouts, getFromSheet } = require('../modules/roboguru-banner') module.exports = { fn: async (req, cache) => { const banners = await cache.fetchSource(getFromSheet({ gsid: '1LCtuoarxSDWv7SIx1O7hgBi8g7TNivnc_862lFvaM1A', sid: "2044131940" })) return buildLayouts(req, banners); }, }; ``` ## RBGR-4883 MT and Roboexpert can't be banned, RBGR-5464 Backfill Deleted Forum ### description product & ops need function to backfill deleted content. There are multiple way to delete contents - user delete their own content (only in old apps) - MT report & delete content - MT report & delete content + banned user ### requirements - run regularly - deleted content to anon - deleted content to public - query by - content type (question/answer) - user - deleted - deleted by user - answered by expert - verified ### request - POST {rubel-forum}/backfill/deleted-content - body ``` { query: { contentType: answer userSerial?: string isDeletedByCreator?: bool -> def: false isByMT?: bool -> def: false isVerified?: bool -> def: false } to: user | anon } ``` ### backfill - delete ### worker - build specific worker with defined interval to hit endpoint /backfill-deleted-content - deleted ## RLO expiring coin ``` ruko-service-api ruko rlo-coin rco rg-notif-payment-center npc corem user -> web -> hit npc npc -> hit ruko ruko update db <- no longer used, lets use rlo-coin rlo-coin get from db ``` ### things to consider - cut balance before session - do something to expire the coins ### things to do - RBGR-5103: P5 [BE] add expiry date column in db - not doing, already has expiry date column - RBGR-5104: P0 [BE] take expiry date into account when deducting coins - mostly in rlo-api - expired, will always be at the end of day on the expiry day (23.59) - probably use cronjob to zero all expired coin - what if a user want/need a refund? no need, actually. P3, or even lets do this when we want to implement expiry by coin - opt1: expiring log -> for history purpose only, can be seen by ops - is a table - pros1: can store life-time zeroing history - opt2: new column, `last balance` to store latest coin before zeroing - is a column - pros1: can store just enough data for recovery purposes - lets say no teacher working at midnight (we don't ) - no need to handle. datarace wont happened - IF there's a poor teacher that accept tutoring session at midnight - let the data race happen. brief OPS team to refund the coin - do we want to restore money by default? - we want to NOT give the coin back - check expiry date before refunding. if its before expire time -> refund, else -> no refund - RBGR-5105: P0 [BE] create configurable coin package - in rlo-coin - frontend hit rlo-api for expired date - FE hit rnpcr, npc (rg-notify-payment-center) hit rlo-api. rlo-api store expiry date in db - FE hit rnpcr, npc (rg-notify-payment-center) hit CF - RBGR-5106: P2 [BE] create jarvis task to adjust coin package - in rlo-coin - ``` cloudfunction gsheet -> modular-component -> rlo-api -> rnpc DBMSeet -> rlo-api -> r jenkins/jarvis -> rlo-api -> DBMS ``` - take option Cloudfunction - there's also an option with envvar, via `rogu config edit` - can also be hardcoded TBH. lets start with hardcoding in rlo-api - RBGR-5108: P0 [BE] get coin endpoint should also return its expiry - in rlo-coin - add new field in response - RBGR-5109: P9999999999 [BE] fetch coin expiry date data - same as RBGR-5108. mark duplicate, or not doing - RBGR-5111: P0 [BE] modify states to show coin expiry - in rg-chatbot-roboguru - ``` wa (whatsapp) rg-whatsapp-proxy (rwp) rg-chatbot-api (rca) rlo-api wa -> hit webhook on rwp -> publish event via pubsub -> subscribed by rca -> if need any rlo data, hit rlo-api ``` - update existing callback to retrieve expiry data - update states to show that data - RBGR-5115: P0 [BE] revamp coin deduction mechanism, deduct before session - in rlo-api - should we implement in rlo-coin? No. - no, no need more service to access rg_production db - RBGR-5117: P5 [BE] add coin refund mechanism - we can make jarvis job for this, but should we? - no. - RBGR-5118: P5 [BE] add jarvis job to refund coins - same argument as RBGR-5117 - RBGR-5132: P0 [BE] update expiry date when buying new coins - in rlo-coin - RBGR-5136: P0 [BE] mechanism to expire coin (reset to 0) - in rlo-coin - new worker role, to reset expired coin every midnight - example can be seen in roboguru-discovery-api, role sitemap - RBGR-5142: P0 [BE] get coin package endpoint should also return expiry date for that package - in rlo-coin - this task is specifically made to describe the making of an endpoint ## Verification Mode rg-forum -> core service -> may expose implementation detail - have to have good abstraction - rubel-forum -> product serviceS - labels definition - query definition -> e.g. what a popular thread is we'll have 2 new endpoints, and update 1 endpoint in rubel-forum 1. GetVerificationModeThread <- azka - probably will reuse lots of things in answermode 2. FreeVerificationModeThread <- azka, grace - e.g. FreeAnswerMode,... - rubel-forum will wrap the api-call to rg-forum - soft delete label (`being-verified`) - in rg-forum -> not with sql `DELETE`, but with `UPDATE set deleted_at = NOW(), is_deleted = true` 3. UpdateAnswerLabel <- grace - add new label (`IneligibleForVerification`) - test by - call endpoint via http or unittest - check whether the new label exists in `forum_discussion_label` in rg-forum ## Answer Mode ```sql= \dt+ forum_thread_label F1 F2 F3 F4 F5 ... Fn Fn+1 1 user -- every 15 minutes begin select * from forum_thread ft left join forum_thread_label ftl on ft.serial = ftl.forum_thread_serial where ft.forum_thread_label not in ('F1', 'F2') -- list selected AND (not exists ( -- reported select 1 from forum_thread_label ftl where ftl.deleted_at IS NULL AND forum_thread.serial = ftl.forum_thread_serial AND ftl.label_serial = 'LBL-2W7TIQF5') ) order by created_at for update; update forum_thread set is_deleted = 1, deleted_at = now() from forum_thread_label where is_deleted = 0 and ( now()-updated_at > duration('15m10s') or now()-created_at > duration('60m') ) commit ``` expected scenarios: # scenario 1: user has no activity after 15m10s ``` worker -> check 05.55 azka -> lock 06.00 worker -> check 06.10 azka -> do nothing 06.15 -- anyone is allowed to fetch that question worker -> check 06.25 -> soft-delete ``` # scenario 2: user has activity before 15m10s ``` worker -> check 05.55 azka -> lock 06.00 worker -> check 06.10 azka -> do something 06.15 -> call endpoint -> update forum_thread_label set updated_at = now() where forum_thread_serial = 'F1' -- people still cant fetch that question ``` ## RBGR-4154 Banner Automation - Refactor cloudfunction `/modular-components` - Use google sheet as data source - Create guidlines to fill gsheet - Create column to represent all value in banner - Cached ~1 hour ## RBGR-4175 Whatsapp Migration - only modify template in yaml - waiting for product team for update ## RBGR-4180 Update Video Concept Behaviors in Question Details provide link, pointing to Apps - similar usecase on `GetQuestionDetail` handler - need new onelink from products, so product can track how big the traffic is - to get the multiple video detail, can _certainly (from tafaquh's words)_ use rg-video's `ListVideo` function How To 1. Get UserCode to check videoQuota exceed or not. Impacted to `isLock` in video ```json= { "concepts": [ "OTHERS" ], "deeplink": "ruangguru://roboguru-search-result?question=segitiga+sama+sisi\u0026grade=3GAWQ3PJRB\u0026subject=Matematika", "image": "https://img-video-tracking.ruangguru.com/20191107105227.png", "isLocked": false, "onelink": "https://ruangguru.onelink.me/blPk/b12c9c7f?question=segitiga+sama+sisi\u0026grade=3GAWQ3PJRB\u0026subject=Matematika", "serial": "RGV-39IJLB2GRT6W", "title": "Rasio Dua Bangun Sebangun 1" } ``` 2. Get list video details using `ListVideo` in `rg-videos` 3. Tidy up onelink, deeplink and other response contract ```protobuf= rpc GetVideoListDetail(GetVideoListDetailRequest) returns (GetVideoListDetailResponse) { option (google.api.http) = { get : "/videos/concept-question" }; option (rg.gateway_url) = "/api/v3/roboguru-discovery/videos/concept-question"; option (rg.auth) = { enabled : true roles : "admin,student,teacher,employee" }; option (rg.errors) = { name : "INTERNAL_ERROR" http_status : INTERNAL_SERVER_ERROR code : 91101 message : "internal error" }; option (rg.errors) = { name : "BAD_REQUEST" http_status : BAD_REQUEST code : 91102 message : "bad request" }; option (rg.errors) = { name: "FORBIDDEN" http_status : FORBIDDEN code: 993134 message: "not allowed" }; } message GetVideoListDetailRequest { string questionSerial = 1; repeated string videoSerial = 2; string videoUUID = 3; string searchUUID = 4; } message GetVideoListDetailResponse { // choose one map<string, Video> videos = 1; repeated Video videos = 1; // recommend using this } ``` ## RBGR-3989 Performance Test W1 jan ### API to be tested docs: https://ruanggguru.atlassian.net/wiki/spaces/SD/pages/944308510/Social+Learning+Team#Performance-Test ``` scope: - We need to test cache and without cache. Might to make unique parameter for each endpoint - We need to get at least 100rps - If needeed, we can scale service dependency. ex: rg-user, roboapi - if it's handled by other team we need to notify them - We need to test at least 5min to trigger auto scale - Define low, normal, high in profile ``` - roboguru-discovery-api - SearchQuestion - image - text - GetQuestionDetail - GetQuestionList - rubel-forum - GetForumThreadList - GetForumThreadTrendingList - GetForumThreadDetailByThreadSerial - rg-forum - GetDiscussionByThreadSerialPaging - rg-content-review - likedislike.GetByUserContentSerials - likedislike.GetByUserContentSerialsAndContentTypes ## RBGR-3523 Multi-question and Multi-photo - Add new field on `SearchQuestion`, ex: `imageURLs: []string` - If this send by user it should merge images to 1 image. It's not developed right now but we need to make contract and handle it's request (if given imageURLs it will return bad request not yet implemented) ## RBGR-3991 Comment in Question Page - roboguru-discovery-api - add endpoint to get list of rating with comment is not empty - filter by comment is not null - sort desc/asc by rating or date - enable pagination ## RBGR-3988 Limit Notification @tafaquh ## RBGR-3512 [Web MT] Filter for Subscribers Question @azka ## RBGR-3998 A/B Test WA RLO @azka might breakdown later ## RBGR-3702 Fix RLO booking issues @azka might breakdown later ## RBGR-3032 Revamp Answer Page & Feedback Mechanism - People: Azka, Ridwan ### Implementation - Integrate with questionView/pageView endpoint - docs tracker api: [quip](https://quip.com/W9WqAHekpBJt/Tracking-Events) - kalo endpoint ga diprovide pake elasticsearch (harusnya sih udah ada, tapi kalo gaada ya setup etl nya pake datamesh) - eventName: `roboguruQuestion` - gaperlu terlalu realtime - invalidate misalnya 1 menit / question - key: `questionPageCount:QU-ASDSD -> 12345` - bulk fetch ketika ngehit tracker (jangan hit tracker dalam loop) - affected endpoints: - question detail - similar question ``` { ..., question: { ..., viewCount: 500 }, similarQuestions: [ ..., { ..., viewCount: 324 } ] } ``` - question list (homepage) ``` { ..., questions: [ question: { ..., viewCount: 500 }, ] } ``` - search question ``` { ..., question: [{ ..., viewCount: 500 }, ], .... } ``` - Detect question answer from pembahasan - match keyword, one of the following (detail: https://ruanggguru.atlassian.net/wiki/spaces/ROB/pages/2328035640/PRD+Revamp+Answer+Page+and+Search+Result#As-user%2C-I-can-see-the-answer.) - Jadi - Oleh karena itu - Oleh sebab itu - Dengan Demikian - Maka dari itu - In conclusion - Therefore - To conclude - To sum up - In summary - Thus - hence - in other words - Sehingga - Dalam hal itu - Karena itu - Berdasarkan penjelasan diatas - on the last sentence on the last paragraph - if not found then return null - pembahasan dalam bentuk html - e.g. `Jadi 2^10 hasilnya <style class=.>1024</style>.` - possible algorithm - use last 1st child html tag && contains conclusion word (jadi, hence, ...) - render html into plain text. split by paragraph and by sentences (by double new line and by punctuation, respectively). in last paragraph, find special keyword. - will remove styling - how to handle image? cant be handled - - on field `db: rg-questionbank.question.text` - Question Rating - Dari fe - kalau ada yang love - langsung kasih rating 5 - nembak 2 endopint - rating 5 - like - kalau rating n >= 3 - langsung kasih love - nembak 2 endopint - rating n - like - kalau rating n <3 - ga kasih love - nembak 1 endopint - rating n - implementation - rg-content-review already has everything we need. can we just use it? @cxBeu4wPQ4afLURnyse_SQ ```go // POST type SetRatingRequest struct { ContentSerial string `json:"contentSerial" validate:"required"` Rating int `json:"rating""` Comment string `json:"comment"` Source string `json:"source" validate:"required"` } // GET authenticatedEmployeeRoute.GET("/rating/aggregates", ratingHandler.GetRatingAggByCourseSerials) ``` - affected endpoints - question list (homepage) - question detail (homepage) - search question - rda - wrap robo-forum - robo-forum - wrap content_review for get - wrap content_review for post - Question Rating Backfill Migration - Convert existing love to 5 stars - Create onetime script to execute - Create endpoint give question rating - new contracts for : ``` rpc SendQuestionRating(SendQuestionRatingRequest) returns (google.protobuf.Empty) { option (google.api.http) = { post : "/rating" body: "*" }; option (rg.gateway_url) = "/api/v3/roboguru-discovery/rating"; option (rg.auth) = { enabled : true roles : "admin,student,teacher,employee" }; option (rg.errors) = { name : "INTERNAL_ERROR" http_status : INTERNAL_SERVER_ERROR code : 91101 message : "internal error" }; option (rg.errors) = { name : "BAD_REQUEST" http_status : BAD_REQUEST code : 91102 message : "bad request" }; } message SendQuestionRatingRequest { string questionSerial = 1; int rating = 2; } ``` ## RBGR-3296 DS Support tracker, passage, e2e - People: Tafaquh ### Implementation - Generate passage on image generator - Join question with question passage, then run image generator ![](https://i.imgur.com/3MAUQPc.png) - Ask assassment team to scale db when generate image - Add searchUUID tracker to 4xx response from roboguruapi.searchQuestion - tracker name `message_command_roboguru` , `roboguru_unknown_subject` , `roboguru_short_question` , `roboguru_multiple_question` , `roboguru_question_not_found` ## RBGR-3299 Information Section in Roboguru Homepage - People: Tafaquh ### Implementation - Adjust information endpoint - api: new/rubelforum/information ## [BE] WA abc test: - Effort: 5 (2-3 day) - People: 1 ## [BE] Deleted Qns in Forum: - Effort: 8 (5 day) - Notes: user bisa punya question, question ini bisa di hapus. Ketika dihapus - Data tetap ada di list - Hide identity user yang post - Data hilang dari pertanyaan saya - Data tetap ada dari jawaban saya apabila user me-reply question yang dihapus - Remove notifikasi terhadap pembuat question - on comment - on like - Concern: - Takut bakalan ganti2 requirement - QA bakal banyak regression - People: 1 ### Implementation #### Delete Question - Instead of we change the current delete function or add new delete endpoint. We can use update label instead. - ~~OPS 1 - DEL `{rg-forum}}/forum/thread/serial/{forumThreadSerial}` to UPDATE `{{rubel-forum}}/rubelforum/forum/question/status-label`~~ - OPS 2 - Add new endpoint DEL `{rubel-forum}}/forum/thread/{forumThreadSerial}` proxy to {{rg-forum}} UPDATE label on rg-forum - When a user deletes a thread, the system must add a new label in `forum_thread_label` for a specific forum serial. - We must add a new label called `deleted` on table `forum_thread_label` - on thread response it should return anonymous ``` { data: { ..., userSerial: "", username: "anon", userTag: {}, imageUrl: "" // avatar ijo } } ``` #### Adjust Thread History - Add new condition on function `GetQuestionByMe` `rubel-forum` line 45 ``` query.FilterByLabels = query.FilterByLabels.Add(entity.LabelHidden, false) if q.FilterByCreatedByMe { query.FilterByLabels = query.FilterByLabels.Add(entity.LabelDeleted, false) } ``` - Add new condition based on deleted label `repository/question_repository/dto.go` ``` func (t *pbQuestionResponse) ToEntity(cfg *entity.QuestionQueryConfig, pageSize int) *entity.QuestionsPaging ``` #### Adjust Thread CreatedByUser - Change `username` to `anon` when label string list contains `deleted` label. The code is [here](https://gitlab.com/ruangguru/source/-/blob/master/rubel-forum/repository/question_repository/dto.go#L215) ``` CreatedByUser: entity.CreatedByUser{ Username: thread.Username, Serial: thread.CreatedBy, Subscription: entity.UserSubscription{}, Tag: entity.UserTag{}, PhotoURL: thread.ImageURL, }, ``` #### Disable Notification - Adjust endpoint for like. Disable send notif when userSerial thread is anonymous - `GiveLikeDislikeForumThreadBySerial` forum-thread/service.go - `CreateForumDiscussion` forum-discussion/service.go - Notes: - Notify product team with case notification worker will works every 10 minutes, what if, in 10 minutes cycle, some other user commented in minute 1, minute 2 and minute 3, and poster deleted the thread on minute 5? the notification will still be sent to poster on minute 10 due to existing notifcationLog before the thread is marked as deleted ## [BE] WA A/B/C/D Test Search Limit: - Effort: 2 day - Notes: user akan dilimit sesuai dengan variant limit yg didapat - 2x - 3x - 4x - 5x - Concern: - People: 1 ### Implementation #### Adjust flagr - Adjust flagr related function like `GetABTestVariantID` in `rda/discovery/repository.go` line 393, so that this function can use by any platform not only WA. - Add flagr flag (enable/disable) on every a/b test. #### Adjust search question limit - Adjust limitation code, `s.cfg.WAQuestionQuota` should be change with variant limit. Use config as default limit. ``` return quotaUsed < s.cfg.WAQuestionQuota, nil to return quotaUsed < WAQuestionQuotaVariantX, nil ``` ## [BE] New Subject: - Effort: 4 week - Notes: - Concern: - Menunggu hasil model dari tim data - Yang bisa dilakukan migrate data `rubel-structure` ke `roboguru-structure` - People: 1 ### Implementation #### Migration Code - Migrate rubel-structure to roboguru-structure (new table in rubel-forum) #### New Endpoint to Create Subject - The handler function will be called `CreateSubjectRoboguruStructure`. It will have body request like this - ensure consistency (non-duplicate) in subject content db when create new subject from roboguru ``` { "subjectName": "Rumus jodoh", "parentSerial": "SMA" "subjectSerial"?: "JDH-123" // this will skip create subject content } ``` - The handler function will be called `CreateStructureRoboguruStructure`. It will have body request like this ``` { "name": "Kelas jodoh", "parentSerial": "SMA" "parentSerial"?: "K0-JDH" // if empty, it means parent already on rubel-structure } ``` #### Adjust Rubel Forum Function - CreateForumThread - Function `GetAllSubjectWithParent` rubel-forum/client/rubel-structure line 34 - `GetForumThreadList` rubel-forum/handler/forum-thread.go line 135 - `GetQuestionList` roboguru-discovery-api/handler/discovery.go line 340 - `getStructureByGradeSerialAndSubjectName` roboguru-discovery-api/handler/discovery.go line 340 - `s.mappingGradeSubject()` roboguru-discovery-api/discovery/service.go line 179 - `rubel-forum/pkg/rubel-structure/service.go` #### Adjust BA Endpoint - `CreateForumThread` rubel-forum/handler/forum-thread.go line 56 to create forum thread - no issue. just make sure the curriculum serial and subject serial are the same with rubel-structure. - `GetLessonsByGroupSerial` rubel-forum/handler/class.go line 104 to get subject serial based on curriculum serial and source: BA #### Migrate Grade and Subject from CloudFunction - Currently, web use CF to get grade & subject - migrate to `/rubelforum/groups` and `/rubelforum/lesson` - support param `showLesson` in `/rubelforum/groups` to list all subject for each groups - Affected code - `rubel-forum/client/group:GetForumStudentRubelStructure` and all code that depends on this function - `rubel-forum/client/class/service.go` and all code that depends on this function ## [Web, BE] Forum TH: - Effort: 8 - Notes: - Depedencies - tracking - question-bank - video - user - roboguru-api - notification - rubel-structure - rg-content-review - rg-user-banned - rg-censor - content-authorization - rg-info-api - rg-socmed-feed - rg-gam-progress - rg-gam-user - general-service ? - Deployment service, pubsub, tracking, db, redis TH - rg-forum + db - rubel-forum + db + redis (dipake rg-forum juga) - roboguru-discovery-api + db + redis - roboguru-forum + db - roboguru-rules ? - pubsub - elasticsearch - roboguru question detail - roboguru question list - forum question list - Setting cloud function - Grade & Class - Banner - Forum info - App info ? - Storage - Icon - Image/Asset - Configuration file TH (config) - MT Tag - Onelink post to forum ? - Onelink question detail ? - Concept value (kalo di id OTHERS/lainnya) - Gamification - Deeplink - Feedback - Bucket uploader ? - People: 1 (Taf) ## [Android, Web, BE] Sharing Soal - Banner: - Effort: 1 - Notes: - Cloudfunction - Deeplink - S3 - Upload asset ## [BE] Refactor Roboguru Chatbot: - Notes: - ALL DONE - Nemu satu bug (not really) di trackingnya. Beda format dengan yang lama, sudah difix mas wahyu dan sedang ditest sama QA ## [BE] Improve Filter Query: https://ruanggguru.atlassian.net/wiki/spaces/SD/pages/2095972373/Slow+query+count+forum+threads+in+Web+MT#Benchmark-Solution - Effort: 5 - Notes: - Support VN & TH - Scope dikecilin ke count aja (?) - ga perlu support pagination dulu - ga perlu support mapping es ke struct - People: 1 (Azka) -> jadi pak R@m@ ## [BE] Improve rg-forum for qna: https://ruangguru.slack.com/archives/CL9NANPC0/p1631941254013900?thread_ts=1631857537.002400&cid=CL9NANPC0 > Yap2 udah aman. > Quick post mortermnya: > - rg-forum dan rg-content-review pake DB yang sama > - Dari Live hit ke rg-forum > GetDiscussionDetailByThreadSerial -> rg-content-review > GetLikeDislike > - Query rg-content-review > GetLikeDislike ada IN nya buat masing2 discussion > - Di Live gak ada pagination, akibatnya query rg-content-review > GetLikeDislike banyak dihit dan banyak IN clausenya > - Gak ada cache di rg-forum > GetDiscussionDetailByThreadSerial > Action item: > - Tambah cache di rg-forum > GetDiscussionDetailByThreadSerial (dengan invalidation yang bagus, jangan timer based. Dan itu gak write intensive, harusnya masih aman kalau clear cache tiap ada update) > - Tambah circuit breaker di rg-forum > GetDiscussionDetailByThreadSerial. In case berat, set LikeDislikenya jadi 0 (gak perlu hit rg-content-review) > - Di Live tambah Pagination -> need app release - Effort: 3 (lowest solution) -> 13 (ideal solution) - Notes: - (opt) Performance - Enable cache - Invalidate when there's modify in thread or thread's discussion - Create ES for rgforum & rg-content-review - Country: ID, VN, TH - rg-content-review not breaking endpoint - (opt) untuk switching whether to use content-review - hit prometheus metric - config - soft error when rg-forum hit rg-content-review ## [Android, BE] Image compressor: - Effort: 2 - Notes: - S3 Bucket - Bikin baru untuk forum - Kalo bisa dari FE yang ngeconvert host s3 ke imgix ## [BE] FBM VN Chatbot: - Effort: - Notes: - banyak kebutuhan dari FBM adapter yg jadi blocker. e.g: - blm support quick-reply - panic ketika user kirim gambar - etc. (belum ketemu) - bisa konek ke qiscus - Concern: - Salah copas reply karena gk paham bahasanya - People: 1 ### Implementations - Ganti reply ke VN - ada beberapa yang langsung ganti, tapi ada banyak jg yang perlu diubah flownya - Get FB user's first name from FB API - Bikin method custom di utils roboguru callback `GetFacebookName` - params: - `tenant_name` (didapat dari callback, blocked by CMN-1151) - `user_id` (didapat dari callback, FB UID) - return: - first_name - error - Ambil FB Access Token dari messenger proxy (`{{rg-messenger-proxy}}/api/v3/rg-messenger-proxy/config/roboguru-vn`) - Request ke FB API, parse response, return - `https://graph.facebook.com/4640110679361604?fields=first_name&access_token={access_token}` - Method dipangggil saat state root dan input subject (notes: di root belum bisa, masih WIP dari chatbot-lib) - cache kalo udah manggil sekali, klo udah ada di cache gk usah dipanggil lagi - Qiscus Callback - masih perlu diskusi diskusi buat mahamin flownya - yang sudah ada bayangan: - untuk beberapa state yg perlu ke qiscus, tinggal diarahin kesana - pas baliknya ke state tertentu - FB Persistent Button - Setup dari FB pagenya langsung (kayaknya) - Bikin setiap state yang bakal dituju dari setiap button punya * (wildcard) source state supaya bisa diarahin dari mana aja - Deployment? setup dependencies baru kah buat VN? atau pake ID aja ## [BE] RLO WA Fund - Effort: medium-high - Notes: - extends existing rg-chatbot-roboguru flow - adds ability to chat with choosen teacher directly via whatsapp(selected via rlo matchmaking mechanism) ### Implementations - add new states in rg-chatbot-roboguru - (atleast in development state) use yaml to store states - if its impossible to utilize yaml in production - > create script to translate yaml into mysql insert query - if possible use this in production as source of truth (replacing mysql) - separates callback implementations by product (roboguru & rlo) - disable call within teacher app when chat is coming from WA - new callbacks - show payment options - show different links depends on what package is selected - check coin - call rg-user for phonenumber-account mapping - call rlo-coin to check current user's coin balance - new rlo-coin endpoint (migrate from corem) ``` ### Response ### GET /coin Authorization: Bearer <TOKEN> ### Response ### HTTP1.1 200 OK { data: { balance: 9999999 } } ``` - select grades + subject (cant utilize existing subject selection) - user select grade + subject, store in userAttr - match making - call rlo-api, based on which grade and subject is selected - learning session - user can chat with teacher - when user chat -> forward to sendbird from rg-chatbot-roboguru - when teacher chat -> rlo-api got event from sendbird, trigger send message endpoint in chatbot - feedback - very similar to the one in roboguru - send to rlo-api instead of roboguru-discovery-api - create new endpoint to send received message from rlo-api - perhaps can utilize the one provided with qiscus? - or exists already? - new endpoint example ``` ### Request ### POST /message Authorization: Bearer <TOKEN> { data: { destination: 08123456789 #destination phone number tenant: roboguru-1 #which tenant to send to message: ini adalah gambar seekor kucing loh dek media_url: https://en.wikipedia.org/wiki/File:VAN_CAT.png #(not sure 'bout this) teacher can send pictures (maybe explanation?) } } ### Response ### HTTP1.1 200 OK ``` - will refactor some parts of existing roboguru implementation into a more reusable form ## [BE] MT Web Typing - ALL DONE FROM BE - WAITING FOR BUGS FROM FE - atleast 1 bug is found - in release mechanism, but i forgot what the cause & effect - solved temporarily by refresh ## [BE] Question Details - Banner: - Effort: - Notes: - Cloudfunction - Deeplink - S3 - Upload asset ### Implementation - Nambah method di file `roboguru-question-detail` untuk handle yang WEB - req.headers.platform == 'ios' or 'android' -> cek apakah bisa equal web - give different layout banner (ask product)

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully