NextGraph integration (WIP), broker banner, and feature-based architecture
- Add NextGraph data layer with @ng-org/orm, SHEX shapes (Event, UserProfile, Participation), session management, and FestipodDataContext with dual-mode operation (connected via NextGraph or local seed data) - Add BrokerBanner and NgStatus components showing connection status - Refactor to feature-based architecture: organize code by business domain (event, user, home, auth, workshop, meeting, notification) instead of technical layer. Modules only import from shared/, never from each other - Collocate BDD features and step definitions with their modules: event-specific steps in event/steps/, user steps in user/steps/, shared generic steps remain in shared/steps/ - Set up multi-layer BDD structure (frontend/backend/e2e steps per module) - Add project documentation (AGENTS.md, .project/knowledge/) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Executable
+148
@@ -0,0 +1,148 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Build and install @ng-org packages from local nextgraph-rs repo.
|
||||
#
|
||||
# This script:
|
||||
# 1. git pull on nextgraph-rs
|
||||
# 2. Installs monorepo deps (pnpm install)
|
||||
# 3. Builds the 4 packages we need (tsc / vite)
|
||||
# 4. Packs them into tarballs (applies publishConfig -> dist/)
|
||||
# 5. Installs the tarballs in festipod and updates package.json versions
|
||||
#
|
||||
# Usage:
|
||||
# bash scripts/build-ng-packages.sh
|
||||
#
|
||||
# Run this after any nextgraph-rs update, or as needed.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
FESTIPOD_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
NEXTGRAPH_RS="${NEXTGRAPH_RS:-$(cd "$FESTIPOD_DIR/../../nextgraph/nextgraph-rs" && pwd)}"
|
||||
SDK_JS="$NEXTGRAPH_RS/sdk/js"
|
||||
TARBALLS_DIR="$FESTIPOD_DIR/.ng-tarballs"
|
||||
|
||||
# Packages to build (in dependency order)
|
||||
PACKAGES=(alien-deepsignals shex-orm web orm)
|
||||
|
||||
echo "=== @ng-org local build ==="
|
||||
echo " nextgraph-rs: $NEXTGRAPH_RS"
|
||||
echo " festipod: $FESTIPOD_DIR"
|
||||
echo ""
|
||||
|
||||
# --- Step 0: git pull ---
|
||||
echo "[0/5] Pulling latest nextgraph-rs..."
|
||||
cd "$NEXTGRAPH_RS"
|
||||
git pull --ff-only || echo " WARN: git pull failed (maybe uncommitted changes?) — continuing with current state"
|
||||
echo ""
|
||||
|
||||
# --- Step 1: Ensure lib-wasm/pkg stub exists ---
|
||||
LIB_WASM_PKG="$SDK_JS/lib-wasm/pkg"
|
||||
if [ ! -f "$LIB_WASM_PKG/package.json" ]; then
|
||||
echo "[1/5] Creating lib-wasm/pkg stub (type-only dependency)..."
|
||||
mkdir -p "$LIB_WASM_PKG"
|
||||
cat > "$LIB_WASM_PKG/package.json" << 'STUBEOF'
|
||||
{
|
||||
"name": "@ng-org/lib-wasm",
|
||||
"version": "0.0.0-stub",
|
||||
"type": "module",
|
||||
"main": "./index.js",
|
||||
"types": "./index.d.ts"
|
||||
}
|
||||
STUBEOF
|
||||
echo "export {};" > "$LIB_WASM_PKG/index.js"
|
||||
# Wildcard type stub: all methods are accepted via index signature
|
||||
cat > "$LIB_WASM_PKG/index.d.ts" << 'DTSEOF'
|
||||
// Stub types for @ng-org/lib-wasm (real build requires Rust/WASM)
|
||||
export declare function orm_start_graph(...args: any[]): any;
|
||||
export declare function orm_start_discrete(...args: any[]): any;
|
||||
export declare function graph_orm_update(...args: any[]): any;
|
||||
export declare function discrete_orm_update(...args: any[]): any;
|
||||
export declare function doc_create(...args: any[]): any;
|
||||
export declare function doc_subscribe(...args: any[]): any;
|
||||
export declare function file_get(...args: any[]): any;
|
||||
export declare function app_request_stream(...args: any[]): any;
|
||||
// Catch-all for any other methods
|
||||
declare const _extra: { [key: string]: (...args: any[]) => any };
|
||||
export default _extra;
|
||||
DTSEOF
|
||||
else
|
||||
echo "[1/5] lib-wasm/pkg stub already exists"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# --- Step 2: Install monorepo deps ---
|
||||
echo "[2/5] Installing monorepo dependencies..."
|
||||
cd "$NEXTGRAPH_RS"
|
||||
pnpm install --frozen-lockfile 2>/dev/null || pnpm install
|
||||
echo ""
|
||||
|
||||
# --- Step 3: Build each package ---
|
||||
echo "[3/5] Building packages..."
|
||||
for pkg in "${PACKAGES[@]}"; do
|
||||
PKG_DIR="$SDK_JS/$pkg"
|
||||
if [ ! -d "$PKG_DIR" ]; then
|
||||
echo " SKIP $pkg (directory not found)"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check if there's a build script
|
||||
HAS_BUILD=$(node -e "const p=require('$PKG_DIR/package.json'); process.stdout.write(p.scripts?.build ? '1' : '0')")
|
||||
if [ "$HAS_BUILD" = "0" ]; then
|
||||
# Try build:ts (orm, alien-deepsignals)
|
||||
HAS_BUILD_TS=$(node -e "const p=require('$PKG_DIR/package.json'); process.stdout.write(p.scripts?.['build:ts'] ? '1' : '0')")
|
||||
if [ "$HAS_BUILD_TS" = "1" ]; then
|
||||
echo " Building $pkg (build:ts)..."
|
||||
cd "$PKG_DIR"
|
||||
pnpm run build:ts
|
||||
else
|
||||
echo " SKIP $pkg (no build script)"
|
||||
fi
|
||||
else
|
||||
echo " Building $pkg (build)..."
|
||||
cd "$PKG_DIR"
|
||||
pnpm run build
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
|
||||
# --- Step 4: Pack each package ---
|
||||
echo "[4/5] Packing tarballs..."
|
||||
rm -rf "$TARBALLS_DIR"
|
||||
mkdir -p "$TARBALLS_DIR"
|
||||
|
||||
for pkg in "${PACKAGES[@]}"; do
|
||||
PKG_DIR="$SDK_JS/$pkg"
|
||||
if [ ! -d "$PKG_DIR/dist" ]; then
|
||||
echo " WARN: $pkg has no dist/ — skipping pack"
|
||||
continue
|
||||
fi
|
||||
cd "$PKG_DIR"
|
||||
TARBALL=$(pnpm pack --pack-destination "$TARBALLS_DIR" 2>/dev/null | tail -1)
|
||||
echo " Packed $pkg → $(basename "$TARBALL")"
|
||||
done
|
||||
echo ""
|
||||
|
||||
# --- Step 5: Install tarballs in festipod (one by one, in dependency order) ---
|
||||
echo "[5/5] Installing in festipod..."
|
||||
cd "$FESTIPOD_DIR"
|
||||
|
||||
# Install one by one to avoid Bun's dependency loop detection issue
|
||||
for pkg in "${PACKAGES[@]}"; do
|
||||
TGZ=$(ls "$TARBALLS_DIR"/ng-org-${pkg}-*.tgz 2>/dev/null | head -1)
|
||||
if [ -z "$TGZ" ]; then
|
||||
echo " WARN: no tarball for $pkg"
|
||||
continue
|
||||
fi
|
||||
echo " Installing @ng-org/$pkg..."
|
||||
bun add "$TGZ"
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "=== Done! All @ng-org packages installed from local build ==="
|
||||
echo ""
|
||||
echo "Installed versions:"
|
||||
for pkg in "${PACKAGES[@]}"; do
|
||||
VERSION=$(node -e "try{const p=require('$FESTIPOD_DIR/node_modules/@ng-org/$pkg/package.json');console.log(p.version)}catch{console.log('not found')}")
|
||||
echo " @ng-org/$pkg: $VERSION"
|
||||
done
|
||||
@@ -11,11 +11,23 @@ interface StepDefinition {
|
||||
lineNumber: number;
|
||||
}
|
||||
|
||||
const stepFiles = [
|
||||
'features/step_definitions/navigation.steps.ts',
|
||||
'features/step_definitions/form.steps.ts',
|
||||
'features/step_definitions/screen.steps.ts',
|
||||
];
|
||||
import { Glob } from 'bun';
|
||||
|
||||
// Discover all step definition files: shared + module-specific
|
||||
function discoverStepFiles(): string[] {
|
||||
const files: string[] = [];
|
||||
// Shared steps
|
||||
for (const f of new Glob('src/shared/steps/**/*.steps.ts').scanSync('.')) {
|
||||
files.push(f);
|
||||
}
|
||||
// Module steps
|
||||
for (const f of new Glob('src/modules/*/steps/**/*.steps.ts').scanSync('.')) {
|
||||
files.push(f);
|
||||
}
|
||||
return files.sort();
|
||||
}
|
||||
|
||||
const stepFiles = discoverStepFiles();
|
||||
|
||||
function extractStepDefinitions(): StepDefinition[] {
|
||||
const definitions: StepDefinition[] = [];
|
||||
@@ -115,7 +127,7 @@ export const stepDefinitions: StepDefinitionInfo[] = ${JSON.stringify(definition
|
||||
${findFunctionCode}
|
||||
`;
|
||||
|
||||
await Bun.write('src/data/stepDefinitions.ts', output);
|
||||
await Bun.write('src/shared/data/stepDefinitions.ts', output);
|
||||
console.log(`Generated ${definitions.length} step definitions`);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Glob } from 'bun';
|
||||
import type { ParsedFeature, ParsedScenario, ParsedStep } from '../src/types/gherkin';
|
||||
import type { ParsedFeature, ParsedScenario, ParsedStep } from '../src/shared/types/gherkin';
|
||||
|
||||
// Map French screen names to screen IDs (same as navigation.steps.ts)
|
||||
const screenNameMap: Record<string, string> = {
|
||||
@@ -73,7 +73,7 @@ function extractScreenIdsFromSteps(steps: ParsedStep[]): Set<string> {
|
||||
}
|
||||
|
||||
async function parseFeatures(): Promise<ParsedFeature[]> {
|
||||
const glob = new Glob('features/**/*.feature');
|
||||
const glob = new Glob('src/modules/*/features/**/*.feature');
|
||||
const features: ParsedFeature[] = [];
|
||||
|
||||
for await (const filePath of glob.scan('.')) {
|
||||
@@ -116,7 +116,7 @@ export function getAllPriorities(): number[] {
|
||||
}
|
||||
`;
|
||||
|
||||
await Bun.write('src/data/features.ts', output);
|
||||
await Bun.write('src/shared/data/features.ts', output);
|
||||
console.log(`Parsed ${features.length} feature files`);
|
||||
return features;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { FeatureTestStatus, ScenarioTestResult } from '../src/types/gherkin';
|
||||
import type { FeatureTestStatus, ScenarioTestResult } from '../src/shared/types/gherkin';
|
||||
|
||||
interface CucumberScenario {
|
||||
id: string;
|
||||
@@ -137,7 +137,7 @@ export function getTestSummary() {
|
||||
}
|
||||
`;
|
||||
|
||||
await Bun.write('src/data/testResults.ts', output);
|
||||
await Bun.write('src/shared/data/testResults.ts', output);
|
||||
console.log(`Generated test results for ${results.size} features`);
|
||||
|
||||
// Print summary
|
||||
|
||||
Reference in New Issue
Block a user