feat: initial infrastructure (#1)
Some checks failed
Node.js CI / Lint and Test (push) Failing after 51s
Code Analysis / SonarQube (push) Failing after 17s

### Explanation

_No response_

### Issue

_No response_

### Attestations

- [ ] I have read and agree to the [Code of Conduct](https://docs.nhcarrigan.com/community/coc/)
- [ ] I have read and agree to the [Community Guidelines](https://docs.nhcarrigan.com/community/guide/).
- [ ] My contribution complies with the [Contributor Covenant](https://docs.nhcarrigan.com/dev/covenant/).

### Dependencies

- [ ] I have pinned the dependencies to a specific patch version.

### Style

- [ ] I have run the linter and resolved any errors.
- [ ] My pull request uses an appropriate title, matching the conventional commit standards.
- [ ] My scope of feat/fix/chore/etc. correctly matches the nature of changes in my pull request.

### Tests

- [ ] My contribution adds new code, and I have added tests to cover it.
- [ ] My contribution modifies existing code, and I have updated the tests to reflect these changes.
- [ ] All new and existing tests pass locally with my changes.
- [ ] Code coverage remains at or above the configured threshold.

### Documentation

_No response_

### Versioning

_No response_

Reviewed-on: #1
Co-authored-by: Naomi Carrigan <commits@nhcarrigan.com>
Co-committed-by: Naomi Carrigan <commits@nhcarrigan.com>
This commit is contained in:
Naomi Carrigan 2025-05-22 19:05:14 -07:00 committed by Naomi Carrigan
parent 4c74ed19b2
commit e32063bfe3
35 changed files with 12717 additions and 14 deletions

44
.gitea/workflows/ci.yml Normal file
View File

@ -0,0 +1,44 @@
name: Node.js CI
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
lint:
name: Lint and Test
steps:
- name: Checkout Source Files
uses: actions/checkout@v4
- name: Use Node.js v22
uses: actions/setup-node@v4
with:
node-version: 22
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 9
- name: Install Dependencies
run: pnpm install
- name: Build internal package
run: cd packages/types && pnpm build
- name: Install again
run: pnpm install
- name: Lint Source Files
run: pnpm run lint
- name: Verify Build
run: pnpm run build
- name: Run Tests
run: pnpm run test

View File

@ -0,0 +1,34 @@
name: Code Analysis
on:
push:
branches:
- main
jobs:
sonar:
name: SonarQube
steps:
- name: Checkout Source Files
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: SonarCube Scan
uses: SonarSource/sonarqube-scan-action@v4
timeout-minutes: 10
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: "https://quality.nhcarrigan.com"
with:
args: >
-Dsonar.sources=.
-Dsonar.projectKey=nutrition-tracker
- name: SonarQube Quality Gate check
uses: sonarsource/sonarqube-quality-gate-action@v1
with:
pollingTimeoutSec: 600
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: "https://quality.nhcarrigan.com"

15
.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
# Packages
node_modules
npm-debug.log
yarn-error.log
# Compiled output
prod
dist
tmp
out-tsc
bazel-out
# Miscellaneous
.angular
.turbo

10
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,10 @@
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"eslint.validate": ["typescript"],
"sonarlint.connectedMode.project": {
"connectionId": "nhcarrigan",
"projectKey": "nhcarrigan_nutrition-tracker"
}
}

View File

@ -1,20 +1,10 @@
# New Repository Template
# Lucinda
This template contains all of our basic files for a new GitHub repository. There is also a handy workflow that will create an issue on a new repository made from this template, with a checklist for the steps we usually take in setting up a new repository.
If you're starting a Node.JS project with TypeScript, we have a [specific template](https://github.com/naomi-lgbt/nodejs-typescript-template) for that purpose.
## Readme
Delete all of the above text (including this line), and uncomment the below text to use our standard readme template.
<!-- # Project Name
Project Description
Lucinda aims to be a full-featured task management system, with a Kanban style approach and cloud-based storage!
## Live Version
This page is currently deployed. [View the live website.]
This page is currently deployed. [View the live website.](https://lucinda.nhcarrigan.com)
## Feedback and Bugs
@ -36,4 +26,4 @@ Copyright held by Naomi Carrigan.
## Contact
We may be contacted through our [Chat Server](http://chat.nhcarrigan.com) or via email at `contact@nhcarrigan.com`. -->
We may be contacted through our [Chat Server](http://chat.nhcarrigan.com) or via email at `contact@nhcarrigan.com`.

17
client/.editorconfig Normal file
View File

@ -0,0 +1,17 @@
# Editor configuration, see https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.ts]
quote_type = single
ij_typescript_use_double_quotes = false
[*.md]
max_line_length = off
trim_trailing_whitespace = false

42
client/.gitignore vendored Normal file
View File

@ -0,0 +1,42 @@
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Node
/node_modules
npm-debug.log
yarn-error.log
# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
# System files
.DS_Store
Thumbs.db

99
client/angular.json Normal file
View File

@ -0,0 +1,99 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"client": {
"projectType": "application",
"schematics": {},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"options": {
"outputPath": "dist/client",
"index": "src/index.html",
"browser": "src/main.ts",
"polyfills": [
"zone.js"
],
"tsConfig": "tsconfig.app.json",
"assets": [
{
"glob": "**/*",
"input": "public"
}
],
"styles": [
"src/styles.css"
],
"scripts": []
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kB",
"maximumError": "1MB"
},
{
"type": "anyComponentStyle",
"maximumWarning": "4kB",
"maximumError": "8kB"
}
],
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"buildTarget": "client:build:production"
},
"development": {
"buildTarget": "client:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"polyfills": [
"zone.js",
"zone.js/testing"
],
"tsConfig": "tsconfig.spec.json",
"assets": [
{
"glob": "**/*",
"input": "public"
}
],
"styles": [
"src/styles.css"
],
"scripts": []
}
}
}
}
},
"cli": {
"analytics": "8236f909-6e2b-4976-92f6-4e1b9fe8f4ab"
}
}

22
client/eslint.config.js Normal file
View File

@ -0,0 +1,22 @@
import NaomisConfig from "@nhcarrigan/eslint-config";
export default [
...NaomisConfig,
{
rules: {
"no-console": "off",
"new-cap": "off",
"@typescript-eslint/naming-convention": "off",
"jsdoc/require-jsdoc": "off",
"jsdoc/require-param": "off",
"jsdoc/require-returns": "off",
"@typescript-eslint/no-useless-constructor": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/consistent-type-assertions": "off",
"@typescript-eslint/no-extraneous-class": "off",
"stylistic/no-multi-spaces": "off",
"unicorn/filename-case": "off",
"@typescript-eslint/consistent-type-imports": "off"
},
},
]

38
client/package.json Normal file
View File

@ -0,0 +1,38 @@
{
"name": "vitalia-client",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"dev": "ng serve",
"build": "ng build",
"test": "echo 'No tests specified' && exit 0",
"lint": "eslint ./src --max-warnings 0"
},
"type": "module",
"private": true,
"dependencies": {
"@angular/common": "^19.2.10",
"@angular/compiler": "^19.2.10",
"@angular/core": "^19.2.10",
"@angular/forms": "^19.2.10",
"@angular/platform-browser": "^19.2.10",
"@angular/platform-browser-dynamic": "^19.2.10",
"@angular/router": "^19.2.10",
"rxjs": "~7.8.2",
"tslib": "^2.8.1",
"zone.js": "~0.15.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "^19.2.11",
"@angular/cli": "^19.2.11",
"@angular/compiler-cli": "^19.2.10",
"@types/jasmine": "~5.1.8",
"jasmine-core": "~5.7.1",
"karma": "~6.4.4",
"karma-chrome-launcher": "~3.2.0",
"karma-coverage": "~2.2.1",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0",
"typescript": "~5.8.3"
}
}

BIN
client/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

View File

@ -0,0 +1,3 @@
<main>
<router-outlet></router-outlet>
</main>

View File

@ -0,0 +1,18 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { Component } from "@angular/core";
import { RouterOutlet } from "@angular/router";
@Component({
imports: [ RouterOutlet ],
selector: "app-root",
styleUrl: "./app.component.css",
templateUrl: "./app.component.html",
})
export class AppComponent {
public title = "Vitalia";
}

View File

@ -0,0 +1,16 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { ApplicationConfig, provideZoneChangeDetection } from "@angular/core";
import { provideRouter } from "@angular/router";
import { routes } from "./app.routes";
export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(routes),
],
};

View File

@ -0,0 +1,13 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { Routes } from "@angular/router";
import { LandingComponent } from "./landing/landing.component.js";
export const routes: Routes = [
{ path: "", pathMatch: "full", redirectTo: "/landing" },
{ component: LandingComponent, path: "landing" },
];

View File

@ -0,0 +1,7 @@
<h1>Lucinda</h1>
<img src="https://cdn.nhcarrigan.com/new-avatars/lucinda-full.png" alt="Lucinda" width="300">
<p>Lucinda is your personal task manager, here to help you get organised and stay on track to meet your goals.</p>
<p>Stay tuned, we're hard at work to bring her to life!</p>

View File

@ -0,0 +1,17 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { Component } from "@angular/core";
@Component({
imports: [],
selector: "app-landing",
styleUrl: "./landing.component.css",
templateUrl: "./landing.component.html",
})
export class LandingComponent {
}

14
client/src/index.html Normal file
View File

@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Lucinda</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
</body>
<script src="https://cdn.nhcarrigan.com/headers/index.js"></script>
</html>

15
client/src/main.ts Normal file
View File

@ -0,0 +1,15 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { bootstrapApplication } from "@angular/platform-browser";
import { AppComponent } from "./app/app.component";
import { appConfig } from "./app/app.config";
bootstrapApplication(AppComponent, appConfig).
// eslint-disable-next-line unicorn/prefer-top-level-await -- it's an angular thing?
catch((error: unknown) => {
console.error(error);
});

1
client/src/styles.css Normal file
View File

@ -0,0 +1 @@
/* You can add global styles to this file, and also import other style files */

15
client/tsconfig.app.json Normal file
View File

@ -0,0 +1,15 @@
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": []
},
"files": [
"src/main.ts"
],
"include": [
"src/**/*.d.ts"
]
}

27
client/tsconfig.json Normal file
View File

@ -0,0 +1,27 @@
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
"isolatedModules": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"moduleResolution": "bundler",
"importHelpers": true,
"target": "ES2022",
"module": "ES2022"
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}

15
client/tsconfig.spec.json Normal file
View File

@ -0,0 +1,15 @@
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": [
"jasmine"
]
},
"include": [
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}

26
package.json Normal file
View File

@ -0,0 +1,26 @@
{
"name": "lucinda",
"version": "0.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"dev": "turbo run dev",
"build": "turbo run build",
"lint": "turbo run lint",
"test": "turbo run test"
},
"keywords": [],
"author": "",
"license": "ISC",
"packageManager": "pnpm@10.10.0",
"devDependencies": {
"@nhcarrigan/eslint-config": "5.2.0",
"eslint": "9.26.0",
"prisma": "6.7.0",
"turbo": "2.5.3"
},
"dependencies": {
"@prisma/client": "6.7.0"
}
}

12074
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

4
pnpm-workspace.yaml Normal file
View File

@ -0,0 +1,4 @@
packages:
- "client"
- "server"
- "packages/types"

18
server/eslint.config.js Normal file
View File

@ -0,0 +1,18 @@
import NaomisConfig from "@nhcarrigan/eslint-config";
export default [
...NaomisConfig,
{
files: ["src/routes/*.ts", "src/hooks/*.ts"],
rules: {
"@typescript-eslint/require-await": "off",
"@typescript-eslint/no-misused-promises": "off"
},
},
{
files: ["src/handlers/**/*.ts"],
rules: {
"@typescript-eslint/naming-convention": "off",
},
},
];

28
server/package.json Normal file
View File

@ -0,0 +1,28 @@
{
"name": "vitalia-server",
"version": "0.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"dev": "tsx src/index.ts --watch",
"build": "tsc",
"start": "op run --env-file=./prod.env -- node prod/index.js",
"lint": "eslint ./src --max-warnings 0",
"test": "echo 'No tests specified' && exit 0"
},
"keywords": [],
"author": "",
"license": "ISC",
"packageManager": "pnpm@10.10.0",
"dependencies": {
"@fastify/cors": "11.0.1",
"@nhcarrigan/logger": "1.0.0",
"fastify": "5.3.2"
},
"devDependencies": {
"@nhcarrigan/typescript-config": "4.0.0",
"tsx": "4.19.4",
"typescript": "~5.8.3"
}
}

1
server/prod.env Normal file
View File

@ -0,0 +1 @@
LOG_TOKEN="op://Environment Variables - Naomi/Alert Server/api_auth"

40
server/src/index.ts Normal file
View File

@ -0,0 +1,40 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import cors from "@fastify/cors";
import fastify from "fastify";
import { logger } from "./utils/logger.js";
/**
* Starts up a web server for health monitoring.
*/
try {
const server = fastify({
logger: false,
});
server.register(cors, {
origin: "*",
});
server.get("/", async(_request, reply) => {
reply.send({ message: "Hello, world!" });
});
server.listen({ port: 12_346 }, (error) => {
if (error) {
void logger.error("instantiate server", error);
return;
}
void logger.log("debug", "Server listening on port 12346.");
});
} catch (error) {
if (error instanceof Error) {
void logger.error("instantiate server", error);
} else {
void logger.error("instantiate server", new Error("Unknown error"));
}
}

View File

@ -0,0 +1,12 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { Logger } from "@nhcarrigan/logger";
export const logger = new Logger(
"Vitalia",
process.env.LOG_TOKEN ?? "",
);

7
server/tsconfig.json Normal file
View File

@ -0,0 +1,7 @@
{
"extends": "@nhcarrigan/typescript-config",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./prod",
}
}

21
turbo.json Normal file
View File

@ -0,0 +1,21 @@
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["^lint"],
"outputs": ["prod/**"]
},
"test": {
"dependsOn": [],
"outputs": []
},
"lint": {
"dependsOn": [],
"outputs": []
},
"dev": {
"dependsOn": [],
"outputs": []
}
}
}