Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
dfd3583
docs: add foundation implementation plan
seonghobae Aug 2, 2026
2a0a182
build: initialize pnpm turborepo workspace
seonghobae Aug 2, 2026
1172ad1
build: define workspace packages
seonghobae Aug 2, 2026
bd47163
build: add turborepo task graph
seonghobae Aug 2, 2026
246d264
build: add shared TypeScript config
seonghobae Aug 2, 2026
0689fda
chore: add repository ignores
seonghobae Aug 2, 2026
950b7c9
chore: document environment variables
seonghobae Aug 2, 2026
214343f
feat: add shared API contracts package
seonghobae Aug 2, 2026
41437ad
build: configure contracts package
seonghobae Aug 2, 2026
c0dd581
feat: define request and event contracts
seonghobae Aug 2, 2026
13b458b
feat: add API gateway application
seonghobae Aug 2, 2026
ab689db
build: configure API gateway
seonghobae Aug 2, 2026
44349c2
feat: bootstrap API gateway
seonghobae Aug 2, 2026
e0c3371
feat: add gateway health module
seonghobae Aug 2, 2026
2fab3ea
feat: add LifeOS web application
seonghobae Aug 2, 2026
80d9658
build: configure web TypeScript
seonghobae Aug 2, 2026
4d0e904
feat: add web application shell
seonghobae Aug 2, 2026
41fc0e3
feat: add initial Today dashboard
seonghobae Aug 2, 2026
d6768d5
feat: style initial dashboard
seonghobae Aug 2, 2026
170c971
build: add Next.js type declarations
seonghobae Aug 2, 2026
430a775
feat: add identity service skeleton
seonghobae Aug 2, 2026
cadfa84
build: configure identity service
seonghobae Aug 2, 2026
657f426
feat: bootstrap identity service
seonghobae Aug 2, 2026
e0204b5
feat: add planning service skeleton
seonghobae Aug 2, 2026
e272809
build: configure planning service
seonghobae Aug 2, 2026
3de4a21
feat: bootstrap planning service
seonghobae Aug 2, 2026
e9a9412
feat: add habit service skeleton
seonghobae Aug 2, 2026
1315aa3
build: configure habit service
seonghobae Aug 2, 2026
22ee6f6
feat: bootstrap habit service
seonghobae Aug 2, 2026
c4d0f02
feat: add review service skeleton
seonghobae Aug 2, 2026
1cafa6f
build: configure review service
seonghobae Aug 2, 2026
e639858
feat: bootstrap review service
seonghobae Aug 2, 2026
5f99f25
infra: add local PostgreSQL and NATS
seonghobae Aug 2, 2026
072c122
docs: add project overview and local setup
seonghobae Aug 2, 2026
2857a0a
ci: add workspace validation pipeline
seonghobae Aug 2, 2026
1d85570
fix: use supported web lint command
seonghobae Aug 2, 2026
dbe6b39
fix: make CI independent of lockfile cache
seonghobae Aug 2, 2026
a07cefd
ci: pin actions and remove licensed duplicate secret scan
seonghobae Aug 2, 2026
50def4e
fix: restrict gateway CORS origins
seonghobae Aug 2, 2026
6f918c4
docs: declare allowed gateway origins
seonghobae Aug 2, 2026
b9a1266
ci: scope format gate to maintained root configuration
seonghobae Aug 2, 2026
feb9a82
test: allow empty identity service foundation suite
seonghobae Aug 2, 2026
6e09598
test: allow empty planning service foundation suite
seonghobae Aug 2, 2026
1c09231
test: allow empty habit service foundation suite
seonghobae Aug 2, 2026
9f57a60
test: allow empty review service foundation suite
seonghobae Aug 2, 2026
5d48596
test: allow empty gateway foundation suite
seonghobae Aug 2, 2026
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
16 changes: 16 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
NODE_ENV=development
WEB_PORT=3000
GATEWAY_PORT=4000
IDENTITY_SERVICE_PORT=4101
PLANNING_SERVICE_PORT=4102
HABIT_SERVICE_PORT=4103
REVIEW_SERVICE_PORT=4104
DATABASE_URL=postgresql://lifeos:lifeos@postgres:5432/lifeos
NATS_URL=nats://nats:4222
CORS_ALLOWED_ORIGINS=http://localhost:3000
SESSION_SECRET=replace-with-at-least-32-random-bytes
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
OAUTH_CALLBACK_BASE_URL=http://localhost:4000
47 changes: 47 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: CI

on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]

permissions:
contents: read

jobs:
validate:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4

- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: 22

- name: Enable Corepack
run: corepack enable

- name: Install dependencies
run: pnpm install --no-frozen-lockfile

- name: Check formatting
run: pnpm format:check

- name: Lint
run: pnpm lint

- name: Typecheck
run: pnpm typecheck

- name: Test
run: pnpm test

- name: Build
run: pnpm build

- name: Validate Compose
run: docker compose config --quiet
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
node_modules/
.pnpm-store/
.turbo/
.next/
dist/
coverage/
.env
.env.*
!.env.example
*.log
.DS_Store
.idea/
.vscode/
83 changes: 83 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# LifeOS

**The open-source personal operating system for goals, projects, tasks, habits, and reviews.**

LifeOS connects everyday action to longer-term direction. It is designed as a multi-user, self-hostable SaaS with domain-oriented microservices, user-owned data, and auditable AI assistance.

## Status

LifeOS is in active foundation development. The current `develop` branch contains the initial monorepo, gateway, service skeletons, shared contracts, responsive web shell, PostgreSQL, and NATS JetStream configuration.

## Architecture

```text
Web / PWA
|
API Gateway / BFF
|---------------------------------------------|
Identity Planning Habit Review
| | | |
PostgreSQL schemas / databases + NATS JetStream events
```

The MVP deliberately keeps goals, projects, milestones, and tasks in one Planning bounded context. Services own their persistence boundaries; direct cross-service table access is prohibited.

## Repository layout

```text
apps/
web/
gateway/
identity-service/
planning-service/
habit-service/
review-service/
packages/
contracts/
infra/
docs/
```

## Prerequisites

- Node.js 22+
- pnpm 10+
- Docker with Compose

## Local development

```bash
cp .env.example .env
corepack enable
pnpm install
docker compose up -d
pnpm dev
```

Default endpoints:

- Web: `http://localhost:3000`
- Gateway health: `http://localhost:4000/v1/health`
- Gateway Today composition: `http://localhost:4000/v1/today`
- NATS monitoring: `http://localhost:8222`

## Authentication

Google and GitHub OAuth are the required login providers. Provider credentials are supplied through environment variables and must never be committed. OAuth flows are part of the next implementation slice; the current web actions are interface placeholders.

## Privacy

This is a public repository. It contains synthetic examples only. Personal goals, health information, relationship data, credentials, access tokens, and production exports must not be committed.

## Documentation

- Product and architecture design: `docs/superpowers/specs/2026-08-02-life-os-design.md`
- Foundation implementation plan: `docs/superpowers/plans/2026-08-02-life-os-foundation.md`

## Contributing

Development work targets `develop` and reaches `main` through reviewed pull requests. Keep service boundaries explicit, update contracts before consumers, add tests with behavior changes, and avoid introducing infrastructure that has no measured need.

## License

A project license will be selected before the first public release. Until then, the source is publicly visible but no license grant is implied.
26 changes: 26 additions & 0 deletions apps/gateway/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "@life-os/gateway",
"version": "0.1.0",
"private": true,
"scripts": {
"build": "nest build",
"dev": "nest start --watch",
"lint": "tsc --noEmit",
"test": "vitest run --passWithNoTests",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@life-os/contracts": "workspace:*",
"@nestjs/common": "^11.1.6",
"@nestjs/core": "^11.1.6",
"@nestjs/platform-express": "^11.1.6",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.2"
},
"devDependencies": {
"@nestjs/cli": "^11.0.10",
"@types/node": "^24.3.0",
"typescript": "^5.9.2",
"vitest": "^3.2.4"
}
}
23 changes: 23 additions & 0 deletions apps/gateway/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Controller, Get, Module } from '@nestjs/common';

@Controller()
class HealthController {
@Get('health')
health(): { status: 'ok'; service: 'gateway' } {
return { status: 'ok', service: 'gateway' };
}

@Get('today')
today(): { tasks: unknown[]; habits: unknown[]; message: string } {
return {
tasks: [],
habits: [],
message: 'Today composition endpoint is ready for domain-service integration.',
};
}
}

@Module({
controllers: [HealthController],
})
export class AppModule {}
24 changes: 24 additions & 0 deletions apps/gateway/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import 'reflect-metadata';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

function getAllowedOrigins(): string[] {
return (process.env.CORS_ALLOWED_ORIGINS ?? 'http://localhost:3000')
.split(',')
.map((origin) => origin.trim())
.filter(Boolean);
}

async function bootstrap(): Promise<void> {
const app = await NestFactory.create(AppModule);
app.enableCors({
origin: getAllowedOrigins(),
credentials: true,
});
app.setGlobalPrefix('v1');
app.enableShutdownHooks();
const port = Number(process.env.GATEWAY_PORT ?? 4000);
await app.listen(port, '0.0.0.0');
}

void bootstrap();
13 changes: 13 additions & 0 deletions apps/gateway/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"module": "CommonJS",
"moduleResolution": "Node",
"rootDir": "src",
"outDir": "dist",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"declaration": false
},
"include": ["src/**/*.ts"]
}
25 changes: 25 additions & 0 deletions apps/habit-service/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "@life-os/habit-service",
"version": "0.1.0",
"private": true,
"scripts": {
"build": "nest build",
"dev": "nest start --watch",
"lint": "tsc --noEmit",
"test": "vitest run --passWithNoTests",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@nestjs/common": "^11.1.6",
"@nestjs/core": "^11.1.6",
"@nestjs/platform-express": "^11.1.6",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.2"
},
"devDependencies": {
"@nestjs/cli": "^11.0.10",
"@types/node": "^24.3.0",
"typescript": "^5.9.2",
"vitest": "^3.2.4"
}
}
22 changes: 22 additions & 0 deletions apps/habit-service/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import 'reflect-metadata';
import { Controller, Get, Module } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';

@Controller()
class HealthController {
@Get('health')
health(): { status: 'ok'; service: 'habit-service' } {
return { status: 'ok', service: 'habit-service' };
}
}

@Module({ controllers: [HealthController] })
class AppModule {}

async function bootstrap(): Promise<void> {
const app = await NestFactory.create(AppModule);
app.enableShutdownHooks();
await app.listen(Number(process.env.HABIT_SERVICE_PORT ?? 4103), '0.0.0.0');
}

void bootstrap();
1 change: 1 addition & 0 deletions apps/habit-service/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"extends":"../../tsconfig.base.json","compilerOptions":{"module":"CommonJS","moduleResolution":"Node","rootDir":"src","outDir":"dist","experimentalDecorators":true,"emitDecoratorMetadata":true,"declaration":false},"include":["src/**/*.ts"]}
25 changes: 25 additions & 0 deletions apps/identity-service/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "@life-os/identity-service",
"version": "0.1.0",
"private": true,
"scripts": {
"build": "nest build",
"dev": "nest start --watch",
"lint": "tsc --noEmit",
"test": "vitest run --passWithNoTests",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@nestjs/common": "^11.1.6",
"@nestjs/core": "^11.1.6",
"@nestjs/platform-express": "^11.1.6",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.2"
},
"devDependencies": {
"@nestjs/cli": "^11.0.10",
"@types/node": "^24.3.0",
"typescript": "^5.9.2",
"vitest": "^3.2.4"
}
}
22 changes: 22 additions & 0 deletions apps/identity-service/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import 'reflect-metadata';
import { Controller, Get, Module } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';

@Controller()
class HealthController {
@Get('health')
health(): { status: 'ok'; service: 'identity-service' } {
return { status: 'ok', service: 'identity-service' };
}
}

@Module({ controllers: [HealthController] })
class AppModule {}

async function bootstrap(): Promise<void> {
const app = await NestFactory.create(AppModule);
app.enableShutdownHooks();
await app.listen(Number(process.env.IDENTITY_SERVICE_PORT ?? 4101), '0.0.0.0');
}

void bootstrap();
1 change: 1 addition & 0 deletions apps/identity-service/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"extends":"../../tsconfig.base.json","compilerOptions":{"module":"CommonJS","moduleResolution":"Node","rootDir":"src","outDir":"dist","experimentalDecorators":true,"emitDecoratorMetadata":true,"declaration":false},"include":["src/**/*.ts"]}
25 changes: 25 additions & 0 deletions apps/planning-service/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "@life-os/planning-service",
"version": "0.1.0",
"private": true,
"scripts": {
"build": "nest build",
"dev": "nest start --watch",
"lint": "tsc --noEmit",
"test": "vitest run --passWithNoTests",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@nestjs/common": "^11.1.6",
"@nestjs/core": "^11.1.6",
"@nestjs/platform-express": "^11.1.6",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.2"
},
"devDependencies": {
"@nestjs/cli": "^11.0.10",
"@types/node": "^24.3.0",
"typescript": "^5.9.2",
"vitest": "^3.2.4"
}
}
Loading
Loading