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:
2026-08-28 15:39:20 +02:00
co-authored by Claude Sonnet 5
parent 3fdbfefa62
commit 3f61b32219
43 changed files with 22425 additions and 9 deletions
+7
View File
@@ -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=
+30 -6
View File
@@ -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.
+8
View File
@@ -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
+23
View File
@@ -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
+131
View File
@@ -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
+15
View File
@@ -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"]
+61
View File
@@ -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>
+21
View File
@@ -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),
},
});
+12
View File
@@ -0,0 +1,12 @@
module.exports = {
rest: {
defaultLimit: 25,
maxLimit: 100,
withCount: true,
strictParams: true,
},
documents: {
strictParams: true,
strictRelations: true,
},
};
+72
View File
@@ -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),
},
};
};
+12
View File
@@ -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',
];
+41
View File
@@ -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,
},
},
},
});
+10
View File
@@ -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),
},
});
+38
View File
@@ -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

+9
View File
@@ -0,0 +1,9 @@
{
"compilerOptions": {
"module": "nodenext",
"moduleResolution": "nodenext",
"target": "ES2021",
"checkJs": true,
"allowJs": true
}
}
+21579
View File
File diff suppressed because it is too large Load Diff
+43
View File
@@ -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
}
}
+3
View File
@@ -0,0 +1,3 @@
# To prevent search engines from seeing the site altogether, uncomment the next two lines:
# User-Agent: *
# Disallow: /
+39
View File
@@ -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',
},
},
});
};
View File
@@ -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');
+6
View File
@@ -0,0 +1,6 @@
'use strict';
module.exports = {
register(/*{ strapi }*/) {},
bootstrap(/*{ strapi }*/) {},
};
+7 -3
View File
@@ -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
}