Collaborative GraphQL API where people can publish ideas, comment, and vote for the best proposals. The stack relies on TypeScript, TypeGraphQL, and Prisma, keeping responsibilities isolated across resolvers, services, and the data layer.
- GraphQL API bootstrapped with Apollo Server 5, Express 5, and TypeGraphQL, wired in src/index.ts.
- Persistence handled by Prisma Client with the Better SQLite 3 adapter (prisma/prisma.ts) and schema definitions in prisma/schema.prisma.
- Authentication and refresh tokens generated via src/utils/jwt.ts; critical resolvers are protected by src/middlewares/auth.middleware.ts.
- Domain logic sits in resolvers (src/resolvers) and services (src/services), enforcing rules such as single votes per user and ownership checks.
schema.graphqlis emitted automatically by TypeGraphQL, so the public contract always mirrors the code.
- Runtime: Node.js 20+, TypeScript 5.9, TSX for fast watch mode.
- Server: Express 5, Apollo Server, and
@as-integrations/express5exposing/graphqlthrough a single middleware. - GraphQL: TypeGraphQL decorators, shared context in src/graphql/context/index.ts, and the
@GqlUser()decorator from src/graphql/decorators/user.decorator.ts. - Data: Prisma Client 7.x, Better SQLite adapter for lightweight development setups.
- Security:
bcryptjsfor hashing helpers in src/utils/hash.ts andjsonwebtokenissuing short-lived access tokens plus 1-day refresh tokens.
.
├── prisma/
│ ├── schema.prisma # Relational modeling for User, Idea, Comment, Vote
│ ├── prisma.ts # Prisma singleton wired to Better SQLite adapter
│ └── migrations/ # Prisma Migrate history
├── src/
│ ├── dtos/ # Typed GraphQL inputs/outputs
│ ├── graphql/ # Context builder and decorators
│ ├── middlewares/ # isAuth guard
│ ├── models/ # TypeGraphQL ObjectTypes
│ ├── resolvers/ # Auth, User, Idea, Comment, Vote entry points
│ ├── services/ # Business logic talking to Prisma
│ └── utils/ # Hash and JWT helpers
├── schema.graphql # Generated automatically (do not edit)
├── package.json # Scripts and dependencies
└── README.md
- Requirements: Node.js 20+, npm 10+ (or pnpm/yarn). Install Prisma CLI as a dev dependency (
npm i -D prisma). - Install packages:
npm install
- Environment variables: copy .env.example to
.envand adjust as needed.DATABASE_URL="file:./dev.db" JWT_SECRET="super-secret-key" NODE_ENV="development"
- Migrations and Prisma Client:
npx prisma migrate dev --name init # applies migrations npx prisma generate # (re)generates the client
- Local server:
Playground available at
npm run dev
http://localhost:4000/graphql.
- Register/Login: Mutations
registerandloginin src/resolvers/auth.resolver.ts return an access token (15 minutes) plus a refresh token (1 day). - Context parsing: src/graphql/context/index.ts inspects
Authorization: Bearer <token>and injects the user id into the GraphQL context. - Middleware:
@UseMiddleware(isAuth)blocks any protected resolver when the user is missing. - Decorator:
@GqlUser()fetches the authenticatedUserentity once and injects it directly into resolver parameters.
buildSchemawiresAuthResolver,UserResolver,IdeaResolver,CommentResolver, andVoteResolverinside src/index.ts.- Resolvers delegate to dedicated services:
IdeaServicehandles creation, updates, listing, and basic aggregations.VoteServiceenforces the "one vote per user" rule via the composite keyuserId_ideaId.CommentServiceguarantees the target idea exists before saving feedback.
- TypeGraphQL models in src/models expose relationships through
FieldResolvers for authors, comments, votes, and counters. - Prisma executes the actual CRUD work on SQLite, honoring cascade deletes declared in the schema.
mutation Register {
register(data: { name: "Ada", email: "ada@labs.io", password: "123456" }) {
token
refreshToken
user {
id
name
email
createdAt
}
}
}
mutation Login {
login(data: { email: "ada@labs.io", password: "123456" }) {
token
refreshToken
user {
id
name
}
}
}mutation CreateIdea {
createIdea(
data: {
title: "AI brainstorming assistant"
description: "Suggests insights"
}
) {
id
title
description
createdAt
}
}
query ListIdeas {
listIdeas {
id
title
countVotes
author {
id
name
}
comments {
id
content
author {
name
}
}
votes {
id
user {
name
}
}
}
}mutation AddComment {
createComment(ideaId: "<ID>", data: { content: "Great proposal!" }) {
id
content
author {
name
}
}
}
mutation ToggleVote {
toggleVote(ideaId: "<ID>")
}Every operation above (except register, login, and createUser) requires a valid Authorization header.
- Modeling: Users own ideas, comments, and votes; the
@@unique([userId, ideaId])composite key prevents duplicate votes. Cascade deletes keep data consistent. - Better SQLite adapter: boosts local performance and keeps Prisma Client lightweight for demos or CI.
- Migrations: live inside
prisma/migrations. Usenpx prisma migrate dev --name <change>to evolve the schema;npx prisma migrate resetfor a local reset. - Diagnostics:
npx prisma studioopens a UI to inspect or edit data quickly.
npm run dev: starts the server withtsx watch.npx prisma generate: syncs the Prisma Client withschema.prisma.npx prisma migrate dev: applies pending migrations.npx prisma studio: launches the Prisma Studio dashboard.