create-softeneers-app 0.1.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 (48) hide show
  1. package/README.md +31 -0
  2. package/dist/args.js +96 -0
  3. package/dist/args.js.map +1 -0
  4. package/dist/index.js +94 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/prompts.js +31 -0
  7. package/dist/prompts.js.map +1 -0
  8. package/dist/scaffold.js +130 -0
  9. package/dist/scaffold.js.map +1 -0
  10. package/dist/templates.js +40 -0
  11. package/dist/templates.js.map +1 -0
  12. package/package.json +41 -0
  13. package/templates/next-fullstack/.env.example +18 -0
  14. package/templates/next-fullstack/README.md +54 -0
  15. package/templates/next-fullstack/apps/server/.env.example +8 -0
  16. package/templates/next-fullstack/apps/server/README.md +64 -0
  17. package/templates/next-fullstack/apps/server/config/config.cjs +24 -0
  18. package/templates/next-fullstack/apps/server/controller/carController.ts +62 -0
  19. package/templates/next-fullstack/apps/server/index.ts +50 -0
  20. package/templates/next-fullstack/apps/server/migrations/20260414160000-create-cars-table.js +39 -0
  21. package/templates/next-fullstack/apps/server/models/car.ts +70 -0
  22. package/templates/next-fullstack/apps/server/package.json +34 -0
  23. package/templates/next-fullstack/apps/server/routes/carRoutes.ts +18 -0
  24. package/templates/next-fullstack/apps/server/seeders/20260414160500-seed-cars.js +34 -0
  25. package/templates/next-fullstack/apps/server/tsconfig.json +14 -0
  26. package/templates/next-fullstack/apps/web/README.md +38 -0
  27. package/templates/next-fullstack/apps/web/app/components/Footer.tsx +19 -0
  28. package/templates/next-fullstack/apps/web/app/components/Navbar.tsx +34 -0
  29. package/templates/next-fullstack/apps/web/app/docs/page.tsx +170 -0
  30. package/templates/next-fullstack/apps/web/app/favicon.ico +0 -0
  31. package/templates/next-fullstack/apps/web/app/globals.css +1 -0
  32. package/templates/next-fullstack/apps/web/app/layout.tsx +29 -0
  33. package/templates/next-fullstack/apps/web/app/masini/page.tsx +269 -0
  34. package/templates/next-fullstack/apps/web/app/page.tsx +88 -0
  35. package/templates/next-fullstack/apps/web/eslint.config.mjs +18 -0
  36. package/templates/next-fullstack/apps/web/next.config.ts +7 -0
  37. package/templates/next-fullstack/apps/web/package.json +26 -0
  38. package/templates/next-fullstack/apps/web/postcss.config.mjs +7 -0
  39. package/templates/next-fullstack/apps/web/public/file.svg +1 -0
  40. package/templates/next-fullstack/apps/web/public/globe.svg +1 -0
  41. package/templates/next-fullstack/apps/web/public/next.svg +1 -0
  42. package/templates/next-fullstack/apps/web/public/vercel.svg +1 -0
  43. package/templates/next-fullstack/apps/web/public/window.svg +1 -0
  44. package/templates/next-fullstack/apps/web/tsconfig.json +34 -0
  45. package/templates/next-fullstack/docker-compose.yml +23 -0
  46. package/templates/next-fullstack/package.json +25 -0
  47. package/templates/next-fullstack/pnpm-workspace.yaml +3 -0
  48. package/templates/next-fullstack/turbo.json +17 -0
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+
3
+ require("dotenv").config();
4
+
5
+ const shared = {
6
+ username: process.env.DB_USER || "root",
7
+ password: process.env.DB_PASSWORD || "",
8
+ database: process.env.DB_NAME || "monolith_demo_dev",
9
+ host: process.env.DB_HOST || "127.0.0.1",
10
+ port: Number(process.env.DB_PORT || 3306),
11
+ dialect: "mysql",
12
+ };
13
+
14
+ module.exports = {
15
+ development: { ...shared },
16
+ test: {
17
+ ...shared,
18
+ database: process.env.DB_NAME_TEST || "monolith_demo_test",
19
+ },
20
+ production: {
21
+ ...shared,
22
+ database: process.env.DB_NAME_PROD || process.env.DB_NAME || "monolith_demo_prod",
23
+ },
24
+ };
@@ -0,0 +1,62 @@
1
+ import { Request, Response } from "express";
2
+ import Car from "../models/car";
3
+
4
+ const getAllCars = async (_req: Request, res: Response) => {
5
+ const cars = await Car.findAll({ order: [["id", "ASC"]] });
6
+ res.status(200).json(cars);
7
+ };
8
+
9
+ const getCarById = async (req: Request, res: Response) => {
10
+ const carId = Number(req.params.id);
11
+ const car = await Car.findByPk(carId);
12
+
13
+ if (!car) {
14
+ return res.status(404).json({ message: "Car not found." });
15
+ }
16
+
17
+ return res.status(200).json(car);
18
+ };
19
+
20
+ const createCar = async (req: Request, res: Response) => {
21
+ const { brand, model, year } = req.body;
22
+
23
+ if (!brand || !model || !year) {
24
+ return res.status(400).json({ message: "brand, model and year are required." });
25
+ }
26
+
27
+ const createdCar = await Car.create({ brand, model, year: Number(year) });
28
+ return res.status(201).json(createdCar);
29
+ };
30
+
31
+ const updateCar = async (req: Request, res: Response) => {
32
+ const carId = Number(req.params.id);
33
+ const car = await Car.findByPk(carId);
34
+
35
+ if (!car) {
36
+ return res.status(404).json({ message: "Car not found." });
37
+ }
38
+
39
+ const { brand, model, year } = req.body;
40
+
41
+ await car.update({
42
+ brand: brand ?? car.brand,
43
+ model: model ?? car.model,
44
+ year: year ? Number(year) : car.year,
45
+ });
46
+
47
+ return res.status(200).json(car);
48
+ };
49
+
50
+ const deleteCar = async (req: Request, res: Response) => {
51
+ const carId = Number(req.params.id);
52
+ const car = await Car.findByPk(carId);
53
+
54
+ if (!car) {
55
+ return res.status(404).json({ message: "Car not found." });
56
+ }
57
+
58
+ await car.destroy();
59
+ return res.status(200).json({ message: "Car deleted successfully." });
60
+ };
61
+
62
+ export { getAllCars, getCarById, createCar, updateCar, deleteCar };
@@ -0,0 +1,50 @@
1
+ import "dotenv/config";
2
+ import cors from "cors";
3
+ import express, { NextFunction, Request, Response } from "express";
4
+ import { sequelize } from "./models/car";
5
+ import carRouter from "./routes/carRoutes";
6
+
7
+ const app = express();
8
+ const PORT = Number(process.env.PORT ?? 4000);
9
+ const FRONTEND_URL = process.env.FRONTEND_URL ?? "http://localhost:3000";
10
+
11
+ // Permitem request-uri din frontend (ex: Next.js pe localhost:3000).
12
+ app.use(
13
+ cors({
14
+ origin: FRONTEND_URL,
15
+ })
16
+ );
17
+
18
+ // Parseaza automat JSON-ul trimis in body de frontend.
19
+ app.use(express.json());
20
+
21
+ // Endpoint simplu de health-check ca sa verifici rapid daca API-ul merge.
22
+ app.get("/health", (_req: Request, res: Response) => {
23
+ res.status(200).json({ ok: true });
24
+ });
25
+
26
+ // Grupam toate endpoint-urile pentru masini sub /api/cars.
27
+ app.use("/api/cars", carRouter);
28
+
29
+ // Middleware minimal de tratare erori, ca sa nu cada serverul fara raspuns util.
30
+ app.use((error: unknown, _req: Request, res: Response, _next: NextFunction) => {
31
+ console.error("Unhandled error:", error);
32
+ res.status(500).json({ message: "Internal server error." });
33
+ });
34
+
35
+ // Pornim serverul doar dupa ce conexiunea la MySQL este valida.
36
+ const startServer = async () => {
37
+ try {
38
+ await sequelize.authenticate();
39
+ console.log("MySQL connection established.");
40
+
41
+ app.listen(PORT, () => {
42
+ console.log(`Backend running on http://localhost:${PORT}`);
43
+ });
44
+ } catch (error) {
45
+ console.error("Failed to connect to database:", error);
46
+ process.exit(1);
47
+ }
48
+ };
49
+
50
+ startServer();
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+
3
+ /** @type {import("sequelize-cli").Migration} */
4
+ module.exports = {
5
+ async up(queryInterface, Sequelize) {
6
+ await queryInterface.createTable("cars", {
7
+ id: {
8
+ allowNull: false,
9
+ autoIncrement: true,
10
+ primaryKey: true,
11
+ type: Sequelize.INTEGER,
12
+ },
13
+ brand: {
14
+ type: Sequelize.STRING,
15
+ allowNull: false,
16
+ },
17
+ model: {
18
+ type: Sequelize.STRING,
19
+ allowNull: false,
20
+ },
21
+ year: {
22
+ type: Sequelize.INTEGER,
23
+ allowNull: false,
24
+ },
25
+ createdAt: {
26
+ allowNull: false,
27
+ type: Sequelize.DATE,
28
+ },
29
+ updatedAt: {
30
+ allowNull: false,
31
+ type: Sequelize.DATE,
32
+ },
33
+ });
34
+ },
35
+
36
+ async down(queryInterface) {
37
+ await queryInterface.dropTable("cars");
38
+ },
39
+ };
@@ -0,0 +1,70 @@
1
+ import { DataTypes, Model, Optional, Sequelize } from "sequelize";
2
+
3
+ const environment = process.env.NODE_ENV ?? "development";
4
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
5
+ const dbConfig = require("../config/config.cjs")[environment];
6
+
7
+ const sequelize = new Sequelize({
8
+ dialect: "mysql",
9
+ host: dbConfig.host,
10
+ port: dbConfig.port,
11
+ database: dbConfig.database,
12
+ username: dbConfig.username,
13
+ password: dbConfig.password,
14
+ logging: false,
15
+ });
16
+
17
+ type CarAttributes = {
18
+ id: number;
19
+ brand: string;
20
+ model: string;
21
+ year: number;
22
+ createdAt?: Date;
23
+ updatedAt?: Date;
24
+ };
25
+
26
+ type CarCreationAttributes = Optional<CarAttributes, "id" | "createdAt" | "updatedAt">;
27
+
28
+ class Car extends Model<CarAttributes, CarCreationAttributes> implements CarAttributes {
29
+ declare id: number;
30
+ declare brand: string;
31
+ declare model: string;
32
+ declare year: number;
33
+ declare readonly createdAt: Date;
34
+ declare readonly updatedAt: Date;
35
+ }
36
+
37
+ Car.init(
38
+ {
39
+ id: {
40
+ type: DataTypes.INTEGER,
41
+ autoIncrement: true,
42
+ primaryKey: true,
43
+ },
44
+ brand: {
45
+ type: DataTypes.STRING,
46
+ allowNull: false,
47
+ },
48
+ model: {
49
+ type: DataTypes.STRING,
50
+ allowNull: false,
51
+ },
52
+ year: {
53
+ type: DataTypes.INTEGER,
54
+ allowNull: false,
55
+ validate: {
56
+ min: 1886,
57
+ max: 3000,
58
+ },
59
+ },
60
+ },
61
+ {
62
+ sequelize,
63
+ modelName: "Car",
64
+ tableName: "cars",
65
+ }
66
+ );
67
+
68
+ export type { CarAttributes, CarCreationAttributes };
69
+ export { sequelize };
70
+ export default Car;
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "server",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "dist/index.js",
6
+ "scripts": {
7
+ "dev": "nodemon index.ts",
8
+ "build": "tsc",
9
+ "start": "node dist/index.js",
10
+ "db:migrate": "sequelize-cli db:migrate --config config/config.cjs",
11
+ "db:seed": "sequelize-cli db:seed:all --config config/config.cjs",
12
+ "db:reset": "sequelize-cli db:migrate:undo:all --config config/config.cjs && sequelize-cli db:migrate --config config/config.cjs && sequelize-cli db:seed:all --config config/config.cjs"
13
+ },
14
+ "keywords": [],
15
+ "author": "",
16
+ "license": "ISC",
17
+ "type": "commonjs",
18
+ "dependencies": {
19
+ "cors": "^2.8.6",
20
+ "dotenv": "^17.4.2",
21
+ "express": "^5.2.1",
22
+ "mysql2": "^3.22.0",
23
+ "nodemon": "^3.1.14",
24
+ "sequelize": "^6.37.8"
25
+ },
26
+ "devDependencies": {
27
+ "@types/cors": "^2.8.19",
28
+ "@types/express": "^5.0.6",
29
+ "@types/node": "^25.6.0",
30
+ "sequelize-cli": "^6.6.5",
31
+ "ts-node-dev": "^2.0.0",
32
+ "typescript": "^6.0.2"
33
+ }
34
+ }
@@ -0,0 +1,18 @@
1
+ import { Router } from "express";
2
+ import {
3
+ createCar,
4
+ deleteCar,
5
+ getAllCars,
6
+ getCarById,
7
+ updateCar,
8
+ } from "../controller/carController";
9
+
10
+ const carRouter = Router();
11
+
12
+ carRouter.get("/", getAllCars);
13
+ carRouter.get("/:id", getCarById);
14
+ carRouter.post("/", createCar);
15
+ carRouter.put("/:id", updateCar);
16
+ carRouter.delete("/:id", deleteCar);
17
+
18
+ export default carRouter;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+
3
+ /** @type {import("sequelize-cli").Migration} */
4
+ module.exports = {
5
+ async up(queryInterface) {
6
+ await queryInterface.bulkInsert("cars", [
7
+ {
8
+ brand: "Dacia",
9
+ model: "Duster",
10
+ year: 2021,
11
+ createdAt: new Date(),
12
+ updatedAt: new Date(),
13
+ },
14
+ {
15
+ brand: "Volkswagen",
16
+ model: "Golf 7",
17
+ year: 2019,
18
+ createdAt: new Date(),
19
+ updatedAt: new Date(),
20
+ },
21
+ {
22
+ brand: "Tesla",
23
+ model: "Model 3",
24
+ year: 2023,
25
+ createdAt: new Date(),
26
+ updatedAt: new Date(),
27
+ },
28
+ ]);
29
+ },
30
+
31
+ async down(queryInterface) {
32
+ await queryInterface.bulkDelete("cars", null, {});
33
+ },
34
+ };
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "commonjs",
5
+ "rootDir": ".",
6
+ "outDir": "dist",
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "skipLibCheck": true
11
+ },
12
+ "include": ["index.ts", "controller/**/*.ts", "models/**/*.ts", "routes/**/*.ts"],
13
+ "exclude": ["dist", "node_modules", "src"]
14
+ }
@@ -0,0 +1,38 @@
1
+ # Frontend Quick Start
2
+
3
+ Frontend-ul este o aplicatie Next.js care consuma API-ul backend-ului (`/api/cars`)
4
+ si afiseaza demo-ul CRUD in pagina `masini`.
5
+
6
+ ## 1) Instaleaza dependintele
7
+
8
+ ```bash
9
+ cd frontend
10
+ npm install
11
+ ```
12
+
13
+ ## 2) Configureaza URL-ul backend-ului (optional, recomandat)
14
+
15
+ ```bash
16
+ echo "NEXT_PUBLIC_API_URL=http://localhost:4000" > .env.local
17
+ ```
18
+
19
+ Daca nu ai `.env.local`, aplicatia foloseste implicit `http://localhost:4000`.
20
+
21
+ ## 3) Porneste frontend-ul
22
+
23
+ ```bash
24
+ npm run dev
25
+ ```
26
+
27
+ Aplicatia ruleaza pe `http://localhost:3000`.
28
+
29
+ ## 4) Pagini utile
30
+
31
+ - `http://localhost:3000/` - overview tehnologii monolith
32
+ - `http://localhost:3000/docs` - documentatie completa
33
+ - `http://localhost:3000/masini` - demo CRUD complet
34
+
35
+ ## Important
36
+
37
+ Backend-ul trebuie sa fie pornit in paralel (`backend: npm run dev`) ca pagina
38
+ `/masini` sa poata face request-uri CRUD.
@@ -0,0 +1,19 @@
1
+ const Footer = () => {
2
+ const currentYear = new Date().getFullYear();
3
+ const currentDate = new Intl.DateTimeFormat("en-US", {
4
+ month: "short",
5
+ day: "2-digit",
6
+ year: "numeric",
7
+ }).format(new Date());
8
+
9
+ return (
10
+ <footer className="border-t ">
11
+ <div className="mx-auto flex w-full items-center justify-between px-6 py-4 text-sm">
12
+ <p>© {currentYear} Demo Repo</p>
13
+ <p>Updated {currentDate}</p>
14
+ </div>
15
+ </footer>
16
+ );
17
+ };
18
+
19
+ export default Footer;
@@ -0,0 +1,34 @@
1
+ import Link from "next/link";
2
+
3
+ const navItems = [
4
+ { label: "Home", href: "/" },
5
+ { label: "Masini", href: "/masini" },
6
+ { label: "Docs", href: "/docs" },
7
+ ];
8
+
9
+ const Navbar = () => {
10
+ return (
11
+ <header className="border-b border-zinc-200 bg-zinc-50 font-sans dark:border-zinc-800 dark:bg-black">
12
+ <nav className="mx-auto flex w-full max-w-5xl items-center justify-between px-6 py-4">
13
+ <Link href="/" className="font-semibold tracking-tight">
14
+ Demo Repo
15
+ </Link>
16
+
17
+ <ul className="flex items-center gap-6 text-sm">
18
+ {navItems.map((item) => (
19
+ <li key={item.href}>
20
+ <Link
21
+ href={item.href}
22
+ className="text-zinc-700 transition-colors hover:text-zinc-950 dark:text-zinc-300 dark:hover:text-zinc-100"
23
+ >
24
+ {item.label}
25
+ </Link>
26
+ </li>
27
+ ))}
28
+ </ul>
29
+ </nav>
30
+ </header>
31
+ );
32
+ };
33
+
34
+ export default Navbar;
@@ -0,0 +1,170 @@
1
+ export default function Docs() {
2
+ return (
3
+ <section className="mx-auto flex w-full max-w-5xl flex-col gap-8 px-6 py-10">
4
+ <header className="space-y-3">
5
+ <h1 className="text-4xl font-bold">Documentatie - Monolith CRUD Demo</h1>
6
+ <p className="text-base text-zinc-700 dark:text-zinc-300">
7
+ Aceasta aplicatie este un exemplu super simplu de monolith web app:
8
+ frontend Next.js + backend Express + MySQL + Sequelize.
9
+ </p>
10
+ <p className="text-base text-zinc-700 dark:text-zinc-300">
11
+ Scopul ei este dublu: suport educational pentru juniori si punct de
12
+ pornire pentru proiecte mici care au nevoie de CRUD rapid.
13
+ </p>
14
+ </header>
15
+
16
+ <article className="space-y-4 rounded-lg border border-zinc-200 p-5 dark:border-zinc-700">
17
+ <h2 className="text-2xl font-semibold">Ce demonstreaza aplicatia</h2>
18
+ <ul className="list-disc space-y-2 pl-6 text-zinc-700 dark:text-zinc-300">
19
+ <li>Arhitectura monolitica simpla (un frontend + un backend).</li>
20
+ <li>Flux complet CRUD pentru resursa `cars` (masini).</li>
21
+ <li>Separare clara pe layere: rute, controller, model, baza de date.</li>
22
+ <li>Migrare si seed pentru popularea initiala a bazei de date.</li>
23
+ <li>Conectare frontend-backend prin API REST si CORS.</li>
24
+ </ul>
25
+ </article>
26
+
27
+ <article className="space-y-4 rounded-lg border border-zinc-200 p-5 dark:border-zinc-700">
28
+ <h2 className="text-2xl font-semibold">Flux CRUD (cap-coada)</h2>
29
+ <ol className="list-decimal space-y-2 pl-6 text-zinc-700 dark:text-zinc-300">
30
+ <li>
31
+ Utilizatorul deschide pagina <code>/masini</code> si apasa butoane CRUD.
32
+ </li>
33
+ <li>
34
+ Frontend-ul trimite request-uri la backend:{" "}
35
+ <code>GET/POST/PUT/DELETE /api/cars</code>.
36
+ </li>
37
+ <li>
38
+ Router-ul backend directioneaza request-ul catre controller-ul potrivit.
39
+ </li>
40
+ <li>
41
+ Controller-ul valideaza input-ul si foloseste modelul Sequelize <code>Car</code>.
42
+ </li>
43
+ <li>
44
+ Modelul executa query-uri in MySQL pe tabela <code>cars</code>.
45
+ </li>
46
+ <li>Backend-ul raspunde cu JSON, iar frontend-ul re-randeaza tabelul.</li>
47
+ </ol>
48
+ </article>
49
+
50
+ <article className="space-y-4 rounded-lg border border-zinc-200 p-5 dark:border-zinc-700">
51
+ <h2 className="text-2xl font-semibold">Documentatie backend pe fisiere</h2>
52
+
53
+ <div className="space-y-4">
54
+ <div className="rounded-md bg-zinc-50 p-4 dark:bg-zinc-900">
55
+ <p className="font-semibold">`backend/index.ts`</p>
56
+ <p className="text-zinc-700 dark:text-zinc-300">
57
+ Punctul de intrare al serverului. Configureaza CORS si JSON parser,
58
+ adauga endpoint-ul de health-check, inregistreaza rutele CRUD si
59
+ porneste serverul doar dupa conexiunea reusita la MySQL.
60
+ </p>
61
+ </div>
62
+
63
+ <div className="rounded-md bg-zinc-50 p-4 dark:bg-zinc-900">
64
+ <p className="font-semibold">`backend/routes/carRoutes.ts`</p>
65
+ <p className="text-zinc-700 dark:text-zinc-300">
66
+ Defineste endpoint-urile REST pentru masini:
67
+ <code> GET /</code>, <code>GET /:id</code>, <code>POST /</code>,{" "}
68
+ <code>PUT /:id</code>, <code>DELETE /:id</code>.
69
+ Este stratul de routing.
70
+ </p>
71
+ </div>
72
+
73
+ <div className="rounded-md bg-zinc-50 p-4 dark:bg-zinc-900">
74
+ <p className="font-semibold">`backend/controller/carController.ts`</p>
75
+ <p className="text-zinc-700 dark:text-zinc-300">
76
+ Contine logica CRUD efectiva. Aici se face validarea simpla a
77
+ datelor, cautarea dupa id, crearea, actualizarea si stergerea
78
+ inregistrarilor din tabela `cars`.
79
+ </p>
80
+ </div>
81
+
82
+ <div className="rounded-md bg-zinc-50 p-4 dark:bg-zinc-900">
83
+ <p className="font-semibold">`backend/models/car.ts`</p>
84
+ <p className="text-zinc-700 dark:text-zinc-300">
85
+ Defineste modelul Sequelize `Car` (campurile tabelului) si conexiunea
86
+ la MySQL folosind setarile din `config/config.cjs`.
87
+ Acesta este stratul care vorbeste direct cu baza de date.
88
+ </p>
89
+ </div>
90
+
91
+ <div className="rounded-md bg-zinc-50 p-4 dark:bg-zinc-900">
92
+ <p className="font-semibold">`backend/config/config.cjs`</p>
93
+ <p className="text-zinc-700 dark:text-zinc-300">
94
+ Configurarea centrala a DB pentru medii (`development`, `test`,
95
+ `production`) citita din variabile de mediu. Este folosita de
96
+ `sequelize-cli` la comenzi de migrate/seed.
97
+ </p>
98
+ </div>
99
+
100
+ <div className="rounded-md bg-zinc-50 p-4 dark:bg-zinc-900">
101
+ <p className="font-semibold">
102
+ `backend/migrations/20260414160000-create-cars-table.js`
103
+ </p>
104
+ <p className="text-zinc-700 dark:text-zinc-300">
105
+ Creeaza tabela `cars` cu structura corecta (`id`, `brand`, `model`,
106
+ `year`, `createdAt`, `updatedAt`). Functia `down` sterge tabela.
107
+ </p>
108
+ </div>
109
+
110
+ <div className="rounded-md bg-zinc-50 p-4 dark:bg-zinc-900">
111
+ <p className="font-semibold">
112
+ `backend/seeders/20260414160500-seed-cars.js`
113
+ </p>
114
+ <p className="text-zinc-700 dark:text-zinc-300">
115
+ Introduce date initiale in tabela `cars` (exemple de masini) pentru
116
+ demo rapid. Functia `down` sterge datele inserate.
117
+ </p>
118
+ </div>
119
+
120
+ <div className="rounded-md bg-zinc-50 p-4 dark:bg-zinc-900">
121
+ <p className="font-semibold">`backend/.env.example`</p>
122
+ <p className="text-zinc-700 dark:text-zinc-300">
123
+ Contin variabilele de mediu necesare: port backend, URL frontend,
124
+ host/user/parola/nume DB pentru MySQL.
125
+ </p>
126
+ </div>
127
+
128
+ <div className="rounded-md bg-zinc-50 p-4 dark:bg-zinc-900">
129
+ <p className="font-semibold">`backend/package.json`</p>
130
+ <p className="text-zinc-700 dark:text-zinc-300">
131
+ Lista de dependinte si script-uri utile:
132
+ <code> dev</code>, <code>build</code>, <code>db:migrate</code>,{" "}
133
+ <code>db:seed</code>, <code>db:reset</code>.
134
+ </p>
135
+ </div>
136
+ </div>
137
+ </article>
138
+
139
+ <article className="space-y-4 rounded-lg border border-zinc-200 p-5 dark:border-zinc-700">
140
+ <h2 className="text-2xl font-semibold">Comenzi utile pentru demo</h2>
141
+ <div className="space-y-2 text-zinc-700 dark:text-zinc-300">
142
+ <p>
143
+ 1. In backend: <code>npm run db:migrate</code>
144
+ </p>
145
+ <p>
146
+ 2. In backend: <code>npm run db:seed</code>
147
+ </p>
148
+ <p>
149
+ 3. In backend: <code>npm run dev</code>
150
+ </p>
151
+ <p>
152
+ 4. In frontend: <code>npm run dev</code>
153
+ </p>
154
+ <p>
155
+ 5. Deschizi <code>/masini</code> si testezi create, read, update, delete.
156
+ </p>
157
+ </div>
158
+ </article>
159
+
160
+ <article className="space-y-4 rounded-lg border border-zinc-200 p-5 dark:border-zinc-700">
161
+ <h2 className="text-2xl font-semibold">Pentru cine este acest demo</h2>
162
+ <ul className="list-disc space-y-2 pl-6 text-zinc-700 dark:text-zinc-300">
163
+ <li>Juniori care invata primul flux CRUD full-stack.</li>
164
+ <li>Echipe mici care vor un boilerplate monolitic simplu.</li>
165
+ <li>Proiecte web mici/medii unde viteza de livrare este importanta.</li>
166
+ </ul>
167
+ </article>
168
+ </section>
169
+ );
170
+ }
@@ -0,0 +1 @@
1
+ @import "tailwindcss";
@@ -0,0 +1,29 @@
1
+ import type { Metadata } from "next";
2
+ import "./globals.css";
3
+ import Navbar from "./components/Navbar";
4
+ import Footer from "./components/Footer";
5
+
6
+ // change the title and description according to the project
7
+ export const metadata: Metadata = {
8
+ title: "Demo Repo",
9
+ description: "Demo Repo by Softeneer",
10
+ };
11
+
12
+ export default function RootLayout({
13
+ children,
14
+ }: Readonly<{
15
+ children: React.ReactNode;
16
+ }>) {
17
+ return (
18
+ <html
19
+ lang="en"
20
+ className="h-full antialiased bg-white text-black dark:bg-black dark:text-white"
21
+ >
22
+ <body className="min-h-full flex flex-col">
23
+ <Navbar />
24
+ <main className="flex-1">{children}</main>
25
+ <Footer />
26
+ </body>
27
+ </html>
28
+ );
29
+ }