Inspiration
When I try to promote my gigs and keep track of my friend’s performances, I have to spend a lot of time on social media. I feel a growing tension between the physical and digital - despite the need for a digital identity, performances and in-person events continue to be the heartbeat of cities and economic lifeline for creatives. It seems that while social media expanded an artist’s reach from one side of the globe to another, it’s arguably never been more difficult for independent artists to promote their work and shows. The product landscape with personalized recommendation engines is serving artists of large followings that fill rooms of +2k people - leaving local artists vastly overlooked. There’s a broken link in the chain between consumers who want to know what’s going on in their backyard, and amazing artists all around them.
What it does
Bandlink allows users to publish serverside pages for artists and venues. These generated pages serve as public-facing profiles that contain bios, links, events, and release data. The profile primitive enables users to follow artists or venues and explore events in their communities with a powerful querying mechanism exposed by the convex reactor.
How we built it
Rapid iterations were a key part of building this thing. Insights would come to me while on Bart, or while exercising - I would then prototype in code, go to the farmers market and local bars, show people and ask "Hey, do you want this?" Getting object feedback required a consistent practice of detachment. It was perhaps the most difficult thing to do - being vulnerable and surrendering to the product. If people said they didn't want it, I would ask why. Repeating this exercise helped me develop a product sense and prioritize the needs of the user.
The most helpful bit of feedback I got was from Greg, a drummer in the band Abracadabra and bartender at my local pub. He said, "Gabe this is cool and all. But if you're giving me yet another thing I have to use, I better have a good reason for it." I quickly realized that for a band to want this product, Bandlink, as an ecosystem, had to capture consumer value directly, and put money in Greg's pocket. And so in building in this manner, I was consistently testing things out, iterating rapidly with convex, and keeping my tech debt in a manageable state.
Challenges we ran into
Engineering
There was an initial curve to learning convex-specific things, like how convex storage works, and how I can incorporate these storages and imageUrls in the models in a type-safe manner. Executing efficient db lookups for the many: many table joins was also a challenge initially, but then reading Ian’s post about the database relationship helpers helped understand how to traverse complex relationships.
Getting the double-legged authentication system to work seamlessly between Clerk, convex and the app router was also a challenge. Protected routes via the nextjs middleware had to account for both levels of authentication and various UX scenarios. The front end needed to retain parity between things like the Authenticated component exposed by convex/react and the useUser hook exposed by cleark/nextjs package.
Timezones on events were challenging too. I had to ensure that people on the West Coast could book a performance at a location on the East Coast. Show times displayed downstream on the event cards needed to appear relative to the venue’s timezone. (A 7 pm show in New York had to display 7 pm on a browser in San Francisco). The solution was storing dates in convex as utc timestamps, as well as a timeZone field in the nested location object on events. Upstream and downstream mechanisms to ensure clean dates were then handled client side. I was thinking about having a separate places table that pointed to a Google places ID for each resource to extract the timezone, but the nested location object works for now.
Lastly, handling image uploads with a typesafe form that supported error handling via the react-hook API was challenging. I had to differentiate the schemas for the form for upstream data ingestion patterns that required images. For example, the payload for the updateTeam mutation requires storage IDs for the images used, but the storage IDs don’t exist yet at the time of form submission - the form at the react-hook level had to validate the form with a separate set of types so that the updateTeam mutation could be called sequentially as part of this async process.
Product
So I got to a place where I had full crud on my resources and things worked. I was so stoked. Surely I would have 100 users the next morning, but actually - the opposite turned out to be true. I would demo and talk about it with so much excitement, but no one cared that much. I found myself begging my friends to click log in, and when I called venues in San Franciso asking them how they currently promote events, they would ask “Is this a sales call”, and hang up the phone.
I needed some help. What’s a tool good for, if no one is using it? So I reached out to my friend Peter, who had made me one of the best coffees of my life at this place in Oakland called Umami Mart. He understood UX and customer experience like no other. We had chatted about a tool like this when we met, and so I hit him up with the bandlink link and we started jammin’. Peter focused on the user journey, layout, and styling so I could focus on engineering. He added elements that instilled trust in the platform. He built cards, information architecture, icons, logos, copy, and a styling system in Figma where we could iterate.
The toughest challenge is the chicken vs. egg problem. We need artists to use this thing in order for fans to use it, but we need fans to use it in order to incentivize artists to use it. Gaining surface area while having a clear product sense and focused execution is the toughest challenge on the horizon.
Accomplishments that we're proud of
Getting the models and data access patterns right was a wonderful feeling. Things started clicking from a product perspective (obsidian diagram attached), and there was a point where the initial curve of Convex started plateauing, and the code started to write itself. The schema-first nature of development produced a joyful typescript experience, whereby modifying a type in the schema would instantly produce typescript errors in the front end. Similarly, changes to the schema were reflected in the convex dashboard, which was quite magical. The API could be organized in parity with the business logic, producing a nice DX akin to trpc for queries and mutations.
What we learned
I learned so much about relational modeling, databases, caching and more. I found that Convex taught me fundamentals about its abstractions, which is a sign of a great product! I would dive into a topic and then read articles on stack, and then gain a better understanding of convex's take. It seems like Convex offers a holistic and integrative echosystem of relational modeling, flexibility of typed relational documents, and a whole lot more for the communication between client and server. The reactivity baked into the product with perfect caching, websocket connection, and document log was just incredible to use. I also learned about monorepos, and why this trpc-like DX coupled with the convex dash is so important for iteration speed. There is so much more to learn still, and it’s exciting to launch something but also feel like I’m just getting started.
What's next for Bandlink
I think Bandlink can provide value for lots of people and can re-envision how we interact with our local communities to something more organic. I see a lot of potential to build a space for people to go out and positively engage with their community, explore new art and experiences, and have one easy tool to explore where they live or travel.
I'm excited for the Bandlink newsletter. We'll be able to Increase surface area by sending out a what’s happening this weekend sort of thing for Bay Area music and grow the echo system horizontally. Placing a CTA for venues to be added to the list, and then having a curated selection of things to check out will increase value for the brand. This can then scale to other selected cities like Atlanta and Mexico City where the bandlink team can start to have a location-specific impact.
On the product end, I’m excited about developing the fan-experience with location-based search. I’m also excited about solidifying our offerings more around tiered plans, and incentivizing small venues to start promoting their offerings on the platform. In the immediate future, we need to tie up the core platform so that people can trust it, specifically enhancing the experience around creating events, and handling events with multiple performances.
Built With
- nextjs
- react
- tailwind
- typescript
- vercel
Log in or sign up for Devpost to join the conversation.