Aplicação ASP.NET Core MVC (.NET 10) para registar o planeamento de circulações no TIC, segundo o modelo da folha
template_planeamento_simplificado_vazio.xlsx, e guardar feeds GTFS com registo de atividade por login.
- .NET 10, ASP.NET Core MVC, ASP.NET Core Identity (perfis
AdmineUtilizador) - PostgreSQL 18 via EF Core + Npgsql (tabelas e colunas em snake_case)
- Bootstrap 5.3 + Bootstrap Icons (layout), Syncfusion EJ2 (grelhas, dropdowns, datas, horas, checkboxes), FullCalendar 6 (calendários)
| Folha | Entidade | Notas |
|---|---|---|
| info_operador | Operador |
NIF único por login, alvará e validade, âmbito (nacional/internacional/nac-int) |
| paragens | Paragem |
código único por login, latitude/longitude (aceita . ou ,) |
| circulações | Circulacao |
operador, linha, autorização, declaração de capacidade, ID viagem (único por login), origem/destino, chegada/partida no TIC, tempo de embarque |
| calendário | CirculacaoDia |
um registo por dia em que a circulação se realiza (ausência = não) |
| percursos | PercursoParagem |
sequência ordenada de paragens por circulação |
Além disso: GtfsFeed (ficheiro .zip, SHA-256, estado de validação, contagens, datas do feed_info) e RegistoAtividade
(log de sessões, GTFS, alterações de dados e administração).
- Admin: vê e edita tudo (operadores, paragens, circulações, feeds GTFS, registos e utilizadores).
- Utilizador: está associado a um operador (obrigatório, definido pelo Admin em Utilizadores) e só vê a informação desse operador: circulações (e calendário, percurso, horas no TIC), paragens usadas nessas circulações e feeds GTFS do operador. Não vê os menus Operadores e Registos e não edita: nas circulações faz pedidos de alteração (menu Pedidos), que o Admin aceita ou rejeita (a alteração em si é feita pelo Admin na circulação).
Os filtros globais estão no ApplicationDbContext; o operador do utilizador vai numa claim da sessão
(AppClaimsPrincipalFactory). Mudar o operador ou o perfil de um utilizador termina as sessões abertas dele.
O SaveChanges continua a impedir alterar registos de outro login a quem não é Admin. Não há registo público.
docker compose up -d # PostgreSQL 18 em localhost:5432 (postgres/postgres)
cd src/AppTIC.Web
dotnet run # aplica as migrações e cria o AdminLogins de teste (criados no arranque em Development, definidos em Seed no appsettings.Development.json):
| Login | Palavra-passe | Perfil |
|---|---|---|
admin@apptic.local |
Admin12345 |
Admin (vê todos os dados) |
rne@apptic.local |
Rne12345 |
Utilizador – Rede Nacional de Expressos |
flixbus@apptic.local |
Flixbus123 |
Utilizador – FlixBus |
Só são criados se ainda não existirem. Para produção, defina apenas Seed:AdminEmail/Seed:AdminPassword e crie os restantes utilizadores em Utilizadores.
Configuração (appsettings.json ou variáveis de ambiente, ex. ConnectionStrings__DefaultConnection):
ConnectionStrings:DefaultConnection– ligação PostgreSQLSeed:AdminEmail,Seed:AdminPassword– primeiro Admin (só é criado se não existir)Syncfusion:LicenseKey– chave de licença Syncfusion (sem ela aparece o aviso de versão de avaliação);Syncfusion:Versiondeve coincidir com o pacote NuGetGtfs:StoragePath– pasta dos .zip (por omissãoApp_Data/gtfs, um subdiretório por login);Gtfs:MaxUploadBytesDatabase:MigrateOnStartup– aplica migrações no arranque (true por omissão)
Script SQL completo da base de dados: database/apptic_schema.sql (ver database/README.md).
Migrações: dotnet tool restore && dotnet ef migrations add <Nome> -p src/AppTIC.Web -o Data/Migrations.
A aplicação corre no IIS com o ASP.NET Core Module (in-process). A base de dados é a tic_plan do PostgreSQL/PostGIS
no mesmo servidor (ConnectionStrings:DefaultConnection em appsettings.json); as migrações aplicam-se no arranque.
Uma vez, no servidor
- Instalar o ASP.NET Core 10 Hosting Bundle (inclui o runtime e o módulo do IIS) e reiniciar o IIS (
iisreset). - Criar as pastas
C:\AppTIC\site(aplicação),C:\AppTIC\dados\gtfs(feeds GTFS) eC:\AppTIC\dados\keys(chaves das sessões). Os caminhos estão emappsettings.Production.json. - No Gestor do IIS, criar o application pool AppTIC com .NET CLR version = No Managed Code.
- Criar o site ticplanner.mobtporto.pt com caminho físico
C:\AppTIC\site, o pool AppTIC e os bindingshttps· porta 443 · nome de anfitriãoticplanner.mobtporto.pt· Require Server Name Indication · certificado deticplanner.mobtporto.pt(ou*.mobtporto.pt), ehttp· porta 80 ·ticplanner.mobtporto.pt(a aplicação redireciona para https e envia HSTS). Endereço em produção:https://ticplanner.mobtporto.pt/. O registo DNSticplanner.mobtporto.ptaponta para10.0.30.97. Também funciona como aplicação dentro de um site existente (p.ex./TICPlannerno Default Web Site): os links e redirecionamentos usam sempre a raiz da aplicação (~/,Url.Action), nunca/. Se o log indicar "Failed to determine the https port for redirect", acrescentarASPNETCORE_HTTPS_PORT=443às variáveis de ambiente doweb.config. - Dar permissão de Modificar em
C:\AppTIC\dadosà contaIIS AppPool\AppTIC:icacls C:\AppTIC\dados /grant "IIS AppPool\AppTIC:(OI)(CI)M" - Abrir as portas 443 e 80 na firewall do Windows, se for acedida a partir de outras máquinas.
- Para criar o primeiro administrador numa base vazia, definir
Seed:AdminEmaileSeed:AdminPassword(p.ex. como variáveis de ambienteSeed__AdminEmail/Seed__AdminPasswordnoweb.configpublicado) e retirá-los depois.
Em cada versão
dotnet publish src/AppTIC.Web -p:PublishProfile=IISCopiar o conteúdo de src/AppTIC.Web/bin/Release/net10.0/publish-iis/ para C:\AppTIC\site. Antes de copiar, parar o
site ou pôr na pasta um app_offline.htm (o IIS liberta os ficheiros e mostra essa página); retirá-lo no fim.
O web.config define ASPNETCORE_ENVIRONMENT=Production e aumenta o limite de upload do IIS (30 MB por omissão) para os
200 MB de Gtfs:MaxUploadBytes. Para ver erros de arranque, pôr stdoutLogEnabled="true" no web.config do servidor
(cria C:\AppTIC\site\logs). Os browsers precisam de acesso à internet para o Syncfusion e o OpenLayers (CDN).
Carregar um .zip guarda o ficheiro, calcula o SHA-256 (avisa se for duplicado) e valida: ficheiros obrigatórios
(agency, stops, routes, trips, stop_times, calendar e/ou calendar_dates), cabeçalhos, contagens e datas/versão do
feed_info.txt. Cada passo (carregamento, validação, descarga, eliminação) fica no registo do feed e no registo do login.
Cada feed é associado a um operador. Depois da validação é gerado um GTFS filtrado TIC, com a mesma lógica do
GTFS_Agg: viagens com pelo menos um stop_time numa paragem do TIC → os seus stop_times, trips, routes, stops
(e estações-mãe), calendar/calendar_dates, shapes, frequencies e transfers referenciados. As paragens do TIC são
os stop_id definidos na ficha do operador (campo "Paragens do TIC no GTFS"); se estiver vazio, usa
Gtfs:ParagensTicPorOmissao do appsettings.json (RNE 100, FlixBus cd022a5c-…, CP 94_2006, STCP TIC1-3/CMP1,2,5,6,
Metro 5703). Os stop_id são os originais de cada feed, sem o sufixo de origem (_S2JE, _5G5E, …) que o GTFS_Agg acrescenta.