Tottem is an open source experimentation, it aims combining personal productivity tool approach with (slow) social media capabilities to make users empowered and somehow emancipated.
I have two considerations in mind:
- building a product based on ethic design
- experimenting open-source web technologies and share it
First goal: designing a product human centered allowing people to build and manage their online and public library. Just a tool to manage and gather the content we love, in order to share it with friends & community ๐
More and more, people โ especially journalists, are losing their ability to choose which content to promote & amplify. Consequently, what they will consume. Instead, automatic recommendation algorithms carefully choose the best (sic!) content for you. Those deep learning algorithms create a unique & personal narrative stream of content in your social feed... You said, best ? So what ? Not really, it's just designed to maximize clicks and views. Of course, what else they can do?
Here, I'm happy to share some references
So, what if I want to explore durable book or article recommendations from a friend? What if I want to really dig into a specific subject?
Tottem aims combining personal productivity tool approach with (slow) social media capabilities to make users empowered and somehow emancipated.
Tottem aims to provide the same high quality user experience that most of modern productivity tools provide. Managing your library should be easy and enjoyable. With a great tool, great content could be made and shared.
The basic workflow:
- Collect everything in one Inbox.
- Organise into Spaces and Collection.
- Express yourself and explain your opinion
- Publish and share with your community
The second goal is about experimenting how to build a web software today. This documentation explains which technologies are used here and how they are organised.
It's a full-stack Typescript app with some code generation in order to have a type safe experience from end-to-end.
Here is a list of main technologies used:
- ๐ React
- ๐ฅ NextJS to provide fast SSR experience
- ๐ TailwindCSS
- ๐ฑ GraphQL, powered by Apollo tools
- ๐ฎโโ๏ธ Auth0 for authentication
- ๐ Prisma Framework to manage data model and database
Inspired by those recommendations, this is how the codebase is structured:
tottem/
โโโ src
โโโโโ generated # contains generated code (types, hooks, ...)
โโโโโ pages # static and dynamic routes declaration used by NextJS
โโโโโ components # shared generic component
โโโโโ scenes # different parts of the application
โโโโโโโ moduleName # Auth | Profile | Me ...
โโโโโโโโโ components # module components. **Each** components can specify its own specific components, queries, ...
โโโโโโโโโ queries.gql # All data queries and mutation are written in gql files
โโโโโโโโโ hooks.ts # Most of the reusable logic is written in hooks
โโโโโโโโโ index.tsx # Main scene file
โโโโโโโโโ View.tsx # Sometime stateless component are isolated in View file for clarity or reusability
โโโโโ services # shared services as authentication, error management, ...
- Prisma provides a library Photon that generate a typesafe client to manipulate data depending on a unique schema declaration in
schema.prisma
file.
Example where Photon is used to retrieve the not softly deleted items from specific collection :
const items = (
await ctx.photon.items.findMany({
where: {
collection: { id: collectionId },
isDeleted: false,
},
select: { id: true, position: true },
orderBy: { createdAt: 'desc' },
})
-
Nexus provides a code-first graphql approach that allows you to generate graphql schema (
schema.graphql
file) based on your resolvers and object definitions. Nexus is fully compliant with prisma and offers a nice plugin to automatically declare resolvers based on your photon client. -
**g is configured to generateraphqthis
gen** query [tool](https://graphql-code-generator.com/) is configured to parse all
.gqlfront-end files containing graphl queries and mutations. **graphql-codegen** uses remote and local (
localSchema.gql) graphql schemas to generate every type and hook we need (putting them inside
types.ts`) so we can safely fetch and mutate data.
Note that when global state management is required, Apollo Client is used as much as possible.
Example where typesafe hook useGetItemsQuery
is generated allowing to fetch data via Apollo Client smoothly
const { data } = useGetItemsQuery({
variables: {
collectionId,
},
})
๐คฏ No typo anymore, much less file & context switching with typescript.
Most of the time, global state approach is used to avoid props drilling. Neither Redux or React Context API are used here. It has been implemented with Apollo Client. A local schema is defined in localSchema.gql
type Breadcrumb {
title: String!
href: String!
}
extend type Query {
breadcrumbs: [Breadcrumb!]!
}
Then, we can define
- Query to read data from Apollo cache
query getBreadcrumbs {
breadcrumbs @client {
title
href
}
}
codegraphql-code
is configured to generate this simple hook query, used in Profile/TopBar for instance:
const { data } = useGetBreadcrumbsQuery()
2 Custom hooks to write data to cache with Apollo client
const useBreadcrumbs = (profileSlug: string) => {
const client = useApolloClient()
const setBreadcrumbs = ({ breadcrumbs }: GetCollectionProfileQuery) => {
client.writeData({
data: {
breadcrumbs,
},
})
}
const resetBreadcrumbs = () => {
client.writeData({
data: {
breadcrumbs: [],
},
})
}
return { resetBreadcrumbs, setBreadcrumbs }
}
Locally PG instance is needed with some var env set. In .env
for instance
AUTH0_LOCAL_ID='auth0|5dc8800986c8ba0e74d73654' # set local user id by passing auth0
AUTH0_CALLBACK='http://localhost:3000/auth/callback'
DATABASE_URL="postgresql://XXX@localhost:5432/XXX?sslaccept=accept_invalid_certs"
GRAPHQL_URL='http://localhost:4000/graphql'
DATABASE_PROVIDER="postgresql"
Then, two repositories are needed
git clone [email protected]:poulainv/tottem.git
cd tottem
npm install
npm run dev
git clone [email protected]:poulainv/tottem-graphql.git
cd tottem-graphql
npm install
npm run dev
Web app is available on http://localhost:3000
and graphql endpoint on http://localhost:4000/graphql
- Clรฉment Dรฉon @deonclem