TypeScript GraphQL API for the Penance game app: card definitions, factions, and effects. Built to support a trading-card-style builder and (later) live match functionality.
| Layer | Tech |
|---|---|
| Runtime | Node.js, TypeScript (ESM) |
| API | Apollo Server 5, GraphQL 16 |
| Database | DynamoDB Local only (Dynalite via AWS SDK v3); hosted AWS DynamoDB not yet implemented |
| Tooling | tsx, cross-env, dotenv, uuid |
| Port | Service | Notes |
|---|---|---|
| 4000 | GraphQL API | Default; override with PORT |
| 8000 | Dynalite | DynamoDB Local; used when PENANCE_ENV=local |
| 8002 | dynamodb-admin | Optional UI to browse tables; run via npm run dynamodb:ui |
- Node.js (v18+ recommended)
- npm
npm installIn a terminal, start Dynalite and leave it running:
npm run dynamodb:localThis listens on port 8000. The API will connect here when PENANCE_ENV=local.
In another terminal (with Dynalite running):
npm run seedThis creates the penance-local table and seeds card data from src/modules/cards/catalog.ts. Factions and card effects are static data in src/modules and are not stored in DynamoDB.
In the same or another terminal:
npm run devThe GraphQL server runs at http://localhost:4000. Use Apollo Sandbox or any GraphQL client.
With Dynalite running:
npm run dynamodb:uiThen open http://localhost:8002 to inspect the local DynamoDB tables.
- Start Dynalite:
npm run dynamodb:local - Start the API:
npm run dev - Re-run
npm run seedonly when you want to reset or refresh card data.
- PENANCE_ENV — Backend for DynamoDB:
local(default for dev): use Dynalite athttp://localhost:8000— this is the only mode implemented todaydev(or other): would use real AWS DynamoDB inus-east-1— not yet implemented
- Table name is
penance-{env}(e.g.penance-local,penance-dev). Single-table design.
The dev script and seed script set PENANCE_ENV=local via cross-env so you don’t need a .env for basic local use.
src/
index.ts # Server bootstrap
schema/ # GraphQL typeDefs + resolvers
dynamodb/ # DynamoDB client, table name (env-based)
modules/
cards/ # Card catalog (seed source), service (DynamoDB reads)
effects/ # Card effects (static catalog + service)
factions/ # Factions (static catalog + service)
scripts/
seed.ts # Seeds cards into DynamoDB
Data flow: GraphQL → resolvers → services. Cards are read from DynamoDB; factions and effects are served from in-memory catalogs.
query {
health
cards {
id
name
rarity
faction
cardEffects {
key
title
description
}
}
}health returns something like: ok | dynamo: http://localhost:8000 so you can confirm which DynamoDB endpoint is in use.
| Command | Purpose |
|---|---|
npm run dev |
Start API with tsx watch (PENANCE_ENV=local) |
npm run build |
Compile TypeScript to dist/ |
npm run start |
Run compiled dist/index.js (set PENANCE_ENV if needed) |
npm run typecheck |
tsc --noEmit |
npm run seed |
Seed cards into local DynamoDB (Dynalite must be running) |
npm run dynamodb:local |
Start Dynalite on port 8000 |
npm run dynamodb:ui |
Start dynamodb-admin on port 8002 |
- add DynamoDB client configuration
- introduce repository files for persistence
- replace in-memory card data with DynamoDB reads
- add mutations for creating and updating cards
- document sample demo queries for interview use

