Card Schema Explained
What is a card schema? A card schema defines both the card itself and the card’s relationship with other cards. This definition is used to create a composable user experience and data system that allows cards to move around.
At Cardstack, we have been using card schemas as basic building blocks for a long time. We have built applications ourselves and released documentation showing other developers how to leverage schemas and define relationships, in order to build applications that are composable — not just in a single-application point of view. They can also use components from other applications to build up an app from parts.
The traditional card schema (Card Schema V1) divides the problem of defining what a card is (its fields and relationships) from actually encoding that data. This is similar to defining a column for your SQL database and then putting in the values by inserting them into the rows. These have always been two separate concepts. But if you want to create something that can move around, you want to combine them. Excel is very good at this. When you open an Excel file, it contains the computer properties (the definition, the columns, and maybe the formula) as well as the instant data (what’s in the rows underneath, the values you type in).
When we talk about databases, especially databases on the Web, it’s very hard to say, “I want to take my data from Google and move it to Facebook.” That’s equally true for, “I want to take my data from Salesforce.com and move it to MailChimp.” You need very specific adapters to bring that together. But what if all the information you enter about your customer or yourself were combined into this thing called a card, which includes both what it is and what the data is? That way, we can facilitate movement across hubs and the whole system.
What is a card? (2:31)
From a framework, programming, and design point of view, a card is an application at a state. A card is both the app and what you put into the app. That’s quite unique. When you use an application that does a to-do list, you think of your to-do list as the app and then of your entry (what you type into your checklist) as the state or the data. But a card contains both. Think about a Web page; when you open up Twitter, it loads the app and looks at your account, seeing what state or what information about your Twitter account fits into that app, and then renders your tweets.
Furthermore, a card has an identity. It has a URL, a link. The goal of making a card a state with an identity (combining services, storage, and references/links) is that the end users perceive the card as a physical thing. It is almost like a screenshot they can move around. And when they want to edit the schema, they can edit it within the application. It’s similar to an Excel file; if you want to have a slightly different formula to predict your revenue, you can go to the app and change the formula by changing the code. Or you can punch in some new information about your sales in July and let the data update itself. So, a card is like a self-contained document, with both the template and the schema included.
The environment — the app you build around cards — uses the service of the card to say, “you told me you have an estimate of your revenue or your projection for this quarter; what is it?” Excel can kind of do that; you can link two Excel sheets together and say, “take the output of sheet three and use it as input for this field.” But the composability starts to break down once you have a couple more sheet libraries and then upload everything to a server — suddenly, all your links break. On the Web, that’s much more reliable. You know that you can always get the latest information from your bank because you have an API. Since every card is also an API, Cardstack implements the card in a server called the Cardstack Hub. Based on the definition of the card, that hub generates an API that is the same as the APIs you get from Gmail or MailChimp or Intercom. The card’s services are part of that.
That’s what a card is. The environment interacts with the card through services, and the card has both its own storage and a link.
What is in a card? (5:42)
A card includes these three components (app/services, state/storage, identity/link), which contain further components.
The app (services) includes templates and schemas:
The template could be the map, the booking screen, the checkout screen, or the account screen of your app. In the Cardstack universe, we have both an isolated and an embedded template, as a card can both stand on its own and contain other cards. An embedded template would be like embedding a YouTube video inside a block, where YouTube renders that little self-contained video with the play control on the bottom. When you go to the YouTube link, you get the isolated view, which shows related content, title, description, and comments; that would be the isolator. Every card is like a YouTube video, except that it’s not just a video, but could be about a to-do list, about invoices, about payments, etc. All these things exist in the template.
The schema is about data types. For example, an app about dog walkers has all kinds of data — like the dog walkers, the locations, the cities, the dogs, and the prices. Those schemas make up the application. If your card is a to-do list, it could have ‘is it done yet?’ data or checkout data or a due date. But if your to-do list ends up marking some sort of business process, you may want to attach it and say, “this item actually links to whether the credit report has been received, whether the loan has been approved, whether the car has been returned.” That idea of a card containing another card and using another schema is quite powerful.
The state (storage) includes field values and references to other cards:
The storage contains the field values (what is actually in the field, what is stored as part of the card) as well as references to other cards. For example, if you wrote a song, you would put in the song title and reference your collaborators. You could point to other cards, referencing the artist’s card or the union card if you’re putting together a Broadway show. This is possible because every card has an identity. You can say, “Who played in this song? Let me go to the card, find the union card, copy and paste all of that, and boom” — that’s how you link your new show or song with another person.
So, the card mixes the things we like about the Web (the hyper-linking aspects of it) with the things we like about applications (which allow you to interact with it and have a consistent user interface).
Once you have a card, you can place this card in your personal library. It’s almost like saving a file to your personal folder. But you can also take this card (or this set of templates, schemas, fields, relationships, and links) and put it in the shared catalog. Usually, what you have on your computer does not easily become something on a website; you have to upload it, copy and paste in the forms, etc. But with cards, because they’re self-contained, all you have to do is say, “Here’s my card.” That card contains everything; and suddenly, it shows up in the shared catalog. That’s the power of the self-encapsulation of cards.
What is in the card schema? (9:10)
A schema has two components: There’s the public face of the card and the private implementation of the card. Let’s take an invoice, for example.
You want to have information with a lot of details; it could point to certain products you have or include a discount or some notes or some special notes for accounting, etc. Those would be private fields.
The public aspects are more obvious; since this is an invoice, it should have a due date, plus information about the payment status, the value, the tax, and maybe some currency details. This basic standard interoperability ensures that, if you receive invoices from ten different organizations, they will look very conform metadata-wise; and even though you may not know the private invoice implementation details, you can still act on that publicly available data very similarly.
This is actually what happens on the Web. When you put something on the Web, you have a lot of fields that make up the Web page — whether it is a boarding pass, flight information, or a product in an e-commerce store. You have some public data that you mark up. Then, Facebook, Google, and search engines look at those public fields, like the public fields of your blog post; they extract the thumbnail image, the title, the description, and the author, and give you a nice little teaser in your news feed. That’s the metadata. It’s something that has an enterprise and backend-system tradition, but is also (through the semantic Web or search engine optimization) meaningful in the Web.
That’s what happens in the app. The metadata is like the interface that shields some of the low-level details. And because the schema and the services are all part of the API family, you can actually see the metadata and the fields. If you go to Card Board (our content management system), you can see that an article has certain fields. We are working on making some of those fields metadata, so you can actually syndicate them to Google News, for instance.
How does a card compose its content? (11:30)
When you compose a card that contains another card, you are doing something called delegated rendering. The easiest example of this is a blog post with a YouTube video. You paste a link to a YouTube video into your blog post, thereby embedding the template from YouTube; in this case, the embedded template is the YouTube player. So, you are rendering your blog post yourself (with your title and your information), but when it comes to this video, you want to delegate the rendering to YouTube and have them compose it. That’s called IFrame (Inline Frame). Ads do this too; if you have a website and you want to make money, you delegate the rendering of a particular portion — such as the top banner — to an ad network or ad agent.
We have been supporting delegated rendering in the Cardstack Framework. In fact, almost all the apps we’ve shipped so far have an embedded template. When you go to Card Folio, the rendering of each crypto asset is delegated. If you go to our Card Board application, the rendering of the media assets and the rich texts that make up the articles are delegated too.
But now, we want to introduce a new way of doing this. Sometimes, you don’t actually need to delegate the rendering of your video. A good example is an email attachment. You might just want to know the file name, size, and type — all of which come from the metadata.
Sometimes, the template (the containing card) just needs to list the metadata. If you have an expense report and you drag a receipt into it, that receipt has metadata about when and how and what category; so, you want to be able to sum up all these things in a table — a rendered list with the metadata for each one of those things. So, in Cardstack, you can either use delegated rendering to build applications or (as the containing application, the invoice, the expense report looking at the receipt) extract the metadata and lay it out in a grid or table of your choice — whatever makes sense for your user experience in the containing app.
What is a card’s facade? (14:21)
Cards are very flexible. They can do anything, because they’re essentially just a pile of code with some data in it; they expose metadata and have a template you can render. But as we think about interoperability, we start looking at your ability to get something you expect from a card. What if a card is describing an event — a conference or a show or a performance from a famous rock band? That event can have certain fields that are expected, such as the door time, duration, and location. If you are an artist and you want to list all your events, all of which may be in different places, you can have differently styled posters on the Web for each of the events. If you click on them, they’re all different, but they can all be listed very coherently within your page template, by leveraging this metadata service.
One way to make sure this works all the time is for a card to declare a facade. The card could say, “I’m an event card. I know what Google and Facebook and Eventbrite expect of an event card; these are the common fields that exist in every event. So, I’ll comply with this idea and make metadata that is always consistent (that is part of a standard), to ensure interoperability.”
How do composite cards support facades? (15:53)
The first card in the Cardstack Ecosystem that ever says “I’m an event” essentially becomes the template for all the other cards that say, “That’s a good idea, an event card. I’m going to be an event card too!” And that’s what happens next. If you share your event card to the catalog and other people, who go to the Card Catalog, like your card, they can use your card to make their own event card. Their card may have a different layout, different fields; it may be for a sporting event or not have general admission; or maybe, it has more information about specific sections. It is a new composite card that can combine fields, add fields / sections / segments, but that uses the facade of the event card to map its fields, so that it looks exactly like the event card that’s in the catalog. That’s what we call field mapping.
When you save this event card, it can be dragged and added to your upcoming event exactly the same way, because it looks like an event card from the outside. That’s what we call re-implementation, which is the card way of doing this — you map all the fields, so that it looks exactly like the event card on the outside, while it could be doing anything on the inside. For example, if you have a playlist and you have different shows with different songs, you can calculate how long your show would be, based on the songs you’re playing; so, you can compute the duration (like in Excel), add it up, and that’s how long your show is going to be. You can do that even though the original event card in the catalog doesn’t support it; you can add support for this additional field and then map it as a duration or calculator field.
That allows us to innovate and derive from works people have done. Developers starting to build an event system can look at the Card Catalog as a template or as a starting point for their own creations.
Can a card have multiple facades? (18:51)
You can create a card with multiple facades. Let’s say you create a card that is a ticket. The ticket is more than just an event, because it also includes payment. You want to make sure everybody has paid for the event and you want to give them a receipt. There’s a receipt in the Card Catalog, there’s an event in the Card Catalog, and there are different payment forms in the Card Catalog. So, when you create that ticket, it is simultaneously a ticket card, a receipt card, and an event card. And you can drag the event into an event calendar or drag the receipt into an expense report system, which will recognize the value, how much you paid, and add it up.
So, even though the card looks just like a ticket to the user, it is actually much more. You can scan a QR code at the door, have the event show up in your calendar, use the payment as proof that you have paid, and take the receipt so you can get reimbursed for it. And then, based on what you think your card is more like — is it more like a ticket, kind of a receipt, less like an event? — that actually helps us to decide which one you prefer, when you drag the card into something that expects multiple types.
Therein lies much of our inspiration for designing Cardstack. When you copy something from Excel and paste it into Word, Word says, “I know what you’re doing. You’re pasting a spreadsheet, so I’m going to preserve the formula.” If you paste it in an email, it may be an image; if you paste it into Notepad, it ends up as a list of names in plain text. So, the idea of being able to use this facade is about saying, “What are you? Can we use the maximum value you provide within the card, so that we can reduce the amount of degradation as you move a card, copy a card, or paste a card from one system to another?” As you compose your card-based experience, this entire idea of weighted facades is really important.
To do multiple facades, you have to be a developer who understands how to map the fields, who knows which fields are required, and who can run tests to make sure those fields are implemented correctly, with the right data type (we’re building tools that make this very easy, using the Cardstack Framework). Most users will just say, “Great! There’s a ticket. Let me go modify the ticket and call the event something else.” This template becomes something where people can just change the data, to make meet-up tickets — which do the same thing and have all these great capabilities — for their own events. But the developer building this for the first time will have to wire this up and create the facades.
How do we deal with new versions of card schemas? (21:42)
Tickets and things like that are stored in your personal library, much like old files (old decks, old PowerPoints, old code, …). But they may go out of date. They may require a new version of Photoshop, or the old version that is no longer on the market. That’s why version control is a big problem. If you try to upload something to a Web service that’s based on the old version, or you’re uploading a file format that’s not supported, it may ask you to update it.
Migration is also very important for those who have done database work, especially MongoDB and NoSQL work. What Cardstack is doing in storing the serialization of the data within the card is very similar to how document databases do things. In document databases, instead of splitting your invoice into three tables (invoice, details, payee, payment), you put them all in one JSON document and store it as is. And if you add a field, you have to migrate the data; so, the migration script has to exist.
Because cards are compositional, you can migrate the part that is related to events or tickets separately, assuming you’re adopting it in a certain way. If you’re deriving and re-implementing it, then you have to take responsibility for upgrading to a certain version. But there are nice things about leveraging this migration. It shows up in searches, and if you have a new field that gets calculated (let’s say the duration of an event card was just a calculation between start time and end time, and now it is its own field), then, for those cards that do not have the duration field, you can go and calculate that and use that as a migration script. That’s how new versions get handled.
When does a card snapshot its contained cards? (25:11)
The version of the card is important. But the version of the data is equally important. We have lived through the world where you go to a brand-new website, get on a product hunt, find the product, and start using the to-do-list application. It’s great, so you put all your data — your state — inside that database, using the template and the UI they provide. Then, one day, they go out of business or they get bought by Facebook and all the data is gone. So, when you send someone a link with your to-do list or your membership information, suddenly, that link doesn’t work anymore, because it’s broken.
That is why we wanted to make sure we can make cards much more resilient to these kinds of version-related issues. In some cases, a version is only available on a website or on a hosted server and suddenly, that host is not available anymore. So, we do something called snapshots. A snapshot is not all that different from taking a screenshot of a boarding pass, in case it disappears from the app or the flight gets canceled and you want to be able to prove that you have a boarding pass. For your own sake, you make a copy, storing the information in a screenshot or PDF. With the card infrastructure and the idea of app + state + link (all of them being one thing), we can make a copy of this state.
Say you’re making a ticket card, which goes through an API to access the Google Calendar API. This Google Calendar API tells you that the event is on the 26th. Then, you update the UI; but while doing that, you store a copy of your data within the card, saying, “Hey card, in case you forget, here is the value of the thing I saw on Google Calendar. It gave me the response that the event is at 7:00 p.m. on the 26th, so please write that down.” It’s the same with payments. You might be using a Stripe API; when you’ve paid, you can take all the data and write it in the card. So, in the future, if the link between the live data and the card got severed, your card would render the last known information that it saved for you. That’s essentially what snapshots are good for — they are good for resiliency.
But it gets even more interesting. It’s not just about data not being available because, for example, your Google Calendar authorization is gone. It’s for sharing. If you are sharing data with another person by selling them a ticket, and it all depends on you having access to the Google API or your Google account, then there’s no guarantee. The other person may not have access to the underlying official API data from Google. Even if you can access that API, the other person may not be able to see the data.
This idea of being able to exchange cards as if they were actual documents / screenshots / printed documents requires us to save that information in a way that allows the card to be mobile. Every single time something goes from a library to the catalog, we capture this information. Now, if someone is trying to make a new event card, and realizes, “oh they support Google Calendar, that’s great, so I can have it updated bidirectionally on my calendar,” the person has to reestablish the link. Then, this would be a new event in October. And that linkage is quite useful for other people using this ticket template for their own workflows. But in this particular example of an event card that is published as a template in the public catalog, the card contains some static data of same sample event. If you have it on your computer and you want to see the live data — whether it has been updated, the date has been changed, the event was canceled, your credit card was charged — you want to be able to switch between the snapshots and the live data, if you are privileged to see the sources. Even if you don’t, it’s good for that to be there.
This over-the-wire response — what has been sent back from the payment card — is entirely within the card and therefore entirely within the Cardstack environment. So, it’s quite easy for us to take what has been returned to the hub, insert it in the browser, and write that to this series of snapshots. You can actually go back and forth on the snapshot history and see how this event has evolved; assuming that it was rescheduled several times, you can actually have a button to see what’s going on.
We haven’t mentioned any more sophisticated data sources than APIs like Stripe or Google Calendar. But the truth is that a lot of what we talk about at Cardstack — about cryptocurrency or blockchain — fits really nicely with this model.
When you want to pay someone in cryptocurrency, that requires you to have a MetaMask plugin that gets the data. If you share the link and the other person doesn’t have your wallet or address, that information disappears, because the linkage (the over-the-wire, the access to the data source) doesn’t exist, it’s severed. Using the same snapshot mechanism we can use for Web APIs / Web 3.0 APIs / crypto APIs / blockchain-based APIs, we can create the same resiliency with a much newer, much more advanced, and much more cutting-edge technology, thus providing safety and dependability. That’s what is currently lacking in the user experience of a blockchain-based application: It’s really hard to get it to work for one person. Imagine what happens when we invite more participants and build network effects. With snapshots, you can say, “There’s a shadow of this data. If you can connect it to your wallet, I will pay you a commission.” Then there’s incentive to say, “Hey, this application works. There’s a hidden treasure here if you unpack this paid-by-ETH bonus system. And once you connect it back over the wire, you get another button in your template that allows you to redeem your rewards.” Snapshots are the way to make this happen.
How do you copy or move a card to a new hub? (31:18)
Ultimately, the point of snapshots and this encapsulation of data and code is to do something relatively simple: We want to create this idea that cards are completely mobile. So, your ticket card — which contains its own template, its own look and feel, the fields, the linkages to Google Calendar, the payment, the snapshot data, and the link — is just one JSON file. All of this is just one data structure, much like everything in your financial model is just one XLS file. That one thing is the code + the data + the value, and it exists in your library. You can also submit or share it. Say you bought a ticket that you put on your home page, which runs Cardstack, and you want to gift it to a local NGO, because it’s a nonprofit that gives underprivileged kids access to this amazing concert. You can send them your ticket through a workflow system or just by copy- and pasting the URL. But that URL (unlike a YouTube video) is actually pulling all the information — including the ticket, payment, transfer, and maybe even blockchain records of who owns the ticket — and giving it to this new shared workspace.
This is not about installing or uninstalling apps, or making sure that versions are compatible (Is it the same WordPress? Do you have an Airtable account?) None of that matters anymore. Is your Airtable aligned with my fields? Of course not, because the schema and the data are separate; they are different between the tenants in a multi-tenant system. But Cardstack completely encapsulates it, so that you don’t have to worry about tenancy anymore. Every workspace, every library, every site, every network, every registry, every consortium is just a folder that contains these cards. A card contains its own data. And if you want to compose it, the cards provide the APIs and service to each other. Most importantly, the Cardstack Framework does all the hard work. All the things we talked about, all the layers of architecture, all the tools and APIs we’ve built — all of this is about creating the illusion that a card is a physical thing you can exchange with the people you like. And when you exchange it, the card goes where you want it to go, including all things necessary. To render it, to link it, to see it, to reliably render it even if you don’t have the permission — all that exists within this promise that is provided by the card stack.
Status & strategy (33:47)
1. Current open-sourced projects are on Card Schema V1 and will continue to work: Card Board, Card Folio, Tally, dotBC Music Registry, Card SDK Project Template
As we embark on the upgrade of this framework, we acknowledge that we have a lot of current open-source projects that are on the first version of schema (Card Schema V1). There’s usually a Git repository with the definition of the file, and then another one that is appended with “-data” — this one has all the data, such as content for articles and images for Card Board; cryptocurrency addresses for Card Folio; prepaid-card accounts, service providers, and billing relationships for Tally; music recordings, albums, and artist release schedules for the dotBC music registry. We are also creating a much simpler Card SDK project template for new developers who want to learn about Cardstack. They can see how card schemas work and get this idea of encapsulation. But these are two separate kinds of repository.
2. Future projects will use Card Schema V2 to support use cases that require multi-party, multi-hub, and multi-version workflows: Card Space, Card Flow, Card Catalog, Multi-Git Registry
Going forward, we will continue working on Card Schema V2, until we can release and start using it. We see a lot of use cases where multiple parties need to work together, exchanging data. So, if someone says, “here’s a new license request; if you fill it out, you’ll be able to get this blockchain license of my song or movie,” that means we have to encode the form to apply for the license, the legal language, the version history of negotiating the terms, as well as the payments (which can be done in cryptocurrency or the traditional way). All of that requires the card V2 encapsulation of app + state + link.
We also see a world where, instead of having Card Board as your blog, you have a multi-hub federated network, where you can exchange articles and syndicate between communities. If someone creates a new article type, which includes a card that could be some data-flow-diagram-based visualization, that card has its own template, its own logic, and you can install it. The hub brings in those schemas and dependencies, with the Card Catalog providing protection. It acts almost as a registry, which uses some additional cryptographic or other type of moderation technique to make sure that the catalog you can depend on (that allows you to share and move across card boundaries) is safe, similar to chrome plugins that you can install in your browser. And that’s what we call Multi-Git repository. The catalog itself is a Git repository containing cards that are submitted and version-controlled by the community or by sellers of premium ticket templates. Card Flow is the way we move it all. And Card Space is how you accumulate and build your own personal library.
As we work on this, the basic structure of a card is not going to change. But the way we encode it, the way we allow these cards to be stitched together through Card Schema V2 allows us to accomplish a really flexible multi-party workflow that will be the foundation of the decentralized way of working, of sharing information, and of conducting business transactions that get you paid and create economic value. So, while Card Schema V1 and V2 will coexist, future Cardstack products will use Card Schema V2 to enable multi-party workflows.
3. Create more with less code — user interface to compose the complete card (schema + templates + data) using only a browser: Leverages the four edges of the Cardstack environment to point and click to a Cardstack app
So, creating more with less is about providing the tools to allow many more people to create, iterate, and share in this card-based economy. We want to break out of these apps on our phones that we both love and hate. Only iOS developers and Android developers can craft these perfect nuggets of scrumptiousness. But in fact, these apps are little prisons of our data that don’t want to interact with each other. The card vision, which is based on the World-Wide-Web vision (that’s why we call ourselves the application site for Web 3.0), is about recombining these pieces that are now locked into apps with branded icons on your home screen, and letting them flow a lot more fluently. This way, it’s all in your workflow within your space, shared in the catalog. And we use open-source tools like Git and blockchain to share that between different people.
We have been trying to rethink what a document-driven, a unit-of-exchange-driven economy on the Web is going to look like. We will get closer and closer to realizing this vision. Card Schema V1 gave us most of the plumbing for indexing, display, rendering, login, logout, and search. And now, we want to make it one level better, so that the new encapsulation actually makes a federated, decentralized Web a reality — not just in theory, but in the same scrumptious, amazing user-interface-quality you expect from an app that you subscribe to today.
- Tally Launches on Testnet: Try Cardstack’s metering and billing network for decentralized SaaS
- Introducing Gitchain: Cardstack’s Protocol for Syncing Application States
- Building the Card Catalog: Status update & strategy for the Card SDK