AST nodes are pretty much correct as-is, GenericClause for both Params and Args, and GenericIdent for explicit generic instantiations.
In the semantic graph, the non-nil GenericClause field indicates if the struct or fn declaration is a generic or not.
The $T identifiers must be declarations, so they can be registered in the scopes (and they have to be registered, so they can be looked up and see if the identifier is defined). They translate to GenericElem in the semantic graph and can only appear in GenericClause (so, in an Fn or Struct declaration).
The Type interface has an IsGeneric method to prevent a non-instantiated Generic type from being used anywhere except in its declaration and instatiation. As long as the type is not fully instantiated, it is still IsGeneric(...) == true.
It follows that generic declarations have a standard StructType or SignatureType, but it returns true to IsGeneric. The type-check pass would make sure it is only used where allowed.
Structs and Fns have fundamentally different semantics regarding generics: