Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 1 addition & 56 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,56 +1 @@
# compiled output
/dist
/node_modules
/build

# Logs
logs
*.log
npm-debug.log*
pnpm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# OS
.DS_Store

# Tests
/coverage
/.nyc_output

# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace

# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json

# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local

# temp directory
.temp
.tmp

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
node_modules
98 changes: 41 additions & 57 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,43 @@
# Future Self
# Futureself

I built Future Self as a simple app for writing messages today and receiving them later in my inbox. It uses a NestJS API with a React (Vite) frontend, PostgreSQL for storage, Redis + BullMQ for scheduling and background jobs, and [Brevo](https://www.brevo.com/) for email delivery.
I built Futureself as a simple app for writing messages today and receiving them later in my inbox. It uses a NestJS API with a React (Vite) frontend, PostgreSQL for storage, Redis + BullMQ for scheduling and background jobs, and [Brevo](https://www.brevo.com/) for email delivery.

Users can write a message, choose a delivery date, and let the system handle the scheduling and sending automatically.

### Why

Most reminder apps are built around tasks and notifications. I wanted something more personal: a way to leave notes for myself that arrive at the right time.

Sometimes its a reflection I want to revisit months later, a message for an important milestone, encouragement before a difficult period, or just context I know Ill forget with time. Future Self is built around that idea: delayed personal communication instead of productivity tooling.
Sometimes it's a reflection I want to revisit months later, a message for an important milestone, encouragement before a difficult period, or just context I know I'll forget with time. Futureself is built around that idea: delayed personal communication instead of productivity tooling.

> **Note** This repository is still in active development

## Prerequisites

- **Node.js** 22.x or current LTS
- **pnpm** 9.x (`npm install -g pnpm`)
- **PostgreSQL** and **Redis** (local install or your own containers)
- **Brevo** API key only if you want real email (optional locally)

## Setup

### 1. Postgres and Redis

Run both on the hosts/ports youll put in `.env.local`. Defaults below assume `127.0.0.1`.
Run both on the hosts/ports you'll put in `.env.local`. Defaults below assume `127.0.0.1`.

### 2. Backend
### 2. Install dependencies

From the repo root:

```bash
npm install
pnpm install
```

Create `.env.local` in the repo root. The app loads `.env.local` first, then `.env.prod` (`[app.module.ts](src/app.module.ts)`). Required keys: `[src/commons/interfaces/env.ts](src/commons/interfaces/env.ts)`.
This installs dependencies for both `apps/api` and `apps/web` in one shot.

### 3. Backend

Create `.env.local` in `apps/api/`. Required keys: `apps/api/src/commons/interfaces/env.ts`.

```env
NODE_ENVIRONMENT=local
Expand All @@ -51,7 +58,7 @@ POSTGRES_HOST=127.0.0.1
POSTGRES_PORT=5432
POSTGRES_HOST_DOCKER=postgres

EMAIL_SENDER_NAME=Future Self
EMAIL_SENDER_NAME=Futureself
EMAIL_SENDER_EMAIL=noreply@example.com
BREVO_API_ENDPOINT=https://api.brevo.com/v3
BREVO_API_KEY=your-brevo-api-key
Expand All @@ -63,70 +70,47 @@ FRONTEND_URL=http://localhost:5173
- `FRONTEND_URL` must match where the Vite app runs (CORS).
- Use a strong `APP_KEY` outside local.

```bash
npm run start:dev
```

API listens on `APP_PORT` (log: `Server running on …`).
### 4. Frontend

### 3. Frontend

```bash
cd frontend
npm install
cp .env.example .env
```

Set `VITE_API_URL` to your API origin (no trailing slash):
Create `.env` in `apps/web/` (copy from `apps/web/.env.example`):

```env
VITE_API_URL=http://localhost:3000
```

Must match backend `APP_PORT`.

```bash
npm run dev
```

App: [http://localhost:5173](http://localhost:5173) (Vite default in `[frontend/vite.config.ts](frontend/vite.config.ts)`).

## Local dev

Two terminals:
Run both from the repo root:

```bash
pnpm dev # starts both api and web concurrently
```

Or in separate terminals:

| Terminal | Directory | Command |
| -------- | ----------- | ------------------- |
| API | repo root | `npm run start:dev` |
| UI | `frontend/` | `npm run dev` |
| Terminal | Command |
| -------- | --------------- |
| API | `pnpm dev:api` |
| Web | `pnpm dev:web` |

App: [http://localhost:5173](http://localhost:5173) — API on port defined in `APP_PORT`.

Register, compose a message, pick a future delivery time. With `DONT_SEND_EMAIL=true`, the queue still runs; email is skipped.

## Scripts

**API** (repo root)


| Command | Purpose |
| -------------------- | --------------------- |
| `npm run start:dev` | Dev server with watch |
| `npm run build` | Production build |
| `npm run start:prod` | Run `dist/` |
| `npm run lint` | ESLint |
| `npm run test` | Unit tests |
| `npm run test:e2e` | E2E tests |


**Frontend** (`frontend/`)


| Command | Purpose |
| ----------------- | ------------------------------ |
| `npm run dev` | Vite dev server |
| `npm run build` | Typecheck + production build |
| `npm run preview` | Serve production build locally |
| `npm run lint` | ESLint |


All scripts run from the **repo root** via pnpm:

| Command | Purpose |
| ----------------- | ------------------------------------ |
| `pnpm dev` | Start both api and web |
| `pnpm dev:api` | API dev server with watch |
| `pnpm dev:web` | Vite dev server |
| `pnpm build` | Production build for both |
| `pnpm build:api` | Production build for api only |
| `pnpm build:web` | Production build for web only |
| `pnpm test` | Run all tests |
| `pnpm lint` | Lint all packages |
| `pnpm format` | Format all packages |
56 changes: 56 additions & 0 deletions apps/api/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# compiled output
/dist
/node_modules
/build

# Logs
logs
*.log
npm-debug.log*
pnpm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# OS
.DS_Store

# Tests
/coverage
/.nyc_output

# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace

# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json

# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local

# temp directory
.temp
.tmp

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
File renamed without changes.
File renamed without changes.
35 changes: 35 additions & 0 deletions apps/api/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// @ts-check
import eslint from '@eslint/js';
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
import globals from 'globals';
import tseslint from 'typescript-eslint';

export default tseslint.config(
{
ignores: ['eslint.config.mjs'],
},
eslint.configs.recommended,
...tseslint.configs.recommendedTypeChecked,
eslintPluginPrettierRecommended,
{
languageOptions: {
globals: {
...globals.node,
...globals.jest,
},
ecmaVersion: 5,
sourceType: 'module',
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
{
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-floating-promises': 'warn',
'@typescript-eslint/no-unsafe-argument': 'warn'
},
},
);
File renamed without changes.
Loading
Loading