Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
c90e14b
chore(gitignore): ignore desktop build artifacts
adoumouangnamouemmanuel Aug 12, 2026
cd9c665
docs(readme): document desktop commands
adoumouangnamouemmanuel Aug 12, 2026
c89ba20
build(api): add sidecar packaging scripts
adoumouangnamouemmanuel Aug 12, 2026
8ce0ba4
build(api): configure sidecar native assets
adoumouangnamouemmanuel Aug 12, 2026
d1790f7
build(api): package sidecar executable
adoumouangnamouemmanuel Aug 12, 2026
ec88a07
test(api): add sidecar smoke verifier
adoumouangnamouemmanuel Aug 12, 2026
d7784bc
feat(api): emit sidecar readiness payload
adoumouangnamouemmanuel Aug 12, 2026
b4affd2
test(api): cover sidecar health security
adoumouangnamouemmanuel Aug 12, 2026
a251269
feat(api): secure local sidecar health
adoumouangnamouemmanuel Aug 12, 2026
de7a5ae
build(desktop): add Tauri commands
adoumouangnamouemmanuel Aug 12, 2026
d34b591
build(desktop): lock Tauri dependencies
adoumouangnamouemmanuel Aug 12, 2026
b0033d8
build(desktop): define Tauri shell crate
adoumouangnamouemmanuel Aug 12, 2026
373978f
build(desktop): add Tauri build script
adoumouangnamouemmanuel Aug 12, 2026
bed7634
build(desktop): add default capability set
adoumouangnamouemmanuel Aug 12, 2026
1fc1c8d
style(desktop): add Windows app icon
adoumouangnamouemmanuel Aug 12, 2026
5d99472
feat(desktop): launch hidden local sidecar
adoumouangnamouemmanuel Aug 12, 2026
16afde4
build(desktop): add Tauri entry point
adoumouangnamouemmanuel Aug 12, 2026
2c92fd0
build(desktop): configure Windows bundle
adoumouangnamouemmanuel Aug 12, 2026
36897f2
build(web): add Tauri API dependency
adoumouangnamouemmanuel Aug 12, 2026
80e6962
feat(web): show desktop sidecar status
adoumouangnamouemmanuel Aug 12, 2026
6c773b1
feat(web): read desktop deployment status
adoumouangnamouemmanuel Aug 12, 2026
d32160c
feat(web): localize desktop status
adoumouangnamouemmanuel Aug 12, 2026
155ec09
docs(roadmap): mark deployment spike progress
adoumouangnamouemmanuel Aug 12, 2026
73c2b00
docs(adr): record sidecar packaging decision
adoumouangnamouemmanuel Aug 12, 2026
de7639d
docs(deployment): add phase 1 spike runbook
adoumouangnamouemmanuel Aug 12, 2026
70a1208
chore(lint): ignore generated Tauri schemas
adoumouangnamouemmanuel Aug 12, 2026
aad5af7
build(root): add desktop scripts
adoumouangnamouemmanuel Aug 12, 2026
f68407d
chore(lint): include CommonJS configs
adoumouangnamouemmanuel Aug 12, 2026
dea21e9
build(db): update SQLite native dependency
adoumouangnamouemmanuel Aug 12, 2026
bbf3738
feat(db): add deployment probe migration
adoumouangnamouemmanuel Aug 12, 2026
940076b
feat(db): export deployment helpers
adoumouangnamouemmanuel Aug 12, 2026
1a7b0a5
build(pnpm): allow SQLite native build
adoumouangnamouemmanuel Aug 12, 2026
43a7761
build(deps): update workspace lockfile
adoumouangnamouemmanuel Aug 12, 2026
1754e45
docs(roadmap): complete deployment spike checklist
adoumouangnamouemmanuel Aug 12, 2026
b5fcbf2
feat(db): define foundation schema
adoumouangnamouemmanuel Aug 13, 2026
e109731
feat(db): add foundation migration
adoumouangnamouemmanuel Aug 13, 2026
05bd77a
chore(db): add foundation migration snapshot
adoumouangnamouemmanuel Aug 13, 2026
793ffb4
chore(db): update migration journal
adoumouangnamouemmanuel Aug 13, 2026
55897c6
feat(db): add sqlite client helper
adoumouangnamouemmanuel Aug 13, 2026
716fa89
feat(db): add tenant repository primitives
adoumouangnamouemmanuel Aug 13, 2026
659dc73
feat(db): add foundation seed data
adoumouangnamouemmanuel Aug 13, 2026
d09f2aa
feat(db): add foundation seed command
adoumouangnamouemmanuel Aug 13, 2026
39e7fba
test(db): cover foundation migration and tenancy
adoumouangnamouemmanuel Aug 13, 2026
62c551a
test(db): add vitest config
adoumouangnamouemmanuel Aug 13, 2026
728020f
feat(db): export foundation modules
adoumouangnamouemmanuel Aug 13, 2026
0f46b89
chore(db): add seed and test scripts
adoumouangnamouemmanuel Aug 13, 2026
e77c73a
chore: wire db seed and tests
adoumouangnamouemmanuel Aug 13, 2026
97211d5
docs(db): document foundation schema
adoumouangnamouemmanuel Aug 13, 2026
8643eb3
docs: add database seed command
adoumouangnamouemmanuel Aug 13, 2026
fa44b0a
docs(roadmap): mark phase 1.3 complete
adoumouangnamouemmanuel Aug 13, 2026
40bc121
chore(scripts): add git bash convenience wrappers
adoumouangnamouemmanuel Aug 13, 2026
75e6666
test(api): make clean-clone api tests use source aliases
adoumouangnamouemmanuel Aug 13, 2026
d1ed14b
ci: enable coderabbit reviews on develop
adoumouangnamouemmanuel Aug 13, 2026
5b3753f
chore(api): share sidecar capability header
adoumouangnamouemmanuel Aug 13, 2026
cbe0a91
security(api): require sidecar token in production
adoumouangnamouemmanuel Aug 13, 2026
98cb32f
test(api): cover sidecar capability checks
adoumouangnamouemmanuel Aug 13, 2026
ded2706
fix(api): handle sidecar startup failures
adoumouangnamouemmanuel Aug 13, 2026
3ea7500
fix(api): parse rust host tuple from version output
adoumouangnamouemmanuel Aug 13, 2026
01affe9
fix(api): harden sidecar verification cleanup
adoumouangnamouemmanuel Aug 13, 2026
dcc056a
security(desktop): require secure sidecar token randomness
adoumouangnamouemmanuel Aug 13, 2026
0039a1b
security(desktop): enable restrictive tauri csp
adoumouangnamouemmanuel Aug 13, 2026
9b67339
fix(db): reject async transaction callbacks
adoumouangnamouemmanuel Aug 13, 2026
8003213
test(db): guard transaction callback types
adoumouangnamouemmanuel Aug 13, 2026
8055332
fix(db): make deployment marker idempotent
adoumouangnamouemmanuel Aug 13, 2026
abc8fe4
security(db): project safe user columns
adoumouangnamouemmanuel Aug 13, 2026
556e669
fix(db): implement seed upgrade contract
adoumouangnamouemmanuel Aug 13, 2026
29d2891
fix(db): enforce sqlite role and audit constraints
adoumouangnamouemmanuel Aug 13, 2026
22c9d0b
test(db): cover migration and repository safeguards
adoumouangnamouemmanuel Aug 13, 2026
30dec90
feat(db): apply committed sqlite migrations
adoumouangnamouemmanuel Aug 13, 2026
f6f2a55
chore(db): use sqlite migrator for db:migrate
adoumouangnamouemmanuel Aug 13, 2026
fb97272
fix(scripts): trust command exit status
adoumouangnamouemmanuel Aug 13, 2026
1cb2953
docs(db): clarify schema metadata primary key
adoumouangnamouemmanuel Aug 13, 2026
586f08e
docs(readme): align command descriptions
adoumouangnamouemmanuel Aug 13, 2026
777093e
feat(db): add application migration helper
adoumouangnamouemmanuel Aug 13, 2026
c95ed07
chore(db): export application migrations
adoumouangnamouemmanuel Aug 13, 2026
a0d447f
chore(db): reuse application migration helper
adoumouangnamouemmanuel Aug 13, 2026
2d76f46
test(db): cover application migration helper
adoumouangnamouemmanuel Aug 13, 2026
e1f75f4
fix(api): migrate sqlite before readiness
adoumouangnamouemmanuel Aug 13, 2026
ffabca5
test(api): cover startup migration readiness
adoumouangnamouemmanuel Aug 13, 2026
bd6037e
build(api): package sqlite migrations in sidecar
adoumouangnamouemmanuel Aug 13, 2026
a67ec9c
test(api): verify sidecar application tables
adoumouangnamouemmanuel Aug 13, 2026
d3fe76e
test(db): normalize migration path assertion
adoumouangnamouemmanuel Aug 13, 2026
4c466ea
test(api): restore sqlite path env in startup test
adoumouangnamouemmanuel Aug 13, 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
4 changes: 4 additions & 0 deletions .coderabbit.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
reviews:
auto_review:
base_branches:
- develop
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
node_modules/
dist/
build/
apps/desktop/src-tauri/binaries/*
apps/desktop/src-tauri/gen/
apps/desktop/src-tauri/target/
.next/
.expo/
coverage/
Expand Down
74 changes: 70 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ Start only the API sidecar in watch mode:
pnpm --filter @edutrack/api run dev
```

Start the desktop shell in development mode:

```bash
pnpm --filter @edutrack/desktop run dev
```

## Quality Commands

```bash
Expand Down Expand Up @@ -97,7 +103,7 @@ Runs TypeScript project-reference checks across all active packages and apps.
pnpm run test
```

Runs the unit test suites for the API and web app.
Runs the unit test suites for the database package, API and web app.

```bash
pnpm run test:e2e
Expand All @@ -113,7 +119,19 @@ pnpm exec playwright install chromium
pnpm run build
```

Builds all active packages and apps.
Builds the shared packages, database package, API and web app. Desktop packaging is handled separately through `pnpm run build:desktop`.

```bash
pnpm run check:desktop
```

Builds the Windows sidecar executable and runs the Tauri/Rust compile check.

```bash
pnpm run verify:sidecar
```

Starts the packaged Windows sidecar, calls `/health` with the local capability header, and confirms the SQLite probe database is created.

## Database Commands

Expand All @@ -123,12 +141,20 @@ Generate SQLite migrations from the Drizzle schema:
pnpm run db:generate
```

Push the SQLite schema to the configured local database:
Apply committed SQLite migrations to the configured local database:

```bash
pnpm run db:migrate
```

For local schema prototyping only, `pnpm --filter @edutrack/db run db:push` can push the current Drizzle schema without using committed migrations.

Seed deterministic Phase 1 foundation data:

```bash
pnpm run db:seed
```

By default, local SQLite uses:

```text
Expand All @@ -137,6 +163,34 @@ By default, local SQLite uses:

Override it with `EDUTRACK_SQLITE_PATH` in `.env`.

## Git Bash Convenience Scripts

These scripts only group existing `pnpm` commands for local development convenience. The source of truth remains the `package.json` scripts above.

```bash
./scripts/db-setup.sh
```

Creates `.data`, runs migrations, seeds foundation data and prints the SQLite path for DBeaver.

```bash
./scripts/db-fresh.sh
```

Resets only the local development SQLite database after an explicit `RESET` confirmation, then migrates and seeds again.

```bash
./scripts/dev-verify.sh
```

Runs formatting check, lint, typecheck, unit tests and production build.

```bash
./scripts/phase-1-check.sh
```

Runs the current Phase 1 verification flow, including database setup, sidecar verification and desktop checks.

## Package-Specific Commands

```bash
Expand All @@ -151,11 +205,21 @@ Runs web-only development, build, tests, and preview.
```bash
pnpm --filter @edutrack/api run dev
pnpm --filter @edutrack/api run build
pnpm --filter @edutrack/api run build:sidecar
pnpm --filter @edutrack/api run verify:sidecar
pnpm --filter @edutrack/api run start
pnpm --filter @edutrack/api run test
```

Runs API-only development, build, compiled start, and tests.
Runs API-only development, build, packaged Windows sidecar build, packaged sidecar verification, compiled start, and tests.

```bash
pnpm --filter @edutrack/desktop run dev
pnpm --filter @edutrack/desktop run check
pnpm --filter @edutrack/desktop run build
```

Runs the Tauri desktop shell, sidecar-backed Rust/Tauri compile check, and Windows installer build.

```bash
pnpm --filter @edutrack/domain run build
Expand Down Expand Up @@ -185,3 +249,5 @@ docs/
## Version 1 Scope Notes

Version 1 is local and SQLite-only. Next.js, mobile apps, cloud sync, PostgreSQL runtime configuration, finance, attendance, parent/student portals, notifications, and remote web access are intentionally out of scope unless a later ADR approves them.

The Phase 1 deployment spike is documented in `docs/deployment/phase-1-deployment-spike.md`.
5 changes: 5 additions & 0 deletions apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,22 @@
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "tsc",
"build:sidecar": "pnpm --filter @edutrack/shared run build && pnpm --filter @edutrack/db run build && pnpm run build && node scripts/build-sidecar.mjs",
"verify:sidecar": "node scripts/verify-sidecar.mjs",
"start": "node dist/index.js",
"typecheck": "tsc -p tsconfig.json --noEmit",
"test": "vitest run --config vitest.config.ts"
},
"dependencies": {
"@edutrack/db": "workspace:*",
"@edutrack/shared": "workspace:*",
"better-sqlite3": "13.0.2",
"fastify": "^4.26.0"
},
"devDependencies": {
"@types/node": "^24.10.1",
"@yao-pkg/pkg": "6.22.0",
"esbuild": "0.28.2",
"tsx": "^4.23.12",
"typescript": "^5.9.3"
}
Expand Down
7 changes: 7 additions & 0 deletions apps/api/pkg.sidecar.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
assets: [
'node_modules/better-sqlite3/prebuilds/win32-x64.node',
'../../packages/db/migrations/sqlite/**/*',
],
publicPackages: ['better-sqlite3'],
};
106 changes: 106 additions & 0 deletions apps/api/scripts/build-sidecar.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { spawnSync } from 'node:child_process';
import { mkdirSync } from 'node:fs';
import { createRequire } from 'node:module';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { build } from 'esbuild';

const require = createRequire(import.meta.url);
const scriptDir = dirname(fileURLToPath(import.meta.url));
const packageRoot = resolve(scriptDir, '..');
const workspaceRoot = resolve(packageRoot, '..', '..');
const binariesDir = join(workspaceRoot, 'apps', 'desktop', 'src-tauri', 'binaries');
const sidecarName = 'edutrack-api-sidecar';
const pkgCliPath = require.resolve('@yao-pkg/pkg/lib-es5/bin.js');
const bundledEntryPath = join(packageRoot, 'dist', 'sidecar.cjs');
const pkgConfigPath = join(packageRoot, 'pkg.sidecar.config.cjs');

const rustcVersion = commandOutput('rustc', ['-vV']);
const targetTriple = parseRustHostTriple(rustcVersion);

if (!targetTriple.endsWith('windows-msvc')) {
throw new Error(
`The Phase 1.2 sidecar spike currently targets Windows MSVC, got ${targetTriple}.`
);
}
Comment thread
adoumouangnamouemmanuel marked this conversation as resolved.

mkdirSync(binariesDir, { recursive: true });

const outputPath = join(binariesDir, `${sidecarName}-${targetTriple}.exe`);

await build({
entryPoints: [join(packageRoot, 'dist', 'index.js')],
bundle: true,
platform: 'node',
target: 'node24',
format: 'cjs',
external: ['better-sqlite3'],
outfile: bundledEntryPath,
logLevel: 'info',
logOverride: {
'empty-import-meta': 'silent',
},
});

run(process.execPath, [
pkgCliPath,
bundledEntryPath,
'--config',
pkgConfigPath,
'--targets',
'node24-win-x64',
'--output',
outputPath,
]);

console.log(`Built ${outputPath}`);

function commandOutput(command, args) {
const result = spawnSync(command, args, {
cwd: workspaceRoot,
encoding: 'utf8',
});

if (result.status !== 0) {
throw new Error(commandFailureMessage(command, args, result));
}

return result.stdout.trim();
}

function run(command, args) {
const result = spawnSync(command, args, {
cwd: packageRoot,
stdio: 'inherit',
});

if (result.status !== 0) {
throw new Error(commandFailureMessage(command, args, result));
}
}

function parseRustHostTriple(rustcVersion) {
const hostLine = rustcVersion.split(/\r?\n/).find((line) => line.startsWith('host:'));

if (!hostLine) {
throw new Error('Could not determine the Rust host triple from rustc -vV output.');
}

const hostTriple = hostLine.slice('host:'.length).trim();

if (!hostTriple) {
throw new Error('Rust host triple was empty in rustc -vV output.');
}

return hostTriple;
}

function commandFailureMessage(command, args, result) {
const invocation = `${command} ${args.join(' ')}`;

if (result.error) {
return `Command failed: ${invocation}\n${result.error.name}: ${result.error.message}`;
}

return result.stderr?.trim() || `Command failed: ${invocation}`;
}
Loading
Loading