Skip to content

feat: ship runnable self-hosted demo - #3

Open
henkas wants to merge 9 commits into
mainfrom
v0-3-runnable-demo
Open

feat: ship runnable self-hosted demo#3
henkas wants to merge 9 commits into
mainfrom
v0-3-runnable-demo

Conversation

@henkas

@henkas henkas commented Mar 24, 2026

Copy link
Copy Markdown
Owner

Summary

  • add a runnable Hono + SQLite demo API with seeded mock data, scheduler persistence, and schedule/task endpoints
  • add a Next.js dashboard with today's schedule, task queue, and a manual reschedule action wired to the live API
  • add package Dockerfiles, clean up compose files, refresh the current-state docs, and lock API tests to src files so built artifacts do not re-run tests

Test Plan

Copilot AI review requested due to automatic review settings March 24, 2026 21:00

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR pivots the repo from the legacy v0.1 macOS CLI/TUI implementation to a runnable self-hosted demo built as a pnpm monorepo: @schedyx/core (deterministic scheduler), @schedyx/api (Hono + SQLite + scheduler daemon), and @schedyx/web (Next.js dashboard consuming the live API).

Changes:

  • Remove legacy CLI/TUI/AppleScript adapter code and root-level TS/Vitest config, replacing with per-package configs.
  • Add runnable demo stack: SQLite persistence + seeded fixtures + scheduler cycle + Hono routes + Next.js dashboard with a manual reschedule action.
  • Add Dockerfiles/Compose wiring and refresh docs to reflect current architecture and usage.

Reviewed changes

Copilot reviewed 92 out of 104 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
vitest.config.ts Removed legacy root Vitest config (moved to package-level).
tsconfig.json Removed legacy root TS config (moved to package-level).
src/tui/utils.ts Removed legacy Ink TUI utility module.
src/tui/types.ts Removed legacy Ink TUI types.
src/tui/index.tsx Removed legacy Ink TUI entrypoint.
src/tui/components/TaskQueue.tsx Removed legacy Ink TUI component.
src/tui/components/StatusBar.tsx Removed legacy Ink TUI component.
src/tui/components/Section.tsx Removed legacy Ink TUI component.
src/tui/components/HelpScreen.tsx Removed legacy Ink TUI component.
src/tui/components/BlockList.tsx Removed legacy Ink TUI component.
src/tui/actions.ts Removed legacy TUI action layer.
src/tui/App.tsx Removed legacy Ink TUI app.
src/cli/index.ts Removed legacy CLI entrypoint.
src/cli/commands/tui.ts Removed legacy CLI TUI command.
src/cli/commands/reconcile.ts Removed legacy CLI reconcile command.
src/cli/commands/plan.ts Removed legacy CLI plan command.
src/cli/commands/init.ts Removed legacy CLI init wizard.
src/cli/commands/commands.test.ts Removed legacy CLI command tests.
src/cli/commands/clear.ts Removed legacy CLI clear command.
src/cli/commands/check.ts Removed legacy CLI check command.
src/cli/commands/apply.ts Removed legacy CLI apply command.
src/adapters/reminders/reminders-applescript.ts Removed legacy AppleScript Reminders adapter.
src/adapters/index.ts Removed legacy adapter resolver.
src/adapters/calendar/applescript.ts Removed legacy AppleScript Calendar adapter.
src/adapters/applescript-adapters.test.ts Removed legacy AppleScript adapter tests.
pnpm-workspace.yaml Added pnpm workspace definition and native-build allowlist.
packages/web/tsconfig.json Added Next.js/React TS config for web package.
packages/web/src/lib/api.ts Added typed fetch helpers for demo API.
packages/web/src/components/task-queue.tsx Added task queue UI component.
packages/web/src/components/schedule-list.tsx Added schedule list UI component.
packages/web/src/components/reschedule-button.tsx Added client-side reschedule trigger.
packages/web/src/app/page.tsx Added demo dashboard page consuming API.
packages/web/src/app/layout.tsx Added root layout + metadata.
packages/web/src/app/globals.css Added demo styling.
packages/web/package.json Added web package manifest/scripts/deps.
packages/web/next.config.ts Configured output tracing root for monorepo deploy.
packages/web/next-env.d.ts Added Next.js TS env types.
packages/web/Dockerfile.dev Added dev Dockerfile for web.
packages/web/Dockerfile Added prod Dockerfile for web.
packages/web/.eslintrc.cjs Added web ESLint config extending root + Next rules.
packages/core/vitest.config.ts Added core package Vitest config.
packages/core/tsconfig.json Added core package TS config (emit declarations/maps).
packages/core/src/validation.ts Added shared validation/sanitization helpers.
packages/core/src/time.ts Added timezone + local date/time formatting helpers.
packages/core/src/reconcile.ts Adjusted config import to type-only.
packages/core/src/reconcile.test.ts Added reconcile unit tests in core package.
packages/core/src/planner.ts Adjusted config import to type-only.
packages/core/src/planner.test.ts Added planner unit tests in core package.
packages/core/src/notes.ts Added #autoblock note helpers.
packages/core/src/models.ts Added shared domain model types.
packages/core/src/locking.ts Added locking logic to flip free based on lockAt.
packages/core/src/locking.test.ts Added locking unit tests in core package.
packages/core/src/index.ts Added public exports for core package.
packages/core/src/config.ts Added shared config type.
packages/core/package.json Added core package manifest/scripts/exports.
packages/api/vitest.config.ts Added API package Vitest config.
packages/api/tsconfig.json Added API package TS config.
packages/api/src/services/scheduler-service.ts Added scheduler cycle + snapshot helpers (core integration + persistence).
packages/api/src/services/scheduler-service.test.ts Added scheduler service unit test.
packages/api/src/scheduler/daemon.ts Added cron-based scheduler daemon.
packages/api/src/routes/tasks.ts Added GET /tasks route.
packages/api/src/routes/schedule.ts Added schedule snapshot + manual run routes.
packages/api/src/routes/health.ts Added health route.
packages/api/src/mock/seed-demo-data.ts Added seed-on-empty + fixture rebasing.
packages/api/src/mock/seed-demo-data.test.ts Added seed/rebase unit test.
packages/api/src/mock/demo-fixtures.ts Added demo task/event fixtures.
packages/api/src/index.ts Added API server bootstrap + seeding + daemon startup.
packages/api/src/env.ts Added env parsing for server/db/scheduler settings.
packages/api/src/db/schema.ts Added SQLite schema for demo state.
packages/api/src/db/repositories/tasks-repository.ts Added task persistence/query helpers.
packages/api/src/db/repositories/events-repository.ts Added event persistence/query helpers.
packages/api/src/db/repositories/blocks-repository.ts Added block persistence + meta storage helpers.
packages/api/src/db/client.ts Added better-sqlite3 client + schema init.
packages/api/src/db/client.test.ts Added DB initialization + repository round-trip test.
packages/api/src/app.ts Added Hono app wiring for routes.
packages/api/src/app.test.ts Added API route integration tests.
packages/api/package.json Added API package manifest/scripts/deps.
packages/api/Dockerfile.dev Added dev Dockerfile for API.
packages/api/Dockerfile Added prod Dockerfile for API.
package.json Converted root to monorepo scripts/devDeps and bumped version.
docs/superpowers/plans/2026-03-24-v0-3-runnable-self-hosted-demo.md Added detailed implementation plan doc for v0.3 demo.
docs/VISION.md Added product vision document for new direction.
docs/TECH_SPEC.md Marked legacy TECH_SPEC and added pointers to current docs.
docs/STATUS.md Rewrote status doc for runnable demo baseline.
docs/ROADMAP.md Rewrote roadmap starting post-v0.3 demo baseline.
docs/QUICKSTART.md Marked legacy quickstart guide.
docs/PHASE0.md Added historical monorepo migration record.
docs/ONBOARDING.md Marked legacy onboarding doc.
docs/FEATURES.md Marked legacy features doc.
docs/EXECUTION_PLAN.md Marked legacy execution plan doc.
docs/DEVELOPMENT.md Updated dev docs for monorepo + API/web demo + Docker flows.
docs/CHANGELOG.md Updated changelog framing around monorepo and demo milestones.
docs/ARCHITECTURE.md Updated architecture doc to reflect new package layout and demo flows.
docker-compose.yml Added runnable prod-style compose for API + web.
docker-compose.dev.yml Added runnable dev-style compose with source mounts.
README.md Updated README for self-hosted demo and current package layout.
CLAUDE.md Added AI session context doc.
AGENTS.md Added AI session context doc (duplicate content).
.gitignore Updated ignore rules for Next/TS/pnpm artifacts.
.github/workflows/ci.yml Updated CI to Ubuntu + pnpm + core build/test + lint/typecheck.
.eslintrc.cjs Enabled JSX parsing and ignored .next/.
.dockerignore Added Docker ignore rules for monorepo artifacts.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/api/src/app.ts
Comment on lines +7 to +12
export function createApp(db: SqliteDatabase) {
const app = new Hono();

registerHealthRoute(app);
registerTaskRoutes(app, db);
registerScheduleRoutes(app, db);

Copilot AI Mar 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The web dashboard triggers POST /schedule/run from a client component (browser) on http://localhost:3000 to the API on http://localhost:3001. The API currently doesn’t set CORS headers, so browsers will block this request (preflight/Origin mismatch). Add explicit CORS handling in the API (e.g., Hono CORS middleware) to allow the web origin(s) used in dev and Docker, or alternatively proxy the call through the Next.js app to keep it same-origin.

Copilot uses AI. Check for mistakes.
Comment on lines +16 to +20
onClick={() => {
startTransition(async () => {
await fetch(`${apiBase}/schedule/run`, { method: "POST" });
router.refresh();
});

Copilot AI Mar 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reschedule click handler doesn’t check response.ok (or handle exceptions) before calling router.refresh(), so failures (including CORS/network errors) will be silent and leave the UI stale. Consider surfacing an error state and only refreshing after a successful POST, or at least guarding with an if (!res.ok) path.

Copilot uses AI. Check for mistakes.
Comment on lines +52 to +55
export function readScheduleSnapshot(db: SqliteDatabase, now: Date = new Date()) {
return {
date: now.toISOString().slice(0, 10),
blocks: listBlocks(db),

Copilot AI Mar 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

readScheduleSnapshot computes date via now.toISOString().slice(0, 10) (UTC date), but runSchedulerCycle returns plan.date which is derived from local date logic in @schedyx/core (formatLocalDate). These can diverge around midnight/timezones and make /schedule/today and /schedule/run disagree. Use the same date derivation as the planner (e.g., formatLocalDate(now) from @schedyx/core) so both endpoints report a consistent “today”.

Copilot uses AI. Check for mistakes.
Comment thread packages/api/src/env.ts
Comment on lines +1 to +7
export function readEnv() {
return {
host: process.env.HOST ?? "0.0.0.0",
port: Number(process.env.PORT ?? "3001"),
databasePath: process.env.DATABASE_PATH ?? "./schedyx-demo.db",
schedulerIntervalMinutes: Number(process.env.SCHEDULER_INTERVAL_MINUTES ?? "15"),
};

Copilot AI Mar 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

readEnv parses numeric env vars with Number(...) but doesn’t handle NaN (e.g., PORT=abc, SCHEDULER_INTERVAL_MINUTES=abc). That can propagate into server startup and cron scheduling and fail at runtime. Consider validating/clamping here (defaulting when Number.isFinite(...) is false) so invalid env doesn’t crash the demo.

Copilot uses AI. Check for mistakes.
Comment on lines +5 to +9
export function startSchedulerDaemon(db: SqliteDatabase, intervalMinutes: number) {
const safeInterval = Math.max(1, intervalMinutes);
return cron.schedule(`*/${safeInterval} * * * *`, () => {
runSchedulerCycle(db, new Date());
});

Copilot AI Mar 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

safeInterval can become NaN if intervalMinutes is NaN, and values >59 produce an invalid cron minute field (e.g., */90 * * * *). This will make cron.schedule(...) throw or misbehave. Clamp/validate intervalMinutes (finite, 1–59) and fall back to a default when invalid.

Copilot uses AI. Check for mistakes.
Comment on lines +90 to +100
export function getLastUnscheduled(db: SqliteDatabase): Task[] {
const row = db
.prepare("SELECT value FROM app_meta WHERE key = ?")
.get(LAST_UNSCHEDULED_KEY) as { value?: string } | undefined;

if (!row?.value) {
return [];
}

return JSON.parse(row.value) as Task[];
}

Copilot AI Mar 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getLastUnscheduled does a raw JSON.parse of the persisted meta value. If the DB is corrupted or an old value is present, this will throw and can break /schedule/today and /schedule/run. Wrap parsing in a try/catch (return [] on failure) and consider validating the decoded shape before returning it as Task[].

Copilot uses AI. Check for mistakes.
Comment thread pnpm-workspace.yaml
Comment on lines +1 to +7
packages:
- "packages/*"
allowBuilds:
better-sqlite3: true
esbuild: true
sharp: true
unrs-resolver: true

Copilot AI Mar 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

allowBuilds is only supported in pnpm >=10.26.0; with earlier pnpm v10 releases (and pnpm v9), it will be ignored, which can reintroduce install failures for native deps like better-sqlite3. Either switch this to onlyBuiltDependencies (array) for broader compatibility, or pin pnpm in CI/dev images to >=10.26.0 to guarantee allowBuilds is honored.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants