@adriankulik/create-fullstack-app 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +84 -0
  3. package/cli/index.js +170 -0
  4. package/cli/package-lock.json +1338 -0
  5. package/cli/package.json +23 -0
  6. package/package.json +40 -0
  7. package/templates/backend/fastapi/lint.sh +9 -0
  8. package/templates/backend/fastapi/main.py +28 -0
  9. package/templates/backend/fastapi/requirements.txt +5 -0
  10. package/templates/backend/fastapi/start.sh +7 -0
  11. package/templates/backend/fastapi/test.sh +7 -0
  12. package/templates/backend/fastapi/test_main.py +19 -0
  13. package/templates/backend/flask/lint.sh +9 -0
  14. package/templates/backend/flask/main.py +24 -0
  15. package/templates/backend/flask/requirements.txt +5 -0
  16. package/templates/backend/flask/start.sh +7 -0
  17. package/templates/backend/flask/test.sh +7 -0
  18. package/templates/backend/flask/test_main.py +21 -0
  19. package/templates/base/.github/workflows/test.yml +36 -0
  20. package/templates/base/.vscode/extensions.json +8 -0
  21. package/templates/base/GEMINI.md +65 -0
  22. package/templates/base/README.md +37 -0
  23. package/templates/base/gitignore +13 -0
  24. package/templates/base/lint.sh +10 -0
  25. package/templates/base/start.sh +13 -0
  26. package/templates/base/test.sh +10 -0
  27. package/templates/frontend/angular/angular.json +84 -0
  28. package/templates/frontend/angular/karma.conf.js +45 -0
  29. package/templates/frontend/angular/lint.sh +2 -0
  30. package/templates/frontend/angular/package-lock.json +16204 -0
  31. package/templates/frontend/angular/package.json +40 -0
  32. package/templates/frontend/angular/src/app/app.component.spec.ts +24 -0
  33. package/templates/frontend/angular/src/app/app.component.ts +73 -0
  34. package/templates/frontend/angular/src/favicon.ico +0 -0
  35. package/templates/frontend/angular/src/index.html +12 -0
  36. package/templates/frontend/angular/src/main.ts +5 -0
  37. package/templates/frontend/angular/src/styles.css +1 -0
  38. package/templates/frontend/angular/start.sh +2 -0
  39. package/templates/frontend/angular/test.sh +2 -0
  40. package/templates/frontend/angular/tsconfig.app.json +16 -0
  41. package/templates/frontend/angular/tsconfig.json +32 -0
  42. package/templates/frontend/angular/tsconfig.spec.json +14 -0
  43. package/templates/frontend/nextjs/.eslintrc.json +3 -0
  44. package/templates/frontend/nextjs/__tests__/page.test.tsx +39 -0
  45. package/templates/frontend/nextjs/app/layout.tsx +18 -0
  46. package/templates/frontend/nextjs/app/page.tsx +69 -0
  47. package/templates/frontend/nextjs/jest.config.js +16 -0
  48. package/templates/frontend/nextjs/jest.setup.js +1 -0
  49. package/templates/frontend/nextjs/lint.sh +3 -0
  50. package/templates/frontend/nextjs/next.config.js +4 -0
  51. package/templates/frontend/nextjs/package-lock.json +9631 -0
  52. package/templates/frontend/nextjs/package.json +31 -0
  53. package/templates/frontend/nextjs/start.sh +2 -0
  54. package/templates/frontend/nextjs/test.sh +2 -0
  55. package/templates/frontend/nextjs/tsconfig.json +27 -0
  56. package/templates/frontend/svelte/.eslintrc.cjs +27 -0
  57. package/templates/frontend/svelte/index.html +12 -0
  58. package/templates/frontend/svelte/lint.sh +3 -0
  59. package/templates/frontend/svelte/package-lock.json +6129 -0
  60. package/templates/frontend/svelte/package.json +30 -0
  61. package/templates/frontend/svelte/src/App.spec.ts +36 -0
  62. package/templates/frontend/svelte/src/App.svelte +61 -0
  63. package/templates/frontend/svelte/src/main.ts +8 -0
  64. package/templates/frontend/svelte/src/setupTests.ts +1 -0
  65. package/templates/frontend/svelte/src/svelte-env.d.ts +2 -0
  66. package/templates/frontend/svelte/start.sh +2 -0
  67. package/templates/frontend/svelte/svelte.config.js +5 -0
  68. package/templates/frontend/svelte/test.sh +2 -0
  69. package/templates/frontend/svelte/tsconfig.json +9 -0
  70. package/templates/frontend/svelte/vite.config.ts +15 -0
  71. package/templates/frontend/vue/.eslintrc.cjs +18 -0
  72. package/templates/frontend/vue/index.html +12 -0
  73. package/templates/frontend/vue/lint.sh +3 -0
  74. package/templates/frontend/vue/package-lock.json +5110 -0
  75. package/templates/frontend/vue/package.json +30 -0
  76. package/templates/frontend/vue/src/App.vue +61 -0
  77. package/templates/frontend/vue/src/__tests__/App.spec.ts +37 -0
  78. package/templates/frontend/vue/src/main.ts +4 -0
  79. package/templates/frontend/vue/src/vite-env.d.ts +7 -0
  80. package/templates/frontend/vue/start.sh +2 -0
  81. package/templates/frontend/vue/test.sh +2 -0
  82. package/templates/frontend/vue/tsconfig.json +12 -0
  83. package/templates/frontend/vue/vite.config.ts +14 -0
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "cli",
3
+ "version": "1.0.0",
4
+ "main": "index.js",
5
+ "bin": {
6
+ "create-fullstack-app": "./index.js"
7
+ },
8
+ "scripts": {
9
+ "test": "echo \"Error: no test specified\" && exit 1"
10
+ },
11
+ "keywords": [],
12
+ "author": "",
13
+ "license": "ISC",
14
+ "description": "",
15
+ "dependencies": {
16
+ "fs-extra": "^11.3.4",
17
+ "picocolors": "^1.1.1",
18
+ "prompts": "^2.4.2"
19
+ },
20
+ "devDependencies": {
21
+ "vitest": "^4.1.5"
22
+ }
23
+ }
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@adriankulik/create-fullstack-app",
3
+ "version": "1.0.0",
4
+ "description": "A CLI tool for scaffolding a full-stack web application with your choice of frontend and backend technologies.",
5
+ "main": "cli/index.js",
6
+ "bin": {
7
+ "create-fullstack-app": "./cli/index.js"
8
+ },
9
+ "files": [
10
+ "cli",
11
+ "templates"
12
+ ],
13
+ "directories": {
14
+ "test": "tests"
15
+ },
16
+ "dependencies": {
17
+ "fs-extra": "^11.3.4",
18
+ "picocolors": "^1.1.1",
19
+ "prompts": "^2.4.2"
20
+ },
21
+ "devDependencies": {
22
+ "@playwright/test": "^1.59.1",
23
+ "vitest": "^4.1.5",
24
+ "wait-on": "^9.0.5"
25
+ },
26
+ "scripts": {
27
+ "test": "echo \"Error: no test specified\" && exit 1"
28
+ },
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/adriankulik/create-fullstack-app.git"
32
+ },
33
+ "keywords": [],
34
+ "author": "",
35
+ "license": "ISC",
36
+ "bugs": {
37
+ "url": "https://github.com/adriankulik/create-fullstack-app/issues"
38
+ },
39
+ "homepage": "https://github.com/adriankulik/create-fullstack-app#readme"
40
+ }
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env bash
2
+ if [ -d "venv" ]; then
3
+ source venv/bin/activate
4
+ ruff check . --fix
5
+ ruff format .
6
+ else
7
+ ruff check . --fix
8
+ ruff format .
9
+ fi
@@ -0,0 +1,28 @@
1
+ from fastapi import FastAPI
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from pydantic import BaseModel
4
+
5
+ app = FastAPI()
6
+
7
+ # Allow CORS for the frontend
8
+ app.add_middleware(
9
+ CORSMiddleware,
10
+ allow_origins=["*"], # In production, specify the actual origin
11
+ allow_credentials=True,
12
+ allow_methods=["*"],
13
+ allow_headers=["*"],
14
+ )
15
+
16
+ class MultiplyRequest(BaseModel):
17
+ number: float
18
+
19
+ class MultiplyResponse(BaseModel):
20
+ result: float
21
+
22
+ @app.post("/api/multiply", response_model=MultiplyResponse)
23
+ def multiply_number(request: MultiplyRequest):
24
+ return MultiplyResponse(result=request.number * 2)
25
+
26
+ @app.get("/api/health")
27
+ def health_check():
28
+ return {"status": "ok"}
@@ -0,0 +1,5 @@
1
+ fastapi==0.136.1
2
+ uvicorn==0.28.0
3
+ pytest==8.1.1
4
+ httpx==0.27.0
5
+ ruff==0.3.3
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env bash
2
+ if [ -d "venv" ]; then
3
+ source venv/bin/activate
4
+ python -m uvicorn main:app --reload --port 8000
5
+ else
6
+ python3 -m uvicorn main:app --reload --port 8000
7
+ fi
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env bash
2
+ if [ -d "venv" ]; then
3
+ source venv/bin/activate
4
+ pytest
5
+ else
6
+ pytest
7
+ fi
@@ -0,0 +1,19 @@
1
+ from fastapi.testclient import TestClient
2
+ from main import app
3
+
4
+ client = TestClient(app)
5
+
6
+ def test_health_check():
7
+ response = client.get("/api/health")
8
+ assert response.status_code == 200
9
+ assert response.json() == {"status": "ok"}
10
+
11
+ def test_multiply_number():
12
+ response = client.post("/api/multiply", json={"number": 5})
13
+ assert response.status_code == 200
14
+ assert response.json() == {"result": 10.0}
15
+
16
+ def test_multiply_number_negative():
17
+ response = client.post("/api/multiply", json={"number": -3.5})
18
+ assert response.status_code == 200
19
+ assert response.json() == {"result": -7.0}
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env bash
2
+ if [ -d "venv" ]; then
3
+ source venv/bin/activate
4
+ ruff check . --fix
5
+ ruff format .
6
+ else
7
+ ruff check . --fix
8
+ ruff format .
9
+ fi
@@ -0,0 +1,24 @@
1
+ from flask import Flask, request, jsonify
2
+ from flask_cors import CORS
3
+
4
+ app = Flask(__name__)
5
+ CORS(app)
6
+
7
+ @app.route("/api/multiply", methods=["POST"])
8
+ def multiply_number():
9
+ data = request.get_json()
10
+ if not data or "number" not in data:
11
+ return jsonify({"error": "Missing number"}), 400
12
+
13
+ try:
14
+ number = float(data["number"])
15
+ return jsonify({"result": number * 2})
16
+ except ValueError:
17
+ return jsonify({"error": "Invalid number"}), 400
18
+
19
+ @app.route("/api/health", methods=["GET"])
20
+ def health_check():
21
+ return jsonify({"status": "ok"})
22
+
23
+ if __name__ == "__main__":
24
+ app.run(port=8000)
@@ -0,0 +1,5 @@
1
+ Flask==3.1.3
2
+ Flask-Cors==4.0.0
3
+ pytest==8.1.1
4
+ httpx==0.27.0
5
+ ruff==0.3.3
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env bash
2
+ if [ -d "venv" ]; then
3
+ source venv/bin/activate
4
+ python main.py
5
+ else
6
+ python3 main.py
7
+ fi
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env bash
2
+ if [ -d "venv" ]; then
3
+ source venv/bin/activate
4
+ pytest
5
+ else
6
+ pytest
7
+ fi
@@ -0,0 +1,21 @@
1
+ import pytest
2
+ from main import app
3
+
4
+ @pytest.fixture
5
+ def client():
6
+ with app.test_client() as client:
7
+ yield client
8
+
9
+ def test_health_check(client):
10
+ response = client.get("/api/health")
11
+ assert response.status_code == 200
12
+ assert response.get_json() == {"status": "ok"}
13
+
14
+ def test_multiply_number(client):
15
+ response = client.post("/api/multiply", json={"number": 5})
16
+ assert response.status_code == 200
17
+ assert response.get_json() == {"result": 10.0}
18
+
19
+ def test_multiply_number_invalid(client):
20
+ response = client.post("/api/multiply", json={"number": "not a number"})
21
+ assert response.status_code == 400
@@ -0,0 +1,36 @@
1
+ name: Fullstack Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+ branches: [ main ]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+
15
+ - name: Set up Python
16
+ uses: actions/setup-python@v5
17
+ with:
18
+ python-version: '3.11'
19
+
20
+ - name: Set up Node.js
21
+ uses: actions/setup-node@v4
22
+ with:
23
+ node-version: '20'
24
+
25
+ - name: Install backend dependencies
26
+ run: |
27
+ cd backend
28
+ pip install -r requirements.txt
29
+
30
+ - name: Install frontend dependencies
31
+ run: |
32
+ cd frontend
33
+ npm install
34
+
35
+ - name: Run tests
36
+ run: ./test.sh
@@ -0,0 +1,8 @@
1
+ {
2
+ "recommendations": [
3
+ "esbenp.prettier-vscode",
4
+ "dbaeumer.vscode-eslint",
5
+ "charliermarsh.ruff",
6
+ "ms-python.python"
7
+ ]
8
+ }
@@ -0,0 +1,65 @@
1
+ # GEMINI.md
2
+
3
+ Behavioral guidelines to reduce common LLM coding mistakes. Merge with project-specific instructions as needed.
4
+
5
+ **Tradeoff:** These guidelines bias toward caution over speed. For trivial tasks, use judgment.
6
+
7
+ ## 1. Think Before Coding
8
+
9
+ **Don't assume. Don't hide confusion. Surface tradeoffs.**
10
+
11
+ Before implementing:
12
+ - State your assumptions explicitly. If uncertain, ask.
13
+ - If multiple interpretations exist, present them - don't pick silently.
14
+ - If a simpler approach exists, say so. Push back when warranted.
15
+ - If something is unclear, stop. Name what's confusing. Ask.
16
+
17
+ ## 2. Simplicity First
18
+
19
+ **Minimum code that solves the problem. Nothing speculative.**
20
+
21
+ - No features beyond what was asked.
22
+ - No abstractions for single-use code.
23
+ - No "flexibility" or "configurability" that wasn't requested.
24
+ - No error handling for impossible scenarios.
25
+ - If you write 200 lines and it could be 50, rewrite it.
26
+
27
+ Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.
28
+
29
+ ## 3. Surgical Changes
30
+
31
+ **Touch only what you must. Clean up only your own mess.**
32
+
33
+ When editing existing code:
34
+ - Don't "improve" adjacent code, comments, or formatting.
35
+ - Don't refactor things that aren't broken.
36
+ - Match existing style, even if you'd do it differently.
37
+ - If you notice unrelated dead code, mention it - don't delete it.
38
+
39
+ When your changes create orphans:
40
+ - Remove imports/variables/functions that YOUR changes made unused.
41
+ - Don't remove pre-existing dead code unless asked.
42
+
43
+ The test: Every changed line should trace directly to the user's request.
44
+
45
+ ## 4. Goal-Driven Execution
46
+
47
+ **Define success criteria. Loop until verified.**
48
+
49
+ Transform tasks into verifiable goals:
50
+ - "Add validation" → "Write tests for invalid inputs, then make them pass"
51
+ - "Fix the bug" → "Write a test that reproduces it, then make it pass"
52
+ - "Refactor X" → "Ensure tests pass before and after"
53
+
54
+ For multi-step tasks, state a brief plan:
55
+ ```
56
+ 1. [Step] → verify: [check]
57
+ 2. [Step] → verify: [check]
58
+ 3. [Step] → verify: [check]
59
+ ```
60
+
61
+ Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.
62
+
63
+ ---
64
+
65
+ **These guidelines are working if:** fewer unnecessary changes in diffs, fewer rewrites due to overcomplication, and clarifying questions come before implementation rather than after mistakes.
@@ -0,0 +1,37 @@
1
+ # Your Fullstack Application
2
+
3
+ > 🚀 This application was scaffolded using [create-fullstack-app](https://github.com/adriankulik/create-fullstack-app) by Adrian Kulik.
4
+
5
+ ## Quickstart
6
+
7
+ This project is set up with unified shell scripts to easily manage both the frontend and backend simultaneously.
8
+
9
+ ### Prerequisites
10
+
11
+ These scripts natively support **macOS** and **Linux**. If you are using **Windows**, you must use a Unix compatibility layer like **Git Bash** or **WSL** (Windows Subsystem for Linux) to run them.
12
+
13
+ Depending on your environment, you may need to ensure the scripts are executable before running them for the first time:
14
+
15
+ ```bash
16
+ chmod +x *.sh
17
+ ```
18
+
19
+ ### Running the App
20
+
21
+ To start both the frontend and backend development servers, simply run:
22
+
23
+ ```bash
24
+ ./start.sh
25
+ ```
26
+
27
+ ### Testing and Linting
28
+
29
+ - **Test:** Run all frontend and backend tests:
30
+ ```bash
31
+ ./test.sh
32
+ ```
33
+
34
+ - **Lint:** Lint and format your codebase:
35
+ ```bash
36
+ ./lint.sh
37
+ ```
@@ -0,0 +1,13 @@
1
+ node_modules/
2
+ dist/
3
+ build/
4
+ .env
5
+ .DS_Store
6
+ coverage/
7
+ .angular/
8
+ .next/
9
+ .svelte-kit/
10
+ venv/
11
+ __pycache__/
12
+ .pytest_cache/
13
+ .ruff_cache/
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env bash
2
+ set -e
3
+
4
+ echo "Linting and Formatting Backend..."
5
+ (cd backend && ./lint.sh)
6
+
7
+ echo "Linting and Formatting Frontend..."
8
+ (cd frontend && ./lint.sh)
9
+
10
+ echo "Linting and formatting complete!"
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+ set -e
3
+
4
+ echo "Starting Backend..."
5
+ (cd backend && ./start.sh) &
6
+ BACKEND_PID=$!
7
+
8
+ echo "Starting Frontend..."
9
+ (cd frontend && ./start.sh) &
10
+ FRONTEND_PID=$!
11
+
12
+ echo "Services started. Press Ctrl+C to stop."
13
+ wait $BACKEND_PID $FRONTEND_PID
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env bash
2
+ set -e
3
+
4
+ echo "Running Backend Tests..."
5
+ (cd backend && ./test.sh)
6
+
7
+ echo "Running Frontend Tests..."
8
+ (cd frontend && ./test.sh)
9
+
10
+ echo "All tests passed!"
@@ -0,0 +1,84 @@
1
+ {
2
+ "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3
+ "version": 1,
4
+ "newProjectRoot": "projects",
5
+ "projects": {
6
+ "frontend": {
7
+ "projectType": "application",
8
+ "schematics": {},
9
+ "root": "",
10
+ "sourceRoot": "src",
11
+ "prefix": "app",
12
+ "architect": {
13
+ "build": {
14
+ "builder": "@angular-devkit/build-angular:browser",
15
+ "options": {
16
+ "outputPath": "dist/frontend",
17
+ "index": "src/index.html",
18
+ "main": "src/main.ts",
19
+ "polyfills": ["zone.js"],
20
+ "tsConfig": "tsconfig.app.json",
21
+ "assets": ["src/favicon.ico", "src/assets"],
22
+ "styles": ["src/styles.css"],
23
+ "scripts": []
24
+ },
25
+ "configurations": {
26
+ "production": {
27
+ "budgets": [
28
+ {
29
+ "type": "initial",
30
+ "maximumWarning": "500kb",
31
+ "maximumError": "1mb"
32
+ },
33
+ {
34
+ "type": "anyComponentStyle",
35
+ "maximumWarning": "2kb",
36
+ "maximumError": "4kb"
37
+ }
38
+ ],
39
+ "outputHashing": "all"
40
+ },
41
+ "development": {
42
+ "buildOptimizer": false,
43
+ "optimization": false,
44
+ "vendorChunk": true,
45
+ "extractLicenses": false,
46
+ "sourceMap": true,
47
+ "namedChunks": true
48
+ }
49
+ },
50
+ "defaultConfiguration": "production"
51
+ },
52
+ "serve": {
53
+ "builder": "@angular-devkit/build-angular:dev-server",
54
+ "configurations": {
55
+ "production": {
56
+ "buildTarget": "frontend:build:production"
57
+ },
58
+ "development": {
59
+ "buildTarget": "frontend:build:development"
60
+ }
61
+ },
62
+ "defaultConfiguration": "development"
63
+ },
64
+ "extract-i18n": {
65
+ "builder": "@angular-devkit/build-angular:extract-i18n",
66
+ "options": {
67
+ "buildTarget": "frontend:build"
68
+ }
69
+ },
70
+ "test": {
71
+ "builder": "@angular-devkit/build-angular:karma",
72
+ "options": {
73
+ "polyfills": ["zone.js", "zone.js/testing"],
74
+ "tsConfig": "tsconfig.spec.json",
75
+ "karmaConfig": "karma.conf.js",
76
+ "assets": ["src/favicon.ico", "src/assets"],
77
+ "styles": ["src/styles.css"],
78
+ "scripts": []
79
+ }
80
+ }
81
+ }
82
+ }
83
+ }
84
+ }
@@ -0,0 +1,45 @@
1
+ process.env.CHROME_BIN = require('puppeteer').executablePath();
2
+
3
+ module.exports = function (config) {
4
+ config.set({
5
+ basePath: '',
6
+ frameworks: ['jasmine', '@angular-devkit/build-angular'],
7
+ plugins: [
8
+ require('karma-jasmine'),
9
+ require('karma-chrome-launcher'),
10
+ require('karma-jasmine-html-reporter'),
11
+ require('karma-coverage'),
12
+ require('@angular-devkit/build-angular/plugins/karma')
13
+ ],
14
+ client: {
15
+ jasmine: {
16
+ },
17
+ clearContext: false
18
+ },
19
+ jasmineHtmlReporter: {
20
+ suppressAll: true
21
+ },
22
+ coverageReporter: {
23
+ dir: require('path').join(__dirname, './coverage/frontend'),
24
+ subdir: '.',
25
+ reporters: [
26
+ { type: 'html' },
27
+ { type: 'text-summary' }
28
+ ]
29
+ },
30
+ reporters: ['progress', 'kjhtml'],
31
+ port: 9876,
32
+ colors: true,
33
+ logLevel: config.LOG_INFO,
34
+ autoWatch: true,
35
+ browsers: ['Chrome', 'ChromeHeadlessCI'],
36
+ customLaunchers: {
37
+ ChromeHeadlessCI: {
38
+ base: 'ChromeHeadless',
39
+ flags: ['--no-sandbox']
40
+ }
41
+ },
42
+ singleRun: false,
43
+ restartOnFileChange: true
44
+ });
45
+ };
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env bash
2
+ npm run lint