{"id":50932350,"url":"https://github.com/im-codebreaker/stackit","last_synced_at":"2026-06-17T05:31:08.101Z","repository":{"id":357364391,"uuid":"1236648228","full_name":"im-codebreaker/stackit","owner":"im-codebreaker","description":"Stack it your way — minimal full-stack starter (Vue 3 + Fastify + Prisma)","archived":false,"fork":false,"pushed_at":"2026-05-19T14:28:54.000Z","size":357,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-19T17:14:23.675Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/im-codebreaker.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-12T12:49:57.000Z","updated_at":"2026-05-19T14:45:33.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/im-codebreaker/stackit","commit_stats":null,"previous_names":["im-codebreaker/stackit"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/im-codebreaker/stackit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/im-codebreaker%2Fstackit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/im-codebreaker%2Fstackit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/im-codebreaker%2Fstackit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/im-codebreaker%2Fstackit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/im-codebreaker","download_url":"https://codeload.github.com/im-codebreaker/stackit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/im-codebreaker%2Fstackit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34435978,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-17T02:00:05.408Z","response_time":127,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-17T05:31:04.778Z","updated_at":"2026-06-17T05:31:08.094Z","avatar_url":"https://github.com/im-codebreaker.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# stackit\n\n\u003e Stack it your way — minimal full-stack starter (Vue 3 + Fastify + Drizzle).\n\nA clean, opinionated, modular pnpm monorepo for shipping a full-stack app fast.\n\n## Stack\n\n| Layer        | Technology                                                  |\n| ------------ | ----------------------------------------------------------- |\n| Frontend     | Vue 3.5, Vite 7, Pinia, Vue Router, Tailwind v4, @rebnd/ui  |\n| Backend      | Fastify 5, autoload, type-provider-zod                      |\n| Database     | PostgreSQL via Drizzle ORM (pgvector-ready)                  |\n| Validation   | Zod v4 — shared between frontend and backend                |\n| Cache        | Redis (optional)                                             |\n| Auth         | better-auth (optional)                                       |\n| Tooling      | TypeScript, ESLint (antfu), Vitest, Docker, Traefik, Turborepo |\n\n## Quickstart\n\n**Local dev (recommended)** — apps run on host, infra in docker:\n\n```bash\n# Clone and setup\ngit clone git@github.com:im-codebreaker/stackit.git my-app\ncd my-app\n\n# Point to your own repo (choose one):\ngit remote set-url origin \u003cyour-repo-url\u003e  # change remote\ngit remote remove origin                    # or remove entirely\n```\n\n```bash\n# Install dependencies and configure\npnpm install\npnpm setup  # interactive — pick optional modules + project name\ncp .env.example .env\n```\n\n```bash\n# Start infrastructure\ndocker compose up -d postgres redis\n```\n\n```bash\n# Setup database\npnpm db:migrate\npnpm db:seed\n```\n\n```bash\n# Start development servers\npnpm dev  # api on :3000, web on :5173\n```\n\n**Full stack in docker** — everything containerized, hot-reload via `--watch`:\n\n```bash\n# Configure environment\ncp .env.example .env\n\n# Start infrastructure and run migrations\ndocker compose up -d postgres redis\npnpm db:migrate\n\n# Start all services with watch mode\ndocker compose up --build --watch       # traefik, postgres, redis, api, web\n```\n\n\u003e **Note:** You may see `\"../../.env not found. Continuing without it.\"` in logs — this is expected. Environment variables are set via `docker-compose.yml`, not the `.env` file (which is excluded by `.dockerignore`).\n\nOpen \u003chttp://localhost\u003e. Traefik on `:80` routes `/` → Vite, `/api` → Fastify, `/docs` → Swagger UI. The api and web containers also expose `:3000` and `:5173` directly if you prefer.\n\nAPI health: \u003chttp://localhost/api/v1/health\u003e · OpenAPI docs: \u003chttp://localhost/docs\u003e\n\n## Structure\n\n```\nstackit/\n├── apps/\n│   ├── api/                    Fastify backend (domain modules, Zod-validated routes)\n│   └── web/                    Vue 3 SPA (Pinia, Vue Router, Tailwind v4)\n├── packages/\n│   ├── shared/                 @stackit/shared      — Zod schemas, TS types, utilities\n│   ├── db/                     @stackit/db          — Drizzle client + schema\n│   ├── cache/                  @stackit/cache       — Redis client (optional)\n│   ├── auth/                   @stackit/auth        — better-auth wrapper (optional)\n│   └── config/\n│       ├── tsconfig/           shared tsconfigs (base, node, web, vitest)\n│       └── eslint-config/      shared ESLint config (wraps @antfu/eslint-config)\n├── infrastructure/             traefik config; reserved for k8s/terraform\n├── scripts/init.ts             post-clone setup (pnpm setup) — self-deletes\n├── docker-compose.yml          traefik + postgres + redis + api + web\n└── Dockerfile                  multi-stage: deps → api/web {build,dev,prod}\n```\n\n## Validation flow (Zod, end to end)\n\n1. Define a schema once in `packages/shared/src/schemas/\u003cdomain\u003e/`.\n2. Fastify route uses it via `fastify-type-provider-zod` — request/response inferred.\n3. Vue form imports the same schema and validates with `RForm` from `@rebnd/ui`.\n4. OpenAPI docs are generated from the schemas automatically.\n\n```ts\n// packages/shared/src/schemas/users/requests.ts\nexport const CreateUserSchema = z.object({\n  email: z.email(),\n  name: z.string().min(1).max(120),\n})\nexport type CreateUserInput = z.infer\u003ctypeof CreateUserSchema\u003e\n\n// Import in API: import { requests } from '@stackit/shared/schemas/users'\n// apps/api/src/modules/users/users.routes.ts\nfastify.post(\n  '/',\n  {\n    schema: {\n      body: requests.CreateUserSchema,\n      response: {\n        201: UserSchema,\n      },\n    },\n  },\n  handlers.createUser\n)\n\n// Import in web: import { users } from '@stackit/shared/schemas'\n// apps/web/src/views/UsersView.vue\n\u003cscript setup lang=\"ts\"\u003e\nimport { RForm } from '@rebnd/ui'\nimport { users } from '@stackit/shared/schemas'\nimport { reactive } from 'vue'\n\nconst state = reactive\u003cusers.requests.CreateUserInput\u003e({ email: '', name: '' })\n\nasync function onSubmit(event: SubmitEvent \u0026 { state: users.requests.CreateUserInput | null }) {\n  if (!event.state) return\n  // Handle submission\n}\n\u003c/script\u003e\n\n\u003ctemplate\u003e\n  \u003cRForm\n    :schema=\"users.requests.CreateUserSchema\"\n    :state=\"state\"\n    @submit=\"onSubmit\"\n  \u003e\n    \u003c!-- form fields --\u003e\n  \u003c/RForm\u003e\n\u003c/template\u003e\n```\n\n## Scripts (root)\n\n| Command             | What it does                                          |\n| ------------------- | ----------------------------------------------------- |\n| `pnpm setup`        | One-time interactive setup (removed after first run)  |\n| `pnpm dev`          | Run all apps in parallel                              |\n| `pnpm build`        | Build every workspace                                 |\n| `pnpm lint`         | ESLint across the repo                                |\n| `pnpm test`         | Vitest across api + web                               |\n| `pnpm type-check`   | tsc / vue-tsc across all packages                     |\n| `pnpm db:generate`  | Generate a Drizzle migration from schema changes      |\n| `pnpm db:migrate`   | Apply pending Drizzle migrations                      |\n| `pnpm db:push`      | Push schema to DB without migration (dev only)        |\n| `pnpm db:seed`      | Seed the database                                     |\n| `pnpm db:studio`    | Open Drizzle Studio                                   |\n\n## Architecture choices\n\n- **Turborepo** — task orchestration with intelligent caching. Run `pnpm dev` to start all apps in parallel, or `pnpm build` to build with cached layers.\n- **Source-only packages** — every shared package exports `./src/index.ts` directly. Apps compile through their own tooling (`tsx`, `vite`). No build step in `packages/`.\n- **Domain-based API modules** — each feature lives in `apps/api/src/modules/\u003cdomain\u003e/` with its own routes, handlers, services, and repositories. Four-layer architecture: routes → handlers (HTTP) → services (business logic) → repositories (data access).\n- **Service layer** — business logic lives between handlers and repositories. Handlers deal with HTTP concerns (status codes, error mapping), services contain domain logic, repositories handle data access with optional transaction support.\n- **Autoloaded Fastify plugins** — drop a file in `plugins/external/` or `plugins/app/`; it registers automatically. Removing a feature is just deleting its file.\n- **Repository pattern** — repositories accept an optional `tx?: DatabaseClient` parameter for participating in Drizzle transactions.\n- **pgvector-ready** — Drizzle natively supports the `vector` column type and `cosineDistance`/`l2Distance` operators. Add `CREATE EXTENSION IF NOT EXISTS vector;` to a migration, declare a `vector('embedding', { dimensions: 1536 })` column, and similarity queries become fully typed.\n- **Module augmentation** — `apps/api/src/types/fastify.d.ts` declares decorators (`fastify.db`, `fastify.cache`, `fastify.auth`).\n- **One demo domain (`users`)** — full CRUD slice with shared schemas, module structure (routes/handlers/services/repositories), store, and view as a template to copy.\n\n## Optional modules\n\nThe `pnpm setup` script asks at install time. Each module is structured so that removing it is purely additive cleanup:\n\n| Module     | Removed if declined                                                              |\n| ---------- | -------------------------------------------------------------------------------- |\n| Redis      | `packages/cache/`, `apps/api/src/plugins/app/redis.ts`, redis service in compose |\n| better-auth | `packages/auth/`, auth plugin/route/lib, login view, auth store, auth schema     |\n\nRe-enabling a module after removal: copy it from this template's git history, or just `pnpm add` and rebuild from scratch.\n\n## License\n\nMIT — see [LICENSE](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fim-codebreaker%2Fstackit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fim-codebreaker%2Fstackit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fim-codebreaker%2Fstackit/lists"}