Aggiungo CMS Strapi self-hosted per gestire rosa, classifica e storico partite
Introduce lo stack Strapi dockerizzato (infra/strapi/), sullo stesso Postgres dello stack Supabase con un database logico separato, dietro Caddy su /cms/*. L'editing dei dati avviene solo nel pannello admin nativo di Strapi. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,13 @@ VITE_SUPABASE_URL=https://tuodominio.it/api
|
||||
VITE_SUPABASE_PUBLISHABLE_KEY=
|
||||
SUPABASE_SERVICE_ROLE_KEY=
|
||||
|
||||
# CMS Strapi (rosa, classifica, storico partite, scout finalizzato) — vedi infra/strapi/.
|
||||
# VITE_STRAPI_URL è pubblico (letture aperte, come le tabelle Supabase "open RLS"), mentre
|
||||
# STRAPI_WRITE_TOKEN è un token con permessi di sola creazione su scout-match-finale: NON deve
|
||||
# mai avere il prefisso VITE_ (finirebbe nel bundle client) e va letto solo lato server.
|
||||
VITE_STRAPI_URL=https://tuodominio.it/cms
|
||||
STRAPI_WRITE_TOKEN=
|
||||
|
||||
# Notifiche push (genera con: npx web-push generate-vapid-keys)
|
||||
VAPID_PUBLIC_KEY=
|
||||
VAPID_PRIVATE_KEY=
|
||||
|
||||
@@ -152,24 +152,48 @@ Passo passo, sul server di produzione:
|
||||
docker exec -i supabase-db psql -U postgres -d postgres -v ON_ERROR_STOP=1 < "$f"
|
||||
done
|
||||
```
|
||||
3. **Reverse proxy TLS**: copia `infra/supabase/docker/Caddyfile.example` in `Caddyfile`,
|
||||
3. **Stack Strapi** (CMS admin per rosa, classifica, storico partite, scout finalizzato — vedi
|
||||
`infra/strapi/`): usa lo stesso Postgres dello stack Supabase, in un database logico separato:
|
||||
```sh
|
||||
docker exec -i supabase-db psql -U postgres -c "CREATE DATABASE strapi;"
|
||||
docker exec -i supabase-db psql -U postgres -c "CREATE USER strapi WITH PASSWORD '...';"
|
||||
docker exec -i supabase-db psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE strapi TO strapi;"
|
||||
cp infra/strapi/.env.production.example infra/strapi/.env
|
||||
```
|
||||
Compila in `infra/strapi/.env` i secret (`APP_KEYS`, `JWT_SECRET`, ecc. — genera ognuno con
|
||||
`openssl rand -base64 32`) e `DATABASE_PASSWORD` (la stessa scelta sopra), poi:
|
||||
```sh
|
||||
cd infra/strapi
|
||||
docker compose up -d --build
|
||||
```
|
||||
Al primo accesso su `<dominio>/cms/admin` crea l'utente amministratore Strapi. Da lì, un solo
|
||||
giro di setup manuale (nessuna automazione: i permessi Strapi si abilitano solo dall'admin UI):
|
||||
in Settings → Users & Permissions Plugin → Roles → Public abilita `find`/`findOne` per
|
||||
`Giocatore`, `Riga-classifica` e `Match-storico`; poi in Settings → API Tokens genera un token
|
||||
con permesso `create` solo su `Scout-match-finale` (va in `STRAPI_WRITE_TOKEN` nell'env
|
||||
dell'app, punto 5). Infine inserisci a mano rosa/classifica/storico nelle rispettive collezioni
|
||||
(i valori di partenza sono nella cronologia git di `src/lib/crapp-data.ts`, prima che venissero
|
||||
spostati qui).
|
||||
4. **Reverse proxy TLS**: copia `infra/supabase/docker/Caddyfile.example` in `Caddyfile`,
|
||||
sostituisci il dominio del punto 0, poi `caddy run --config Caddyfile` (o come container).
|
||||
Gestisce automaticamente il certificato Let's Encrypt.
|
||||
4. **Env dell'app**:
|
||||
5. **Env dell'app**:
|
||||
```sh
|
||||
cp .env.production.example .env
|
||||
```
|
||||
Compila `VITE_SUPABASE_URL` (dominio del punto 0 + `/api`),
|
||||
`VITE_SUPABASE_PUBLISHABLE_KEY` (= `ANON_KEY` dello stack), `SUPABASE_SERVICE_ROLE_KEY`
|
||||
(= `SERVICE_ROLE_KEY`), e le chiavi `VAPID_*` reali (`npx web-push generate-vapid-keys`).
|
||||
5. **Build e avvio**:
|
||||
(= `SERVICE_ROLE_KEY`), `VITE_STRAPI_URL` (dominio del punto 0 + `/cms`), `STRAPI_WRITE_TOKEN`
|
||||
(il token generato al punto 3), e le chiavi `VAPID_*` reali
|
||||
(`npx web-push generate-vapid-keys`).
|
||||
6. **Build e avvio**:
|
||||
```sh
|
||||
bun run build
|
||||
node .output/server/index.mjs # ascolta su PORT (default 3000)
|
||||
```
|
||||
Tienilo vivo con un process manager (pm2/systemd) — il Caddy del punto 3 lo espone via TLS
|
||||
Tienilo vivo con un process manager (pm2/systemd) — il Caddy del punto 4 lo espone via TLS
|
||||
sull'hostname app.
|
||||
6. **Job pianificati** — gli endpoint `src/routes/api/public/promemoria-palloni.ts` e
|
||||
7. **Job pianificati** — gli endpoint `src/routes/api/public/promemoria-palloni.ts` e
|
||||
`sollecita-presenze.ts` vanno richiamati periodicamente via HTTP POST da un cron di sistema o
|
||||
`pg_cron`: non partono da soli.
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
HOST=0.0.0.0
|
||||
PORT=1337
|
||||
APP_KEYS="toBeModified1,toBeModified2"
|
||||
API_TOKEN_SALT=tobemodified
|
||||
ADMIN_JWT_SECRET=tobemodified
|
||||
TRANSFER_TOKEN_SALT=tobemodified
|
||||
JWT_SECRET=tobemodified
|
||||
ENCRYPTION_KEY=tobemodified
|
||||
@@ -0,0 +1,23 @@
|
||||
# TEMPLATE DI PRODUZIONE per il CMS Strapi (rosa, classifica, storico partite, scout finalizzato).
|
||||
# Copia in .env accanto a docker-compose.yml e compila. Rigenera SEMPRE secret nuovi in produzione,
|
||||
# non riusare quelli di sviluppo — un valore per riga, generabili con: openssl rand -base64 32
|
||||
|
||||
HOST=0.0.0.0
|
||||
PORT=1337
|
||||
|
||||
APP_KEYS=
|
||||
API_TOKEN_SALT=
|
||||
ADMIN_JWT_SECRET=
|
||||
JWT_SECRET=
|
||||
TRANSFER_TOKEN_SALT=
|
||||
ENCRYPTION_KEY=
|
||||
|
||||
# Stesso cluster Postgres dello stack Supabase self-hosted (infra/supabase/docker/), database
|
||||
# logico separato — vedi README "Produzione", passo Strapi.
|
||||
DATABASE_CLIENT=postgres
|
||||
DATABASE_HOST=db
|
||||
DATABASE_PORT=5432
|
||||
DATABASE_NAME=strapi
|
||||
DATABASE_USERNAME=strapi
|
||||
DATABASE_PASSWORD=
|
||||
DATABASE_SSL=false
|
||||
@@ -0,0 +1,131 @@
|
||||
############################
|
||||
# OS X
|
||||
############################
|
||||
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
Icon
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
._*
|
||||
|
||||
|
||||
############################
|
||||
# Linux
|
||||
############################
|
||||
|
||||
*~
|
||||
|
||||
|
||||
############################
|
||||
# Windows
|
||||
############################
|
||||
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
Desktop.ini
|
||||
$RECYCLE.BIN/
|
||||
*.cab
|
||||
*.msi
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
|
||||
############################
|
||||
# Packages
|
||||
############################
|
||||
|
||||
*.7z
|
||||
*.csv
|
||||
*.dat
|
||||
*.dmg
|
||||
*.gz
|
||||
*.iso
|
||||
*.jar
|
||||
*.rar
|
||||
*.tar
|
||||
*.zip
|
||||
*.com
|
||||
*.class
|
||||
*.dll
|
||||
*.exe
|
||||
*.o
|
||||
*.seed
|
||||
*.so
|
||||
*.swo
|
||||
*.swp
|
||||
*.swn
|
||||
*.swm
|
||||
*.out
|
||||
*.pid
|
||||
|
||||
|
||||
############################
|
||||
# Logs and databases
|
||||
############################
|
||||
|
||||
.tmp
|
||||
*.log
|
||||
*.sql
|
||||
*.sqlite
|
||||
*.sqlite3
|
||||
|
||||
|
||||
############################
|
||||
# Misc.
|
||||
############################
|
||||
|
||||
*#
|
||||
ssl
|
||||
.idea
|
||||
nbproject
|
||||
public/uploads/*
|
||||
!public/uploads/.gitkeep
|
||||
.tsbuildinfo
|
||||
.eslintcache
|
||||
|
||||
############################
|
||||
# Node.js
|
||||
############################
|
||||
|
||||
lib-cov
|
||||
lcov.info
|
||||
pids
|
||||
logs
|
||||
results
|
||||
node_modules
|
||||
.node_history
|
||||
|
||||
############################
|
||||
# Package managers
|
||||
############################
|
||||
|
||||
.yarn/*
|
||||
!.yarn/cache
|
||||
!.yarn/unplugged
|
||||
!.yarn/patches
|
||||
!.yarn/releases
|
||||
!.yarn/sdks
|
||||
!.yarn/versions
|
||||
.pnp.*
|
||||
yarn-error.log
|
||||
|
||||
############################
|
||||
# Tests
|
||||
############################
|
||||
|
||||
coverage
|
||||
|
||||
############################
|
||||
# Strapi
|
||||
############################
|
||||
|
||||
.env
|
||||
license.txt
|
||||
exports
|
||||
.strapi
|
||||
dist
|
||||
build
|
||||
.strapi-updater.json
|
||||
.strapi-cloud.json
|
||||
@@ -0,0 +1,15 @@
|
||||
# Immagine di produzione per il CMS admin (rosa, classifica, storico partite, scout finalizzato).
|
||||
# Build multi-stage: installa e builda l'admin panel, poi copia solo l'output nell'immagine finale.
|
||||
FROM node:20-slim AS build
|
||||
WORKDIR /opt/app
|
||||
COPY package.json package-lock.json* ./
|
||||
RUN npm install
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
FROM node:20-slim
|
||||
WORKDIR /opt/app
|
||||
ENV NODE_ENV=production
|
||||
COPY --from=build /opt/app .
|
||||
EXPOSE 1337
|
||||
CMD ["npm", "run", "start"]
|
||||
@@ -0,0 +1,61 @@
|
||||
# 🚀 Getting started with Strapi
|
||||
|
||||
Strapi comes with a full featured [Command Line Interface](https://docs.strapi.io/dev-docs/cli) (CLI) which lets you scaffold and manage your project in seconds.
|
||||
|
||||
### `develop`
|
||||
|
||||
Start your Strapi application with autoReload enabled. [Learn more](https://docs.strapi.io/dev-docs/cli#strapi-develop)
|
||||
|
||||
```
|
||||
npm run develop
|
||||
# or
|
||||
yarn develop
|
||||
```
|
||||
|
||||
### `start`
|
||||
|
||||
Start your Strapi application with autoReload disabled. [Learn more](https://docs.strapi.io/dev-docs/cli#strapi-start)
|
||||
|
||||
```
|
||||
npm run start
|
||||
# or
|
||||
yarn start
|
||||
```
|
||||
|
||||
### `build`
|
||||
|
||||
Build your admin panel. [Learn more](https://docs.strapi.io/dev-docs/cli#strapi-build)
|
||||
|
||||
```
|
||||
npm run build
|
||||
# or
|
||||
yarn build
|
||||
```
|
||||
|
||||
## ⚙️ Deployment
|
||||
|
||||
Strapi gives you many possible deployment options for your project including [Strapi Cloud](https://cloud.strapi.io). Browse the [deployment section of the documentation](https://docs.strapi.io/dev-docs/deployment) to find the best solution for your use case.
|
||||
|
||||
```
|
||||
yarn strapi deploy
|
||||
```
|
||||
|
||||
## 📚 Learn more
|
||||
|
||||
- [Resource center](https://strapi.io/resource-center) - Strapi resource center.
|
||||
- [Strapi documentation](https://docs.strapi.io) - Official Strapi documentation.
|
||||
- [Strapi tutorials](https://strapi.io/tutorials) - List of tutorials made by the core team and the community.
|
||||
- [Strapi blog](https://strapi.io/blog) - Official Strapi blog containing articles made by the Strapi team and the community.
|
||||
- [Changelog](https://strapi.io/changelog) - Find out about the Strapi product updates, new features and general improvements.
|
||||
|
||||
Feel free to check out the [Strapi GitHub repository](https://github.com/strapi/strapi). Your feedback and contributions are welcome!
|
||||
|
||||
## ✨ Community
|
||||
|
||||
- [Discord](https://discord.strapi.io) - Come chat with the Strapi community including the core team.
|
||||
- [Forum](https://forum.strapi.io/) - Place to discuss, ask questions and find answers, show your Strapi project and get feedback or just talk with other Community members.
|
||||
- [Awesome Strapi](https://github.com/strapi/awesome-strapi) - A curated list of awesome things related to Strapi.
|
||||
|
||||
---
|
||||
|
||||
<sub>🤫 Psst! [Strapi is hiring](https://strapi.io/careers).</sub>
|
||||
@@ -0,0 +1,21 @@
|
||||
module.exports = ({ env }) => ({
|
||||
auth: {
|
||||
secret: env('ADMIN_JWT_SECRET'),
|
||||
},
|
||||
apiToken: {
|
||||
salt: env('API_TOKEN_SALT'),
|
||||
},
|
||||
transfer: {
|
||||
token: {
|
||||
salt: env('TRANSFER_TOKEN_SALT'),
|
||||
},
|
||||
},
|
||||
secrets: {
|
||||
encryptionKey: env('ENCRYPTION_KEY'),
|
||||
},
|
||||
flags: {
|
||||
nps: env.bool('FLAG_NPS', true),
|
||||
promoteEE: env.bool('FLAG_PROMOTE_EE', true),
|
||||
docLinks: env.bool('FLAG_DOC_LINKS', true),
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
module.exports = {
|
||||
rest: {
|
||||
defaultLimit: 25,
|
||||
maxLimit: 100,
|
||||
withCount: true,
|
||||
strictParams: true,
|
||||
},
|
||||
documents: {
|
||||
strictParams: true,
|
||||
strictRelations: true,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,72 @@
|
||||
/** @import { Core } from '@strapi/strapi' */
|
||||
|
||||
const path = require('path');
|
||||
const { isDatabaseClientKind } = require('@strapi/database');
|
||||
|
||||
module.exports = ({ env }) => {
|
||||
const client = env('DATABASE_CLIENT', 'sqlite');
|
||||
|
||||
if (!isDatabaseClientKind(client)) {
|
||||
throw new Error(
|
||||
`Unsupported DATABASE_CLIENT: ${client}. Use "postgres", "mysql", or "sqlite".`
|
||||
);
|
||||
}
|
||||
|
||||
/** @type {Record<Core.Config.Database.ClientKind, Core.Config.Database['connection']>} */
|
||||
const connections = {
|
||||
mysql: {
|
||||
client: 'mysql',
|
||||
connection: {
|
||||
host: env('DATABASE_HOST', 'localhost'),
|
||||
port: env.int('DATABASE_PORT', 3306),
|
||||
database: env('DATABASE_NAME', 'strapi'),
|
||||
user: env('DATABASE_USERNAME', 'strapi'),
|
||||
password: env('DATABASE_PASSWORD', 'strapi'),
|
||||
ssl: env.bool('DATABASE_SSL', false) && {
|
||||
key: env('DATABASE_SSL_KEY', undefined),
|
||||
cert: env('DATABASE_SSL_CERT', undefined),
|
||||
ca: env('DATABASE_SSL_CA', undefined),
|
||||
capath: env('DATABASE_SSL_CAPATH', undefined),
|
||||
cipher: env('DATABASE_SSL_CIPHER', undefined),
|
||||
rejectUnauthorized: env.bool('DATABASE_SSL_REJECT_UNAUTHORIZED', true),
|
||||
},
|
||||
},
|
||||
pool: { min: env.int('DATABASE_POOL_MIN', 2), max: env.int('DATABASE_POOL_MAX', 10) },
|
||||
},
|
||||
postgres: {
|
||||
client: 'postgres',
|
||||
connection: {
|
||||
connectionString: env('DATABASE_URL'),
|
||||
host: env('DATABASE_HOST', 'localhost'),
|
||||
port: env.int('DATABASE_PORT', 5432),
|
||||
database: env('DATABASE_NAME', 'strapi'),
|
||||
user: env('DATABASE_USERNAME', 'strapi'),
|
||||
password: env('DATABASE_PASSWORD', 'strapi'),
|
||||
ssl: env.bool('DATABASE_SSL', false) && {
|
||||
key: env('DATABASE_SSL_KEY', undefined),
|
||||
cert: env('DATABASE_SSL_CERT', undefined),
|
||||
ca: env('DATABASE_SSL_CA', undefined),
|
||||
capath: env('DATABASE_SSL_CAPATH', undefined),
|
||||
cipher: env('DATABASE_SSL_CIPHER', undefined),
|
||||
rejectUnauthorized: env.bool('DATABASE_SSL_REJECT_UNAUTHORIZED', true),
|
||||
},
|
||||
schema: env('DATABASE_SCHEMA', 'public'),
|
||||
},
|
||||
pool: { min: env.int('DATABASE_POOL_MIN', 2), max: env.int('DATABASE_POOL_MAX', 10) },
|
||||
},
|
||||
sqlite: {
|
||||
client: 'sqlite',
|
||||
connection: {
|
||||
filename: path.join(__dirname, '..', env('DATABASE_FILENAME', '.tmp/data.db')),
|
||||
},
|
||||
useNullAsDefault: true,
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
connection: {
|
||||
...connections[client],
|
||||
acquireConnectionTimeout: env.int('DATABASE_CONNECTION_TIMEOUT', 60000),
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
module.exports = [
|
||||
'strapi::logger',
|
||||
'strapi::errors',
|
||||
'strapi::security',
|
||||
'strapi::cors',
|
||||
'strapi::poweredBy',
|
||||
'strapi::query',
|
||||
'strapi::body',
|
||||
'strapi::session',
|
||||
'strapi::favicon',
|
||||
'strapi::public',
|
||||
];
|
||||
@@ -0,0 +1,41 @@
|
||||
const allowedMediaTypes = [
|
||||
'image/*',
|
||||
'video/*',
|
||||
'audio/*',
|
||||
'application/pdf',
|
||||
'application/msword',
|
||||
'application/vnd.openxmlformats-officedocument.*',
|
||||
'text/plain',
|
||||
'text/csv',
|
||||
];
|
||||
|
||||
const deniedTypes = [
|
||||
'image/svg+xml',
|
||||
'application/vnd.microsoft.portable-executable',
|
||||
'application/x-msdownload',
|
||||
'application/x-msdos-program',
|
||||
'application/x-executable',
|
||||
'application/x-dosexec',
|
||||
'application/x-sh',
|
||||
'text/x-shellscript',
|
||||
'application/x-mach-binary',
|
||||
];
|
||||
|
||||
module.exports = () => ({
|
||||
'users-permissions': {
|
||||
config: {
|
||||
jwtManagement: 'refresh',
|
||||
sessions: {
|
||||
httpOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
upload: {
|
||||
config: {
|
||||
security: {
|
||||
allowedTypes: allowedMediaTypes,
|
||||
deniedTypes,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
module.exports = ({ env }) => ({
|
||||
host: env('HOST', '0.0.0.0'),
|
||||
port: env.int('PORT', 1337),
|
||||
app: {
|
||||
keys: env.array('APP_KEYS'),
|
||||
},
|
||||
webhooks: {
|
||||
populateRelations: env.bool('WEBHOOKS_POPULATE_RELATIONS', false),
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
# CMS admin (rosa, classifica, storico partite, scout finalizzato) per CrAPP.
|
||||
# Si appoggia allo stesso Postgres dello stack Supabase self-hosted (infra/supabase/docker/,
|
||||
# progetto compose "supabase", rete di default "supabase_default" — verifica con
|
||||
# `docker network ls` se il nome differisce) con un database logico separato ("strapi"), invece
|
||||
# di un secondo container Postgres: stesso isolamento dei dati, metà del carico su hardware
|
||||
# limitato (es. Raspberry Pi 4).
|
||||
#
|
||||
# Uso:
|
||||
# cp .env.production.example .env # compila i secret, vedi README "Produzione"
|
||||
# docker compose up -d
|
||||
#
|
||||
# Crea prima il database logico (una tantum, vedi README):
|
||||
# docker exec -i supabase-db psql -U postgres -c "CREATE DATABASE strapi;"
|
||||
# docker exec -i supabase-db psql -U postgres -c "CREATE USER strapi WITH PASSWORD '...';"
|
||||
# docker exec -i supabase-db psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE strapi TO strapi;"
|
||||
|
||||
services:
|
||||
strapi:
|
||||
build: .
|
||||
container_name: crapp-strapi
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
# Solo locale, come api-gw dello stack Supabase — dietro il reverse proxy TLS (Caddyfile).
|
||||
- "127.0.0.1:1337:1337"
|
||||
volumes:
|
||||
- strapi-uploads:/opt/app/public/uploads
|
||||
networks:
|
||||
- supabase
|
||||
|
||||
networks:
|
||||
supabase:
|
||||
name: supabase_default
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
strapi-uploads:
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 497 B |
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "nodenext",
|
||||
"moduleResolution": "nodenext",
|
||||
"target": "ES2021",
|
||||
"checkJs": true,
|
||||
"allowJs": true
|
||||
}
|
||||
}
|
||||
Generated
+21579
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "strapi",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"description": "A Strapi application",
|
||||
"scripts": {
|
||||
"build": "strapi build",
|
||||
"console": "strapi console",
|
||||
"deploy": "strapi deploy",
|
||||
"dev": "strapi develop",
|
||||
"develop": "strapi develop",
|
||||
"start": "strapi start",
|
||||
"strapi": "strapi",
|
||||
"upgrade": "npx @strapi/upgrade latest",
|
||||
"upgrade:dry": "npx @strapi/upgrade latest --dry"
|
||||
},
|
||||
"dependencies": {
|
||||
"@strapi/database": "5.52.2",
|
||||
"@strapi/plugin-cloud": "5.52.2",
|
||||
"@strapi/plugin-users-permissions": "5.52.2",
|
||||
"@strapi/strapi": "5.52.2",
|
||||
"pg": "8.20.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"react-router-dom": "^6.30.3",
|
||||
"styled-components": "^6.0.0"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"engines": {
|
||||
"node": ">=20.0.0 <=26.x.x",
|
||||
"npm": ">=6.0.0"
|
||||
},
|
||||
"strapi": {
|
||||
"uuid": "7cc5aaf5-d55f-4ee8-9141-02e2dd523a1c",
|
||||
"installId": "8e493229589483c80fc99464f570c7c84540d2c64f9fe878c9677834e48e6fa1"
|
||||
},
|
||||
"allowScripts": {
|
||||
"esbuild@0.28.2": true,
|
||||
"esbuild@0.21.5": true,
|
||||
"@swc/core@1.16.1": true,
|
||||
"core-js-pure@3.50.0": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# To prevent search engines from seeing the site altogether, uncomment the next two lines:
|
||||
# User-Agent: *
|
||||
# Disallow: /
|
||||
@@ -0,0 +1,39 @@
|
||||
const config = {
|
||||
locales: [
|
||||
// 'ar',
|
||||
// 'fr',
|
||||
// 'cs',
|
||||
// 'de',
|
||||
// 'da',
|
||||
// 'es',
|
||||
// 'he',
|
||||
// 'id',
|
||||
// 'it',
|
||||
// 'ja',
|
||||
// 'ko',
|
||||
// 'ms',
|
||||
// 'nl',
|
||||
// 'no',
|
||||
// 'pl',
|
||||
// 'pt-BR',
|
||||
// 'pt',
|
||||
// 'ru',
|
||||
// 'sk',
|
||||
// 'sv',
|
||||
// 'th',
|
||||
// 'tr',
|
||||
// 'uk',
|
||||
// 'vi',
|
||||
// 'zh-Hans',
|
||||
// 'zh',
|
||||
],
|
||||
};
|
||||
|
||||
const bootstrap = (app) => {
|
||||
console.log(app);
|
||||
};
|
||||
|
||||
export default {
|
||||
config,
|
||||
bootstrap,
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
const { mergeConfig } = require('vite');
|
||||
|
||||
module.exports = (config) => {
|
||||
// Important: always return the modified config
|
||||
return mergeConfig(config, {
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': '/src',
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"kind": "collectionType",
|
||||
"collectionName": "giocatori",
|
||||
"info": {
|
||||
"singularName": "giocatore",
|
||||
"pluralName": "giocatoris",
|
||||
"displayName": "Giocatore",
|
||||
"description": "Anagrafica rosa CRAP Volley. Le statistiche (presenze, MVP, ecc.) restano calcolate lato app, non vivono qui."
|
||||
},
|
||||
"options": {
|
||||
"draftAndPublish": false
|
||||
},
|
||||
"pluginOptions": {},
|
||||
"attributes": {
|
||||
"codice": {
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"unique": true,
|
||||
"regex": "^g[0-9]+$"
|
||||
},
|
||||
"nome": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"numero": {
|
||||
"type": "integer",
|
||||
"required": true
|
||||
},
|
||||
"ruolo": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"nascita": {
|
||||
"type": "date",
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
const { createCoreController } = require('@strapi/strapi').factories;
|
||||
|
||||
module.exports = createCoreController('api::giocatore.giocatore');
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
const { createCoreRouter } = require('@strapi/strapi').factories;
|
||||
|
||||
module.exports = createCoreRouter('api::giocatore.giocatore');
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
const { createCoreService } = require('@strapi/strapi').factories;
|
||||
|
||||
module.exports = createCoreService('api::giocatore.giocatore');
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"kind": "collectionType",
|
||||
"collectionName": "match_storici",
|
||||
"info": {
|
||||
"singularName": "match-storico",
|
||||
"pluralName": "match-storicos",
|
||||
"displayName": "Match storico",
|
||||
"description": "Storico partite di campionato CSI."
|
||||
},
|
||||
"options": {
|
||||
"draftAndPublish": false
|
||||
},
|
||||
"pluginOptions": {},
|
||||
"attributes": {
|
||||
"data": {
|
||||
"type": "date",
|
||||
"required": true
|
||||
},
|
||||
"avversario": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"casa": {
|
||||
"type": "boolean",
|
||||
"required": true,
|
||||
"default": true
|
||||
},
|
||||
"set_nostri": {
|
||||
"type": "integer",
|
||||
"required": true
|
||||
},
|
||||
"set_loro": {
|
||||
"type": "integer",
|
||||
"required": true
|
||||
},
|
||||
"parziali": {
|
||||
"type": "json"
|
||||
},
|
||||
"mvp": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
const { createCoreController } = require('@strapi/strapi').factories;
|
||||
|
||||
module.exports = createCoreController('api::match-storico.match-storico');
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
const { createCoreRouter } = require('@strapi/strapi').factories;
|
||||
|
||||
module.exports = createCoreRouter('api::match-storico.match-storico');
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
const { createCoreService } = require('@strapi/strapi').factories;
|
||||
|
||||
module.exports = createCoreService('api::match-storico.match-storico');
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"kind": "collectionType",
|
||||
"collectionName": "righe_classifica",
|
||||
"info": {
|
||||
"singularName": "riga-classifica",
|
||||
"pluralName": "riga-classificas",
|
||||
"displayName": "Riga classifica",
|
||||
"description": "Classifica campionato CSI, una riga per squadra."
|
||||
},
|
||||
"options": {
|
||||
"draftAndPublish": false
|
||||
},
|
||||
"pluginOptions": {},
|
||||
"attributes": {
|
||||
"pos": {
|
||||
"type": "integer",
|
||||
"required": true
|
||||
},
|
||||
"squadra": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"giocate": {
|
||||
"type": "integer",
|
||||
"required": true,
|
||||
"default": 0
|
||||
},
|
||||
"vinte": {
|
||||
"type": "integer",
|
||||
"required": true,
|
||||
"default": 0
|
||||
},
|
||||
"perse": {
|
||||
"type": "integer",
|
||||
"required": true,
|
||||
"default": 0
|
||||
},
|
||||
"set_fatti": {
|
||||
"type": "integer",
|
||||
"required": true,
|
||||
"default": 0
|
||||
},
|
||||
"set_subiti": {
|
||||
"type": "integer",
|
||||
"required": true,
|
||||
"default": 0
|
||||
},
|
||||
"punti": {
|
||||
"type": "integer",
|
||||
"required": true,
|
||||
"default": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
const { createCoreController } = require('@strapi/strapi').factories;
|
||||
|
||||
module.exports = createCoreController('api::riga-classifica.riga-classifica');
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
const { createCoreRouter } = require('@strapi/strapi').factories;
|
||||
|
||||
module.exports = createCoreRouter('api::riga-classifica.riga-classifica');
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
const { createCoreService } = require('@strapi/strapi').factories;
|
||||
|
||||
module.exports = createCoreService('api::riga-classifica.riga-classifica');
|
||||
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"kind": "collectionType",
|
||||
"collectionName": "scout_match_finales",
|
||||
"info": {
|
||||
"singularName": "scout-match-finale",
|
||||
"pluralName": "scout-match-finales",
|
||||
"displayName": "Scout match finale",
|
||||
"description": "Risultato finale di una partita scoutata dal vivo (dato storico, di sola consultazione). L'azione-per-azione resta in scout_live/localStorage durante la partita."
|
||||
},
|
||||
"options": {
|
||||
"draftAndPublish": false
|
||||
},
|
||||
"pluginOptions": {},
|
||||
"attributes": {
|
||||
"match_id": {
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"unique": true
|
||||
},
|
||||
"data": {
|
||||
"type": "date",
|
||||
"required": true
|
||||
},
|
||||
"avversario": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"casa": {
|
||||
"type": "boolean",
|
||||
"required": true,
|
||||
"default": true
|
||||
},
|
||||
"set_nostri": {
|
||||
"type": "integer",
|
||||
"required": true
|
||||
},
|
||||
"set_loro": {
|
||||
"type": "integer",
|
||||
"required": true
|
||||
},
|
||||
"parziali": {
|
||||
"type": "json"
|
||||
},
|
||||
"mvp": {
|
||||
"type": "string"
|
||||
},
|
||||
"azioni": {
|
||||
"type": "json"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
const { createCoreController } = require('@strapi/strapi').factories;
|
||||
|
||||
module.exports = createCoreController('api::scout-match-finale.scout-match-finale');
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
const { createCoreRouter } = require('@strapi/strapi').factories;
|
||||
|
||||
module.exports = createCoreRouter('api::scout-match-finale.scout-match-finale');
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
const { createCoreService } = require('@strapi/strapi').factories;
|
||||
|
||||
module.exports = createCoreService('api::scout-match-finale.scout-match-finale');
|
||||
@@ -0,0 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
register(/*{ strapi }*/) {},
|
||||
bootstrap(/*{ strapi }*/) {},
|
||||
};
|
||||
@@ -4,14 +4,18 @@
|
||||
# (o come container: docker run -p 80:80 -p 443:443 -v ./Caddyfile:/etc/caddy/Caddyfile caddy)
|
||||
#
|
||||
# Un solo hostname: /api/* va al gateway Supabase (envoy accetta qualsiasi Host, instrada per
|
||||
# path), tutto il resto va all'app. handle_path toglie il prefisso /api prima di inoltrare, quindi
|
||||
# VITE_SUPABASE_URL nell'app deve essere https://<dominio>/api (supabase-js aggiunge da solo
|
||||
# /rest/v1, /auth/v1, ecc.).
|
||||
# path), /cms/* va al CMS Strapi (infra/strapi/), tutto il resto va all'app. handle_path toglie
|
||||
# il prefisso prima di inoltrare, quindi VITE_SUPABASE_URL nell'app deve essere
|
||||
# https://<dominio>/api (supabase-js aggiunge da solo /rest/v1, /auth/v1, ecc.) e VITE_STRAPI_URL
|
||||
# deve essere https://<dominio>/cms.
|
||||
|
||||
crapp.ddns.net {
|
||||
handle_path /api/* {
|
||||
reverse_proxy 127.0.0.1:8000
|
||||
}
|
||||
handle_path /cms/* {
|
||||
reverse_proxy 127.0.0.1:1337
|
||||
}
|
||||
handle {
|
||||
reverse_proxy 127.0.0.1:3000
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user