Skip to content

Chore/monorepo - #18

Merged
Bebaz0 merged 11 commits into
mainfrom
chore/monorepo
Sep 19, 2026
Merged

Bebaz0 merged 11 commits into
mainfrom
chore/monorepo

Conversation

@Bebaz0

@Bebaz0 Bebaz0 commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

What changes

Turns this repo into the monorepo for the ACM FEUP site and the ACM Platform API. The site moves to apps/web with its git history preserved, a NestJS API joins it in apps/api, and local development and CI are set up so several people can start working. No features and no deploy: this is structure, tooling and docs only.

One commit per stage, meant to be reviewed commit by commit:

Commit Stage
2daa7d6, a3f7020 Monorepo: pnpm workspaces, Turborepo, shared config in packages/config, Node 24 and pnpm 12 pinned
2d6e503 API: NestJS app with a single GET /health that runs select 1
1c43421 Database: Postgres 18 in Docker Compose, Drizzle, first migration
132e194 Rename the workspace scope from @plataforma to @acmfeup
c02021b /status page on the site, calling the API from the browser
bd5fdd6 Lefthook pre-commit, Vitest, and the PR pipeline in .github/workflows/pr.yml
acc9009 README, CONTRIBUTING and AGENTS.md

Decisions worth knowing before reviewing:

  • Biome stays as linter and formatter, shared from packages/config. No ESLint or Prettier.
  • One .env at the repo root, optional: every value has a local default, so a fresh clone runs without one.
  • linter.yml is gone. pr.yml runs lint, typecheck, test and build, plus a migrations job (every migration applied to an empty Postgres, and a check that db:generate produces nothing) and a gitleaks secret scan.

How to test

pnpm install
docker compose up -d --wait
pnpm db:migrate
pnpm dev

Then open http://localhost:3000/status: both API and Database should read Connected.

Verified locally:

  • Following only the README in a clean folder, with an empty pnpm store and no cached Docker image: everything running in 7m55s, almost all of it downloads.
  • pnpm lint, pnpm typecheck, pnpm test and pnpm build pass at the root, also on a clean copy with CI=true and --frozen-lockfile.
  • The migrations job logic against a throwaway Postgres: applies from scratch, passes with no drift, fails when schema.ts changes without a migration.
  • Gitleaks 8.30.1 over the full history: no findings. A fake token in a throwaway repo was caught.

Before merging

  • Vercel Root Directory set to apps/web. Without it, the first production deploy from main breaks acmfeup.eu.
  • GITLEAKS_LICENSE added as an org secret (acmfeup is an organisation, so the action needs its free license). The gitleaks job stays red until then.
  • CI green.

Expected, not bugs

  • The Vercel preview for this branch will most likely fail until the Root Directory changes. Production is not affected.
  • acmfeup.eu/status will read Unreachable until the API is deployed. It is noindex.
  • health_check is a placeholder table, so the migration pipeline has something to apply. The first PR with a real table should drop it.
  • Out of scope, for later PRs: auth, email, observability, infrastructure, and the API deploy (including running migrations in production).

After merging

Anyone with an existing checkout should delete the old root node_modules and .next and run pnpm install again.

Checklist

  • I can explain every change in this PR during review, including code an agent wrote
  • Tests cover the logic I added (parseCorsOrigins, cn)
  • Migrations are backwards compatible (the first one only creates a table)
  • No merged migration was edited
  • No secrets, tokens or real credentials in the diff

Bebaz0 and others added 8 commits September 18, 2026 00:12
Move the Next.js site to apps/web with git mv so history is preserved,
and turn the repo root into the monorepo root for the ACM platform.

- pnpm-workspace.yaml with apps/* and packages/*; the previous file only
  held an invalid allowBuilds placeholder
- root package.json with dev/build/lint/typecheck/test/format
  delegating to turbo
- pin Node 24 (.nvmrc + engines) and pnpm 12.4.2 (packageManager)
- turbo.json: build dependsOn ^build, dev non-cached and persistent
- packages/config with the shared tsconfig base and Biome config;
- .gitignore paths unanchored so they match nested workspaces
Move the Next.js site to apps/web with git mv so the history follows it,
and turn the repo root into the monorepo root for the ACM platform.

- pnpm-workspace.yaml listing apps/* and packages/*; the previous file was
  unusable, it only held an allowBuilds placeholder string and no packages key
- root package.json with dev/build/lint/typecheck/test/format on turbo
- pin Node 24 (.nvmrc + engines) and pnpm 12.4.2 (packageManager)
- turbo.json: build dependsOn ^build, dev non-cached and persistent
- packages/config holds the shared tsconfig base and Biome config; the repo
  stays on Biome instead of moving to ESLint + Prettier
- nested Biome configs need root: false and resolve the shared config through
  the @plataforma/config specifier, a relative path does not resolve
- unanchor the .gitignore paths so they match nested workspaces, and ignore
  .idea/

No Vercel change here. The Root Directory has to move to apps/web before
this lands on main.
apps/api is a hand written NestJS 12 app rather than a nest new scaffold,
which would have pulled in ESLint, Prettier and Jest that this repo does
not use.

- GET /health runs select 1 and reports both the api and the database:
  200 {status: ok, db: up}, or 503 {status: degraded, db: down}
- API_PORT configures the port, 4000 by default
- CORS_ORIGIN is a comma separated list, parsed by parseCorsOrigins, which
  falls back to the local web app so a fresh clone works with no env file
- src/db/client.ts exports the pg pool; Drizzle goes on top of it next
- useImportType is off for this package: import type would erase the
  metadata Nest reads to resolve constructor dependencies

The endpoint answers 503 until the database lands in the next commit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
  docker-compose.yml runs Postgres 18 with a named volume and a pg_isready
  healthcheck, and apps/api talks to it through Drizzle.

  - src/config/env.ts loads the root .env with Node's own loadEnvFile and
    defaults to the compose credentials, so a fresh clone needs no .env
  - schema.ts holds a single placeholder health_check table; the first PR
    with a real table should drop it
  - 0000_keen_white_queen.sql is the baseline migration, and re-running
    db:generate produces nothing, which is what CI will assert
  - db:generate, db:migrate, db:studio, db:seed and db:reset, on the api
    package and mirrored at the root
  - db:seed builds first: node cannot run src/db/seed.ts directly, type
    stripping treats it as ESM and demands file extensions
  - Postgres 18 moved its volume to /var/lib/postgresql
  - drizzle/ is excluded from Biome so the formatter does not fight
    drizzle-kit output

 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Rename the workspace packages and the local dev database from plataforma
to acmfeup, which matches the organisation name and reads more naturally
for contributors.

- @plataforma/{web,api,config} become @acmfeup/{web,api,config}, and the
  root package and the db:* filters follow
- the Docker container, database, user and password become acmfeup, with
  .env.example and the DATABASE_URL default in env.ts updated to match

The database credentials changed, so an existing local volume still holds
the old user: run pnpm db:reset once after pulling.
  /status calls the API's /health from the browser and shows whether the
  API and the database are reachable. It is the end to end check for local
  setup and the reference for how the web app calls the API.

  - the request runs client side on purpose so it also exercises CORS
  - next.config.ts loads the root .env, since Next only reads its own
    folder and NEXT_PUBLIC_API_URL has to be there when it gets inlined
  - turbo hashes .env and NEXT_PUBLIC_API_URL so a changed API URL cannot
    replay a stale build, and dev passes the runtime vars through
  - noindex, it is a diagnostic page
  - lefthook runs biome check --write on staged files before each commit;
    its own postinstall installs the hook on pnpm install and skips CI
  - vitest in web and api with one example test each; tsconfig.build.json
    keeps test files out of the api's dist, which vitest 5 no longer skips
  - pr.yml runs lint, typecheck, test and build as a matrix with pnpm and
    turbo caches, and cancels superseded runs on the same PR
  - the migrations job applies every migration to an empty Postgres, then
    fails if db:generate leaves any file behind; it checks git status
    rather than git diff, since a new migration is an untracked file
  - gitleaks runs through the official action and needs the
    GITLEAKS_LICENSE org secret, as acmfeup is an organisation
  - issue forms for features and bugs, a PR template and CODEOWNERS
  - linter.yml is gone, the lint job replaces it

  Co-Authored-By: Claude
- README replaces the create-next-app template: what the repo is, the
  four commands to get running, and the everyday scripts
- setup uses docker compose up -d --wait: without --wait, db:migrate raced
  Postgres' first start and failed 2 out of 3 times, with no error printed
- CONTRIBUTING covers issue to merge, the Definition of Ready, the seven
  day rule for draft PRs, and the migration rules
- AGENTS.md sets the conventions for every coding agent, starting with
  the rule that whoever opens a PR must be able to explain it in review;
  CLAUDE.md only imports it, since Claude Code does not read AGENTS.md

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 19, 2026 01:13
@vercel

vercel Bot commented Sep 19, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
new-website Ready Ready Preview Sep 19, 2026 4:59pm UTC

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

The current diff introduces build/CI blockers (invalid GitHub Action versions, missing React type imports, and invalid/nested HTML structure in Next layout/404 link button).

Review effort: Lite
Findings: None

What changed in this PR

Converts the repository into a pnpm + Turborepo monorepo containing the ACM FEUP Next.js website (apps/web) and a new NestJS + Drizzle + Postgres API (apps/api), with shared lint/typecheck config, local Docker Postgres, and CI/automation for multi-package development.

Changes:

  • Added monorepo tooling (pnpm workspaces, Turborepo tasks, shared Biome/tsconfig in packages/config) and standardized root scripts.
  • Introduced a NestJS API with a /health endpoint, Drizzle schema + initial migration, and root .env loading defaults.
  • Added web app structure and UI (status page, components, assets), plus CI workflow and repo contribution/agent docs.
File Description
turbo.json Turborepo pipeline configuration (tasks, outputs, env passthrough).
README.md Monorepo-focused setup and command documentation.
pnpm-workspace.yaml Workspace package discovery + allowBuilds configuration.
packages/​config/​tsconfig.base.json Shared TypeScript base config for all packages.
packages/​config/​package.json Shared config package metadata.
packages/​config/​biome.json Shared Biome configuration.
package.json Root scripts + pinned package manager and engines for monorepo orchestration.
lefthook.yml Pre-commit Biome formatting/linting for staged files.
docker-compose.yml Local Postgres service for API/database development.
CONTRIBUTING.md Contribution workflow + migration and secret-handling guidelines.
CLAUDE.md Agent instruction pointer to @AGENTS.md.
biome.json Root Biome config now extends shared config.
apps/​web/​tsconfig.json Web tsconfig now extends shared base.
apps/​web/​src/​lib/​utils.ts Adds cn utility for className composition.
apps/​web/​src/​lib/​utils.test.ts Adds Vitest coverage for cn.
apps/​web/​src/​components/​ui/​card.tsx Adds shared Card UI primitives.
apps/​web/​src/​components/​ui/​button.tsx Adds shared Button component (variants + asChild).
apps/​web/​src/​components/​DepartmentCard.tsx Adds department card component used on the home page.
apps/​web/​src/​components/​Countdown.tsx Adds countdown/timer component rendered on the home page.
apps/​web/​src/​app/​status/​status-check.tsx Client-side API/DB status check UI and fetch logic.
apps/​web/​src/​app/​status/​page.tsx /status page shell and metadata.
apps/​web/​src/​app/​sitemap.ts Sitemap route for the site.
apps/​web/​src/​app/​page.tsx New/updated home page content and layout.
apps/​web/​src/​app/​not-found.tsx Custom 404 page.
apps/​web/​src/​app/​manifest.json PWA manifest metadata.
apps/​web/​src/​app/​layout.tsx Root layout with fonts + analytics/speed insights + head tags.
apps/​web/​src/​app/​icon1.png App icon asset.
apps/​web/​src/​app/​icon0.svg SVG icon asset with light/dark variants.
apps/​web/​src/​app/​globals.css Tailwind v4 + design tokens and base layer styles.
apps/​web/​src/​app/​favicon.ico Favicon asset.
apps/​web/​src/​app/​apple-icon.png Apple touch icon asset.
apps/​web/​public/​window.svg Public asset (window icon).
apps/​web/​public/​web-app-manifest-192x192.png Public PWA icon asset (192).
apps/​web/​public/​vercel.svg Public asset (Vercel logo).
apps/​web/​public/​robots.txt Robots rules + sitemap link.
apps/​web/​public/​next.svg Public asset (Next.js logo).
apps/​web/​public/​globe.svg Public asset (globe icon).
apps/​web/​public/​file.svg Public asset (file icon).
apps/​web/​public/​acm-square-white.png Public asset (square logo).
apps/​web/​public/​acm_logo.png Public asset (logo).
apps/​web/​postcss.config.mjs PostCSS config for Tailwind in apps/web.
apps/​web/​package.json Web package scripts + dependencies for Next/Tailwind/Vitest.
apps/​web/​next.config.ts Loads repo-root .env and Next config adjustments for monorepo.
apps/​web/​components.json shadcn/ui component config for the web app.
apps/​web/​biome.json Web Biome config extending shared config + Next/React domains.
apps/​api/​tsconfig.json API tsconfig extending shared base with Nest decorator metadata enabled.
apps/​api/​tsconfig.build.json Build tsconfig excluding test files.
apps/​api/​src/​main.ts NestJS bootstrap, env/CORS wiring, and server listen.
apps/​api/​src/​health/​health.service.ts DB health check implementation (select 1).
apps/​api/​src/​health/​health.controller.ts /health endpoint returning ok/degraded payloads.
apps/​api/​src/​db/​seed.ts Seed script placeholder and pool teardown.
apps/​api/​src/​db/​schema.ts Drizzle schema (placeholder health_check table).
apps/​api/​src/​db/​client.ts Postgres pool + Drizzle client export.
apps/​api/​src/​config/​env.ts Root .env loading and defaults for API config.
apps/​api/​src/​config/​cors.ts CORS origin parsing helper.
apps/​api/​src/​config/​cors.test.ts Vitest coverage for CORS parsing.
apps/​api/​src/​app.module.ts Nest module wiring for health controller/service.
apps/​api/​package.json API package scripts + Nest/Drizzle/pg dependencies.
apps/​api/​nest-cli.json Nest CLI build config.
apps/​api/​drizzle/​meta/​0000_snapshot.json Drizzle schema snapshot metadata for migration baseline.
apps/​api/​drizzle/​meta/​_journal.json Drizzle migration journal metadata.
apps/​api/​drizzle/​0000_keen_white_queen.sql Initial SQL migration creating health_check.
apps/​api/​drizzle.config.ts Drizzle-kit configuration using env-based DB URL.
apps/​api/​biome.json API Biome config (including Nest DI import-type rule override).
AGENTS.md Repository conventions for coding agents and repo workflows.
.nvmrc Pins Node major version for local dev/CI.
.gitignore Updates ignores for monorepo builds, env files, and editor tooling.
.github/​workflows/​pr.yml CI pipeline for lint/typecheck/test/build + migrations + gitleaks.
.github/​workflows/​linter.yml Removes legacy linter workflow.
.github/​pull_request_template.md Adds PR template with checklist and structure.
.github/​ISSUE_TEMPLATE/​feature.yml Feature issue template.
.github/​ISSUE_TEMPLATE/​bug.yml Bug report issue template.
.github/​CODEOWNERS Adds code ownership requirements.
.env.example Documents supported env vars and defaults template.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@Bebaz0
Bebaz0 marked this pull request as draft September 19, 2026 01:19
- api: handle idle-client errors on the pg pool so a Postgres restart
    no longer crashes the process
  - api: set connectionTimeoutMillis to 5s so /health reports the db as
    down instead of hanging on an unreachable host
  - api: use || for env defaults so blank values in .env fall back to
    the docker-compose defaults
  - web: treat non-503 error responses from /health as a failed check
    instead of reporting the database as unreachable
@Bebaz0
Bebaz0 marked this pull request as ready for review September 19, 2026 17:00
@Bebaz0
Bebaz0 merged commit af9c947 into main Sep 19, 2026
8 checks passed

This branch was successfully deployed

1 active deployment
Preview — cea346e6 Deployed Sep 19, 2026 by vercel[bot]
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