https://github.com/loderunner/twotter
https://github.com/loderunner/twotter
Last synced: 6 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/loderunner/twotter
- Owner: loderunner
- Created: 2025-10-02T16:17:12.000Z (6 months ago)
- Default Branch: main
- Last Pushed: 2025-10-02T16:28:16.000Z (6 months ago)
- Last Synced: 2025-10-02T18:27:09.196Z (6 months ago)
- Language: TypeScript
- Size: 39.1 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Twotter
A toy Twitter-like backend built with Express.js and PostgreSQL.
## Setup
### Prerequisites
- Node.js 20+
- Docker and Docker Compose
### Installation
1. Install dependencies:
```bash
pnpm install
```
2. Start PostgreSQL:
```bash
docker compose up -d
```
3. Run database migrations:
```bash
pnpm run db:migrate
```
4. Seed the database with fixture data:
```bash
pnpm run db:seed
```
5. Start the development server:
```bash
pnpm run dev
```
The API will be available at `http://localhost:3000`.
## API Endpoints
### `GET /users`
Returns all users in the system.
**Response:**
```json
[
{
"id": "",
"full_name": "John Doe",
"username": "johndoe419",
"email": "john.doe@example.com",
"follows": ["", ""],
"followed_by": ["", ""]
}
]
```
### `GET /users/:id`
Returns a specific user profile.
**Response:**
```json
{
"id": "",
"full_name": "John Doe",
"username": "johndoe419",
"email": "john.doe@example.com",
"follows": ["", ""],
"followed_by": ["", ""]
}
```
### `GET /users/:id/posts`
Returns all posts by a user, paginated and sorted chronologically (most recent first).
**Query Parameters:**
- `page` (default: 1) - Page number
- `limit` (default: 20, max: 100) - Number of posts per page
**Response:**
```json
[
{
"id": "",
"author_id": "",
"text": "Hello Twotter",
"posted_at": "2025-10-02T13:05:35.166Z",
"replying_to": "",
"replies": ["", ""],
"liked_by": ["", ""]
}
]
```
### `GET /users/:id/feed`
Returns posts from users that this user follows, paginated and sorted chronologically (most recent first).
**Query Parameters:**
- `page` (default: 1) - Page number
- `limit` (default: 20, max: 100) - Number of posts per page
**Response:**
```json
[
{
"id": "",
"author_id": "",
"text": "Hello Twotter",
"posted_at": "2025-10-02T13:05:35.166Z",
"replying_to": "",
"replies": ["", ""],
"liked_by": ["", ""]
}
]
```
## Database Schema
### Users
- `id` - Primary key (nanoid)
- `full_name` - User's full name
- `username` - Unique username
- `email` - Unique email address
- `created_at` - Timestamp
### Posts
- `id` - Primary key (nanoid)
- `author_id` - Foreign key to users
- `text` - Post content
- `posted_at` - Timestamp
- `replying_to` - Foreign key to posts (nullable)
### Follows
- `follower_id` - Foreign key to users
- `followed_id` - Foreign key to users
- Primary key: (follower_id, followed_id)
### Likes
- `post_id` - Foreign key to posts
- `user_id` - Foreign key to users
- Primary key: (post_id, user_id)
## Seed Data
For development with a small dataset:
```bash
pnpm run db:seed
```
For integration testing with a large dataset (wipes database first):
```bash
pnpm run db:seed:integration
```
The integration seed generates deterministic data using a seeded random number generator:
- 500 users with realistic names
- 5000 posts spread over the last 30 days
- 1000 replies to existing posts
- ~40,000 follow relationships (avg 80 follows per user)
- ~75,000 likes (avg 15 likes per post)
**Note:** The integration seed produces identical data every time for reliable testing.
## Testing
Run integration tests:
```bash
pnpm run test:integration
```
Run tests in watch mode:
```bash
pnpm run test:integration:watch
```
The integration tests automatically seed the database with deterministic data before running.
## Development
Build for production:
```bash
pnpm run build
```
Start production server:
```bash
pnpm start
```