Index Design going incorrect
When creating an optimal index, start with = -- vendor_id in your case.

Then you get one crack at a "range" -- updated_at or (in the first case) code.

Also (or alternatively) "covering" the query can be beneficial.  This is where all the columns mentioned in the SELECT exist in the INDEX.  In the case of SELECT *, that is all columns in the table, and that is usually to many.  When doing code, count(*), only 3 or 4 columns are mentioned, so "covering" may be practical and beneficial.

The PRIMARY KEY (id) is included implicitly in any secondary key.

It is handy to provide the entire EXPLAIN when asking questions like these.  It is instructive to discuss "key_len" and how that tells you how many columns it used.  EXPLAIN FORMAT=JSON SELECT ... is even better, since it is explicit.

Why did it pick (vendor_Id, code, feedback, updated_At, id) for the first query?  It is missing created_at, so it is not "covering".  Probably it decided that vendor_id (=) plus code (range) was slightly better than vendor_id, updated_At.  I would expect the latter (aka "Index1") to be better because it might be able to consume the ORDER BY.

index1 (vendor_Id, updated_At) is redundant (and can be DROPped) because of codeIndex (vendor_Id, updated_At, code).

The second query needs (vendor_Id, updated_At, code) -- =, "range", "covering".  The query can be performed in the index, without touching the data.

The third query adds feedback; so it needs the columns of (vendor_Id, code, feedback, updated_At), but it is hard to know whether that order is best or (vendor_Id, updated_At, code, feedback).

What version are you using?  5.6, 5.7, and 8.0 have each made significant changes to optimizations in this area.

BTW, and  code is not null is redundant in the first query.

The first query cannot stop after 10 rows; this is because there is more than one "range" in the WHERE.