Scaffold the Before-M1 repo skeleton

Stand up the modular-monolith skeleton per docs/V1_BUILD_PLAN.md: one .NET 10
solution with web + worker hosts sharing seven interface-bounded module projects,
PostgreSQL 17 + pgvector via EF Core 10, a React 19 + Vite SPA built into wwwroot,
and Docker Compose for one-command local dev. Skeleton only — no feature code.

Architecture
- One project per module (OrgBoard, Identity, Skills, Assembler, Governance,
  Memory, Integrations); each is its own assembly so non-public types (entities,
  DbContext) are invisible across modules at compile time.
- TeamUp.Bootstrap is the only library that references all modules; both hosts
  reference only Bootstrap. SharedKernel/Infrastructure never reference modules.
- IModule seam: Register(...) runs in both hosts; MapEndpoints(...) only in web.
- PlatformDbContext owns the pgvector extension + the seven module schemas
  (InitialPlatform migration); MigrationRunner applies it then any module context.
- One image, two roles selected by RUN_MODE at the Docker entrypoint.

Verified
- dotnet build green (nullable + warnings-as-errors).
- ArchitectureTests 8/8 — reflection-based boundary rules (no module -> module,
  -> Infrastructure, -> Bootstrap, or -> host references).
- IntegrationTests 10/10 — Testcontainers boots the host against real pgvector:
  migration applies, vector extension + 7 schemas exist, /health 200, every
  /api/<module>/ping 200, /openapi/v1.json served.
- client builds clean (Vite 6 — pinned for Node 22.3.0; Vite 8 needs Node >=22.12).

Packages and base images route through the Nexus mirror (mirror.soroushasadi.com),
reachable from Iran when nuget.org / Docker Hub / MCR are not. CI is intentionally
deferred to a later session.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-09 06:41:28 +03:30
commit 36fe158b43
89 changed files with 7329 additions and 0 deletions
+44
View File
@@ -0,0 +1,44 @@
# syntax=docker/dockerfile:1
#
# One image, two roles. RUN_MODE (web|worker) selects the binary at the entrypoint.
# Build context is the repo root (see docker-compose.yml: context: ..).
# Base images are pulled through Soroush's Nexus Docker proxy group (mirror.soroushasadi.com),
# reachable from Iran. To build against public registries instead, replace the mirror prefixes
# with docker.io/library (node) and mcr.microsoft.com (dotnet).
# ---- Stage 1: build the React/Vite SPA ----
FROM mirror.soroushasadi.com/node:22-bookworm-slim AS client
WORKDIR /client
COPY client/package.json client/package-lock.json ./
RUN npm ci
COPY client/ ./
RUN npm run build
# ---- Stage 2: restore + publish BOTH hosts into /app ----
FROM mirror.soroushasadi.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY Directory.Build.props Directory.Packages.props nuget.config global.json ./
COPY src/ ./src/
RUN dotnet restore src/Hosts/TeamUp.Web/TeamUp.Web.csproj
RUN dotnet restore src/Hosts/TeamUp.Worker/TeamUp.Worker.csproj
# Skip the web project's npm client target (-p:BuildClient=false) — the SPA is built in stage 1.
RUN dotnet publish src/Hosts/TeamUp.Web/TeamUp.Web.csproj -c Release -o /app --no-restore -p:BuildClient=false
RUN dotnet publish src/Hosts/TeamUp.Worker/TeamUp.Worker.csproj -c Release -o /app --no-restore
# Drop the built SPA into the served wwwroot.
COPY --from=client /client/dist /app/wwwroot
# ---- Stage 3: runtime ----
# aspnet:10.0 (Ubuntu Noble) has a shell so the entrypoint can branch on RUN_MODE, and avoids any
# tag-availability risk. For prod you can switch to a chiseled tag and select the role via the
# container command/args instead (chiseled images have no shell).
FROM mirror.soroushasadi.com/dotnet/aspnet:10.0 AS final
WORKDIR /app
COPY --from=build /app ./
COPY docker/entrypoint.sh /app/entrypoint.sh
RUN chmod +x /app/entrypoint.sh
ENV RUN_MODE=web \
ASPNETCORE_HTTP_PORTS=8080
EXPOSE 8080
USER $APP_UID
ENTRYPOINT ["/app/entrypoint.sh"]